Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

2633

.pdf
Скачиваний:
6
Добавлен:
07.01.2021
Размер:
54.26 Mб
Скачать

изображения, загружается растровое изображение. OpenGL генерирует 1 текстуру, и сохраняет эту текстуру в texture[0].

Далее, в данном примере, будем использовать текстуру мипналожения, имя текстуры – lights.bmp:

AUX_RGBImageRec *LoadBMP(char *Filename) // Загрузка

картинки

 

{

 

FILE *File=NULL;

// Индекс файла

if (!Filename)

// Проверка имени файла

{

 

return NULL;

// Если нет, возврат NULL

}

File=fopen(Filename,"r"); // Проверка существования файла

if (File)

// Файл существует?

{

 

 

fclose(File);

// Закрыть файл

 

return auxDIBImageLoad(Filename); // Загрузка картинки и возврат

указателя на нее указателя

 

 

}

 

 

return NULL;

// Если загрузка не удалась, возврат NULL

}

 

 

int LoadGLTextures()

// Загрузка картинки и конвертирование в

текстуру

 

 

{

 

 

int Status=FALSE;

// Индикатор состояния

AUX_RGBImageRec *TextureImage[1];

// Создать место для

текстуры

 

 

memset(TextureImage,0,sizeof(void *)*1);

// Установить

указатель в NULL

 

 

// Загрузка картинки, проверка на ошибки, если картинка не

найдена - выход

 

 

if (TextureImage[0]=LoadBMP("Data/Lights.bmp"))

{

 

 

Status=TRUE;

// Установка Status в TRUE

glGenTextures(1, &texture[0]); // Создание трех текстур

//Создание текстуры с мип-наложением glBindTexture(GL_TEXTURE_2D, texture[0]);

gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY,

GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);

133

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);

}

В следующих строках кода автоматически генерируются текстурные координаты для любого объекта, которые выводятся на экран Команда glTexGen включает достаточно сложную математику. GL_S и GL_T – координаты текстуры. По умолчанию они заданы так, чтобы брать текущее x положение на экране и текущее y положение на экране и из них вычислить вершину текстуру:

// Текстуризация контура закрепленного за объектом glTexGeni(GL_S, GL_TEXTURE_GEN_MODE,

GL_OBJECT_LINEAR);

// Текстуризация контура закрепленного за объектом glTexGeni(GL_T, GL_TEXTURE_GEN_MODE,

GL_OBJECT_LINEAR);

 

 

 

glEnable(GL_TEXTURE_GEN_S);

// Автоматическая

генерация

 

 

 

glEnable(GL_TEXTURE_GEN_T);

// Автоматическая

генерация

 

 

 

}

 

 

 

if (TextureImage[0])

 

// Если текстура существует

{

 

 

 

if (TextureImage[0]->data)

 

// Если изображение текстуры

существует

 

 

 

{

 

 

 

free(TextureImage[0]->data);

// Освобождение памяти

изображения текстуры

 

 

 

}

 

 

 

free(TextureImage[0]);

 

// Освобождение памяти под

структуру

 

 

 

}

 

 

 

return Status;

// Возвращаем статус

}

 

 

 

Стоит отметить, что объекты не текстурированны по z плоскости. Только появляются полосы. Передние и задние грани текстурированны, однако, именно это и необходимо.

X(GL_S) охватывает наложение текстуры слева направо, а Y(GL_T) охватывает наложение текстуры сверху и вниз.

134

GL_TEXTURE_GEN_MODE позволяет выбирать режим наложения текстуры, которую необходимо использовать по координатам текстуры S и T. Есть три возможности:

GL_EYE_LINEAR – текстура зафиксирована на экране. Она никогда не перемещается. Объект накладывается на любую часть текстуры, которую он захватывает.

GL_OBJECT_LINEAR – в данной программе используется этот режим. Текстура привязана к объекту, перемещающемуся по экрану.

GL_SPHERE_MAP – создает металлический отражающий тип объекта.

Также необходимо задать GL_OBJECT_PLANE, но значение по умолчанию то, которое желаемо.

Есть несколько новых строк кода в конце InitGL(). Вызов BuildFont() был помещен ниже кода, загружающего текстуру. Строка с glEnable(GL_COLOR_MATERIAL) была удалена. Если необходимо задать текстуре цвет, можно использовать glColor3f(r, г, b) и добавить строку glEnable(GL_COLOR_MATERIAL) в конце этой части кода:

int InitGL(GLvoid)

// Все начальные настройки OpenGL здесь

{

 

 

 

if (!LoadGLTextures())// Переход на процедуру загрузки текстуры

{

 

 

 

return FALSE;

// Если текстура не загружена возвращаем

FALSE

 

 

 

}

 

 

 

BuildFont();

// Построить шрифт

glShadeModel(GL_SMOOTH);

// Разрешить плавное

затенение

 

 

 

glClearColor(0.0f, 0.0f, 0.0f, 0.5f);// Черный фон

glClearDepth(1.0f);

// Установка буфера глубины

glEnable(GL_DEPTH_TEST);

// Разрешение теста глубины

glDepthFunc(GL_LEQUAL)

 

// Тип теста глубины

glEnable(GL_LIGHT0);

// Быстрое простое освещение

(Устанавливает в качестве источника освещения Light0)

glEnable(GL_LIGHTING);

// Включает освещение

// Действительно хорошие вычисления перспективы glHint(GL_PERSPECTIVE_CORRECTION_HINT,

GL_NICEST);

Далее дадим разрешение наложения 2D текстуры, и выбор текстуры номер один. При этом будет отображена текстура номер один на любой 3D-объект, который выводится на экран. Здесь возможно разрешать и запрещать наложение текстуры самостоятельно:

135

glEnable(GL_TEXTURE_2D); // Разрешение наложения текстуры

glBindTexture(GL_TEXTURE_2D, texture[0]);// Выбор текстуры return TRUE; // Инициализация окончена успешно

}

Код изменения размера не изменился, но код DrawGLScene изменился:

int DrawGLScene(GLvoid) // Здесь происходит рисование

{

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //

Очистка экран и буфера глубины glLoadIdentity();

// Сброс просмотра В этой части кода происходит первое изменение. Вместо того,

чтобы поместить объект в середину экрана, будем вращать его, используя COS и SIN. По оси X будет происходить раскачивание от -1.1 слева до +1.1 вправо. Здесь будет использоваться переменная rot для управления раскачиванием слева направо. Раскачивание будет происходить от +0.8 верх до -0.8 вниз. Для раскачивания будет использоваться переменная rot:

// Позиция текста glTranslatef(1.1f*float(cos(rot/16.0f)),0.8f*float(sin(rot/20.0f)),-3.0f);

Далее идет описание вращения. Символ будет вращаться по осям

X, Y и Z:

 

glRotatef(rot,1.0f,0.0f,0.0f);

// Вращение по оси X

glRotatef(rot*1.2f,0.0f,1.0f,0.0f);

// Вращение по оси Y

glRotatef(rot*1.4f,0.0f,0.0f,1.0f);

// Вращение по оси Z

Следует смещать символ по каждой оси немного налево, вниз, и вперед, чтобы центрировать его, иначе, когда он вращается, он будет вращаться не вокруг собственного центра.

(-0.35f, -0.35f, 0.1f) – наиболее подходящие числа, но они могут изменяться в зависимости от шрифта:

glTranslatef(-0.35f,-0.35f,0.1f); // Центр по осям X, Y, Z

Наконец, далее осуществляется вывод эмблемы, затем увеличение переменной rot, поэтому, символ вращается и перемещается по экрану:

glPrint("N");

// Нарисуем символ эмблемы

rot+=0.1f;

// Увеличим переменную вращения

return TRUE;

// Заканчиваем процедуру

}

 

Далее надо добавить KillFont() в конце KillGLWindow(), что позволит почистит память прежде, чем произойдет выход из программы:

136

if (!UnregisterClass("OpenGL",hInstance)) // Если класс не зарегистрирован

{

MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK|MB_ICONINFORMATION);

hInstance=NULL;

// Установить копию приложения в ноль

}

 

KillFont();

// Уничтожить шрифт

}

 

Результат работы программы представлен на рис. 23.

Измените код программы, используя другие шрифты. Также попробуйте заменить используемые эмблемы и их цвета (рис 24).

Рис. 23. Использование текстурированного векторного шрифта

Рис. 24. Использование измененного текстурированного векторного шрифта

137

Контрольные вопросы

1.С какой целью в OpenGL используется шрифт «wingdings»?

2.Что произойдет, если на очень изогнутых поверхностях задать отклонение шрифта равное 0.0f?

3.Как по умолчанию в OpenGL заданы координаты текстуры

(GL_S и GL_T)?

4.Что будет происходить при отсутствии центрирования символа при его вращении?

2.16 Создание эффекта тумана

Код основан на программном коде проекта, в котором реализовано наложение текстуры на куб, т.е. следует использовать результат работы программы – куб, с наложенной текстурой.

Сначала подготовим данные:

Bool gp;

// G Нажата? (Новая строка)

GLuint filter;

// Используемый фильтр для текстур

GLuint fogMode[]= { GL_EXP, GL_EXP2, GL_LINEAR }; // Хранит три типа тумана

GLuint fogfilter= 0; // Тип используемого тумана

GLfloat fogColor[4]= {0.5f, 0.5f, 0.5f, 1.0f}; // Цвет тумана Подготовка всех необходимых переменных, содержащих

параметры затуманивания.

Массив fogMode будет хранить три значения: GL_EXP, GL_EXP2 и GL_LINEAR, – это три типа тумана. Объявляются переменные в начале кода, после строки GLuint texture[3]. В переменной fogfilter будет храниться тип тумана который будет использоваться. fogColor будет содержать цвет, который придается туману. Двоичная переменная gp в начало кода, чтобы можно было узнать нажата ли клавиша 'g' во время выполнения программы-примера.

Далее внесем изменения в DrawGLScene, а именно: функция InitGL, строка glClearColor() изменена, чтобы заполнить экран цветом

тумана для достижения лучшего эффекта:

 

glClearColor(0.5f,0.5f,0.5f,1.0f);

// Очистка экран, заполнение его

цветом тумана.

 

 

glEnable(GL_FOG);

// Включаем туман (GL_FOG)

glFogi(GL_FOG_MODE, fogMode[fogfilter]);

// Выбираем тип

тумана

 

 

glFogfv(GL_FOG_COLOR, fogColor); // Устанавливаем цвет тумана

138

glFogf(GL_FOG_DENSITY, 0.35f); // Выбираем плотность тумана

glHint(GL_FOG_HINT, GL_DONT_CARE); // Вспомогательная

установка тумана

 

glFogf(GL_FOG_START, 1.0f);

// Глубина, с которой начинается

туман

 

glFogf(GL_FOG_END, 5.0f);

// Глубина, где туман

заканчивается.

 

Возьмем сначала первые три строчки этого кода. Первая строка glEnable(GL_FOG) инициализирует туман:

GL_DONT_CARE;

// Позволяет OpenGL выбрать формулу

для расчета тумана (по вершинам или по пикселям).

GL_NICEST;

//Создает туман по пикселям.

GL_FASTEST;

// Вычисляет туман по вершинам.

Далее строка, glFogi(GL_FOG_MODE, fogMode[fogfilter])

устанавливает режим фильтрации тумана. Массив fogMode содержал переменные GL_EXP, GL_EXP2 и GL_LINEAR, которые имеют следующий смысл:

GL_EXP – обычный туман, заполняющий весь экран;

GL_EXP2 – затуманивает весь экран, зато придает больше глубины всей сцене;

GL_LINEAR – наиболее приемлемый режим прорисовки тумана, в котором бъекты выходят из тумана и исчезают в нем гораздо лучше.

Строка glFogfv(GL_FOG_COLOR, fogcolor) задает цвет тумана. Строка glFogf(GL_FOG_DENSITY, 0.35f) устанавливает,

насколько густым будет туман. hintval может быть: GL_DONT_CARE, GL_NICEST или GL_FASTEST

Следующая строка glFogf(GL_FOG_START, 1.0f) устанавливает, насколько близко к экрану начинается затуманивание. Следующая строка glFogf(GL_FOG_END, 5.0f) сообщает программе, насколько глубоко в экран должен уходить сам туман.

Далее рассмотрим события при нажатии клавиш:

Код, предназначенный для того чтобы переключаться между разными способами затуманивания, идет в конце программы, вместе с обработкой нажатия клавиш.

if (keys['G'] && !gp)

// Нажата ли клавиша "G"?

{

 

gp=TRUE;

// gp устанавливает в TRUE

fogfilter+=1;

// Увеличиние fogfilter на 1

if (fogfilter>2)

// fogfilter больше 2 ... ?

{

 

139

fogfilter=0; // Если так, установить fogfilter в ноль

}

glFogi (GL_FOG_MODE, fogMode[fogfilter]);// Режим тумана

}

 

if (!keys['G'])

// Клавиша "G" отпущена?

{

 

gp=FALSE;

// Если да, gp установить в FALSE

}

На рис. 24. представлен результат работы программы в случае, если использовать обычный туман, заполняющий весь экран – GL_EXP.

Рис. 24. Обычный туман, заполняющий весь экран – GL_EXP

Попробуйте изменить тип тумана:

GL_EXP2 – затуманивает весь экран и придает больше глубины всей сцене .

GL_LINEAR – лучший режим прорисовки тумана. Объекты как выходят из тумана и исчезают в нем гораздо лучше (рис. 25).

140

Рис. 25. Туман GL_LINEAR

Контрольные вопросы

1)Что означает строка GLuint fogMode[]={GL_EXP, GL_EXP2, GL_LINEAR}?

2)Каково назчение функции glFogi()?

3)Какие параметры имеет функция glFogfv() и за что отвечает каждый параметр?

4)Какая команда инициализирует туман?

5)Как изхменить тип тумана?

6)Чтотакое плотность тумана и как ее изменить?

2.17.Квадратирование для отображения сложных объектов

Используем квадратирование для отображения сложных объектов. Для этого большого проекта используем код, который был реализован при создании различных режимов фильтрации текстур, применение простого освещения с возможностью перемещения объектов с помощью клавиатуры:

#include <windows.h> //

Заголовочный файл для Windows

#include <stdio.h>

//

Заголовочный

файл

для

стандартной

библиотеки ввода/вывода

 

 

 

 

 

#include <gl\gl.h>

//

Заголовочный

файл

для

библиотеки

OpenGL32

 

 

 

 

 

#include <gl\glu.h>

// Заголовочный файл для библиотеки GLu32

#include <gl\glaux.h>

// Заголовочный файл для библиотеки GLaux

 

 

141

 

 

 

HDC hDC=NULL;

//

Приватный контекст устройства GDI

HGLRC hRC=NULL; //

Постоянный контекст рендеринга

HWND hWnd=NULL;//

Сохраняет дескриптор окна

 

HINSTANCE hInstance;

// Сохраняет экземпляр приложения

bool keys[256];

//

Массив для работы с клавиатурой

bool active=TRUE;

//

Флаг

активации окна,

по

умолчанию =

TRUE

 

 

 

 

 

bool fullscreen=TRUE;// Флаг полноэкранного вывода

bool light;

// Освещение Вкл/Выкл

 

 

bool lp;

// L нажата?

 

 

bool fp;

// F нажата?

 

 

bool sp;

// Пробел нажат? (Новая строка)

int part1;

// Начало диска (Новая строка)

int part2;

// Конец диска (Новая строка)

 

int p1=0;

// Приращение 1 (Новая строка)

int p2=1;

// Приращение 2 (Новая строка)

GLfloat xrot;

// X вращение

 

 

GLfloat yrot;

// Y вращение

 

 

GLfloat xspeed;

// X скорость вращения

 

 

GLfloat yspeed;

// Y скорость вращения

 

 

GLfloat z=-5.0f;

// Глубина экрана

 

 

GLUquadricObj *quadratic;

// Место для

хранения объекта

Quadratic (Новая строка)

 

 

 

 

 

GLfloat LightAmbient[]={0.5f, 0.5f, 0.5f, 1.0f};

//

Фоновое

значение света

 

 

 

 

 

GLfloat LightDiffuse[]={1.0f, 1.0f, 1.0f, 1.0f};

//

Значение

рассеянного света

 

 

 

 

 

GLfloat LightPosition[]={0.0f, 0.0f, 2.0f, 1.0f};

//

Позиция

источника

 

 

 

 

 

GLuint filter;

// Используемый фильтр

 

 

GLuint texture[3];

// Место для 3-х текстур

 

 

GLuint object=0;

// Объект рисования

 

 

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

// Объявление WndProc

 

 

 

 

Далее внесем изменения в InitGL().

 

 

Добавим три строки

кода

для инициализации

квадратичного

объекта. Они должны быть после инициализации освещения (light1), но до строки return true. Первая строка инициализирует квадратичный объект и создает указатель на то место в памяти, где он будет содержаться. Если он не может быть создан, то будет возвращен 0. Вторая строка кода создает плавные нормали на квадратичном объекте, поэтому освещение будет выглядеть хорошо. Другое возможное

142

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]