В завершение рассмотрим одну интересную и часто используемую возможность OpenGL – создание эффекта тумана. Легкое затуманивание сцены создает реалистичный эффект, а частенько может и скрыть некоторые артефакты, которые появляются, когда в сцене присутствуют отдаленные объекты.
Туман в OpenGL реализуется путем изменения цвета объектов в сцене в зависимости от их глубины, т.е. расстояния до точки наблюдения. Изменение цвета происходит либо для вершин примитивов, либо для каждого пикселя на этапе растеризации в зависимости от реализации OpenGL. Этим процессом можно частично управлять – см. раздел 6.4.
Для включения эффекта затуманивания необходимо вызвать команду glEnable(GL_FOG).
Метод вычисления интенсивности тумана в вершине можно определить с помощью команд
void glFog[if] (enum pname, T param) ;
void glFog[if]v (enum pname, T params) ;
Аргумент pname может принимать следующие значения:
GL_FOG_MODE аргумент param определяет формулу, по которой будет вычисляться интенсивность тумана в точке.
В этом случае param может принимать значения
GL_EXP Интенсивность вычисляется по формуле f=exp(-d*z)
GL_EXP2 Интенсивность вычисляется по формуле f=exp(-(d*z)2)
GL_LINEAR Интенсивность вычисляется по формуле f=e-z/e-s
где z – расстояние от вершины, в которой вычисляется интенсивность тумана, до точки наблюдения.
Коэффициенты d,e,s задаются с помощью следующих значений аргумента pname
GL_FOG_DENSITY param определяет коээфициент d
GL_FOG_START param определяет коэффициент s
GL_FOG_END param определяет коэффициент e
Цвет тумана задается с помощью аргумента pname, равного
GL_FOG_COLOR в этом случае params – указатель на массив из 4-х компонент цвета.
Приведем пример использования этого эффекта:
GLfloat FogColor[4]={0.5,0.5,0.5,1};
glEnable(GL_FOG);
glFogi(GL_FOG_MODE,GL_LINEAR);
glFogf(GL_FOG_START,20.0);
glFogf(GL_FOG_END,100.0);
glFogfv(GL_FOG_COLOR,FogColor);
-
Поясните разницу между локальными и бесконечно удаленными источниками света.
-
Для чего служит команда glColorMaterial?
Глава 5.Текстурирование
Под текстурой будем понимать некоторое изображение, которое надо определенным образом нанести на объект, например, для придания иллюзии рельефности поверхности.
Наложение текстуры на поверхность объектов сцены повышает ее реалистичность, однако при этом надо учитывать, что этот процесс требует вычислительных затрат, особенно если OpenGL не поддерживается аппаратно.
Для работы с текстурой следует выполнить следующую последовательность действий:
-
выбрать изображение и преобразовать его к нужному формату;
-
передать изображение в OpenGL;
-
определить, как текстура будет наноситься на объект и как она будет с ним взаимодействовать;
-
связать текстуру с объектом.
Для использования текстуры необходимо сначала загрузить в память нужное изображение и передать его OpenGL.
Считывание графических данных из файла и их преобразование можно проводить вручную. Можно также воспользоваться функцией, входящей в состав библиотеки GLAUX (для ее использования надо дополнительно подключить glaux.lib), которая сама проводит необходимые операции. Это функция
AUX_RGBImageRec* auxDIBImageLoad (const char *file)
где file – название файла с расширением *.bmp или *.dib. Функция возвращает указатель на область памяти, где хранятся преобразованные данные.
При создании образа текстуры в памяти следует учитывать следующие требования:
Во-первых, размеры текстуры, как по горизонтали, так и по вертикали должны представлять собой степени двойки. Это требование накладывается для компактного размещения текстуры в текстурной памяти и способствует ее эффективному использованию. Работать только с такими текстурами конечно неудобно, поэтому после загрузки их надо преобразовать. Изменение размеров текстуры можно провести с помощью команды
void gluScaleImage (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 задается тип элементов массивов, расположенных по адресам datain и dataout. Как и обычно, это может быть тип GL_UNSIGNED_BYTE, GL_SHORT, GL_INT и так далее. Результат своей работы функция заносит в область памяти, на которую указывает параметр dataout.
Во-вторых, надо предусмотреть случай, когда объект после растеризации оказывается по размерам значительно меньше наносимой на него текстуры. Чем меньше объект, тем меньше должна быть наносимая на него текстура и поэтому вводится понятие уровней детализации текстуры. (mipmap) Каждый уровень детализации задает некоторое изображение, которое является, как правило, уменьшенной в два раза копией оригинала. Такой подход позволяет улучшить качество нанесения текстуры на объект. Например, для изображения размером 2mx2n можно построить max(m,n)+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 все компоненты.
Параметры width, height, data определяют размеры и расположение текстуры соответственно, а format и type имеют аналогичный смысл, что и в команде gluScaleImage().
После выполнения этой команды текстура копируется во внутреннюю память OpenGL, и поэтому память, занимаемую исходным изображением, можно освободить.
В OpenGL допускается использование одномерных текстур, то есть размера 1xN, однако, это всегда надо указывать, задавая в качестве значения target константу GL_TEXTURE_1D. Полезность одномерных текстур сомнительна, поэтому не будем останавливаться на этом подробно.
При использовании в сцене нескольких текстур, в OpenGL применяется подход, напоминающий создание списков изображений (так называемые текстурные объекты). Сначала с помощью команды
void glGenTextures (GLsizei n, GLuint* textures)
надо создать n идентификаторов текстур, которые будут записаны в массив textures. Перед началом определения свойств очередной текстуры следует сделать ее текущей («привязать» текстуру), вызвав команду
void glBindTexture (GLenum target, GLuint texture)
где target может принимать значения GL_TEXTURE_1D или GL_TEXTURE_2D, а параметр texture должен быть равен идентификатору той текстуры, к которой будут относиться последующие команды. Для того, чтобы в процессе рисования сделать текущей текстуру с некоторым идентификатором, достаточно опять вызвать команду glBindTexture() c соответствующим значением target и texture. Таким образом, команда glBindTexture() включает режим создания текстуры с идентификатором texture, если такая текстура еще не создана, либо режим ее использования, то есть делает эту текстуру текущей.
Так как не всякая аппаратура может оперировать текстурами большого размера, целесообразно ограничить размеры текстуры до 256x256 или 512x512 пикселей. Отметим, что использование небольших текстур повышает эффективность программы.
Достарыңызбен бөлісу: |