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

2633

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

{

 

 

int Status=FALSE;

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

AUX_RGBImageRec *TextureImage[1];

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

хранения текстуры

 

 

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

// устанавление ссылки

на NULL // Загрузка изображения, Проверка на ошибки, Если файл не найден то выход

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

{

Status=TRUE; // Установление статуса в TRUE glGenTextures(1, &texture[0]);

//Генерирование одного идентификатора текстуры

//Создание текстуру с линейной фильтрацией (Linear Filtered) glBindTexture(GL_TEXTURE_2D, texture[0]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,

GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,

GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]- >sizeX,

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

}

if (TextureImage[0]) // Если текстура существует

{

 

if (TextureImage[0]->data)

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

{

 

// Освобождение места, выделенного под изображение

free(TextureImage[0]->data);

}

 

free(TextureImage[0]);

// Освобождение структуры

изображения

 

}

 

return Status;

// Возврат статуса

}

 

Status хранит информацию об успехе операции:

Далее необходимо настроить OpenGL для обрисовки того, что будет нужно. Z-буфер (тест глубины) использоваться не будет, поэтому необходимо удалить строчки из кода первой программы:

glDepthFunc(GL_LEQUAL); и glEnable(GL_DEPTH_TEST);

93

В коде используется текстурирование, значит необходимо добавить все необходимые строки, которых не было, т.е. текстурирование и смешивание:

int InitGL(GLvoid)

// Всё установки OpenGL будут здесь

{

if (!LoadGLTextures())

//Загрузка текстуру

{

return FALSE;

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

}

glEnable(GL_TEXTURE_2D);

//Включение текстурирования

//Включение плавной раскраски (интерполирование по вершинам) glShadeModel(GL_SMOOTH);

glClearColor(0.0f, 0.0f, 0.0f, 0.5f);

//Фоном будет черный цвет

glClearDepth(1.0f);

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

//Максимальное качество перспективной коррекции

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

//Устанавка функции смешивания glBlendFunc(GL_SRC_ALPHA,GL_ONE); glEnable(GL_BLEND);

//Включение смешивания

Следующий фрагмент кода так же новый. Он устанавливает начальные углы, расстояние и цвет для каждой звезды. Чтобы изменить угол star[1] необходимо написать – star[1].angle={некоторое значение:

}.

for (loop=0; loop<num; loop++)

//Создание цикла и «проход» по всем звездам

{

star[loop].angle=0.0f;

//Установление всех углов в 0

Дистанцию рассчитывать следует, взяв текущий номер звезды (это значение loop) и разделив на максимальное значение звезд. Потом умножив результат на 5.0f, получим сдвиг каждой звезды немного дальше, чем предыдущей. Когда loop равен 50 (последняя звезда), loop разделенный на num будет равен 1.0f. Если установить zoom подальше в экран, можно использовать большее число, чем 5.0f, но звезды должны быть немного меньше (из-за перспективы).

94

Следует отметить, что цвета для каждой звезды задаются случайным образом от 0 до 255:

//Вычисление растояние до центра star[loop].dist=(float(loop)/num)*5.0f;

//Присваивание star[loop] случайного значения (красный) star[loop].r=rand()%256;

//Присваивание star[loop] случайного значения (зеленый) star[loop].g=rand()%256;

//Присваивание star[loop] случайного значения (голубой) star[loop].b=rand()%256;

}

return TRUE;

//Инициализация прошла нормально

}

Код функции Resize тот же самый, так что необходимо рассмотреть код обрисовки сцены.

int DrawGLScene(GLvoid)

//Здесь происходит рисование

{

//Очистка буфера цвета и глубины

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Выбор текстуры

glBindTexture(GL_TEXTURE_2D, texture[0]); for (loop=0; loop<num; loop++)

//Цикл по всем звездам

{

//Обнуление видовой матрицы (Model Matrix) перед каждой звездой

glLoadIdentity();

//Перенос по оси z на 'zoom'

glTranslatef(0.0f,0.0f,zoom);

// Вращение вокруг оси x на угол 'tilt' glRotatef(tilt,1.0f,0.0f,0.0f);

Теперь необходимо осуществить движение звезд. Звезда появляется в середине экрана. сначала необходимо задание вращение сцены вокруг оси y. Если угол 90 градусов, то ось x будет лежать не слева направо, а наоборот и выходить за пределы экрана. Вращая сцену, стоит изменить направления осей x и z.

Во второй строчке описан сдвиг позиции по оси x:

//Поворот на угол звезды вокруг оси glRotatef(star[loop].angle,0.0f,1.0f,0.0f);

//Движение вперед по оси x

95

glTranslatef(star[loop].dist,0.0f,0.0f);

Звезда – плоская текстура. Необходимо, чтобы звезды были направлены на наблюдателя всё время, вне зависимости от их вращения и движения по экрану. Этого можно добиться путем отмены вращения, которое было сделано, перед тем как была нарисована звезда. Следует отменить вращение в обратном порядке. Выше был описан поворот экрана, когда было описано вращение на угол звезды. В обратном порядке, необходимо повернуть обратно звезду на текущий угол. Чтобы сделать это, следует использовать обратное значение угла, и повернуть звезду на этот угол. И так как звезда была повернута на 10 градусов, то, поворачивая обратно на -10 градусов получаем звезду, повернутую к наблюдателю по y. Первая строчка ниже отменяет вращение по оси y. Потом аналогично нужно отменить вращение по оси x. Чтобы сделать это следует вращать звезду на угол -tilt. После всех этих операций звезда полностью повернута к наблюдателю:

glRotatef(-star[loop].angle,0.0f,1.0f,0.0f);

// Отмена текущего

поворота звезды

 

 

glRotatef(-tilt,1.0f,0.0f,0.0f);

// Отмена поворота экрана

Для того чтобы получить

различные

цвета, необходимо взять

максимальное количество звезд (num) и вычесть текущий номер (loop), потом вычесть единицу, так как цикл начинается с 0 и идет до num-1. Если результат будет 10, то используется цвет 10ой звезды. Вследствие того, что цвет двух звезд обычно различный. Не совсем хороший способ, но зато эффективный. Последнее значение это альфа (alpha). Чем меньше значение, тем прозрачнее звезда.

Если twinkle включен, то каждая звезда будет нарисована дважды. Программа будет работать медленнее в зависимости от типа вашего компьютера. Если twinkle включен, цвета двух звезд будут смешиваться вместе для создания реально красивых цветов. Так как это звезды не вращаются, то это проявлялось бы как будто звёзды анимировались, когда twinkling включен.

Следует отметить, как просто добавить цвет в текстуру. Даже если текстура черно-белая, она будет окрашена в цвет, который был выбран, перед тем как нарисовать текстуру:

if (twinkle)

// Если Twinkling включен

{

 

// Данный цвет использует байты glColor4ub(star[(num-loop)-1].r,star[(num-loop)-1].g, star[(num-loop)-1].b,255);

glBegin(GL_QUADS);

// Начало рисования текстурирования

квадрата

 

glTexCoord2f(0.0f,0.0f);

 

96

glVertex3f(-1.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f(1.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f); glEnd(); // Конец рисования

}

Далее описывается рисование основной звезды. Разница между кодом выше только в том, что звезда всегда рисуется, и вращается по оси z:

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

// Поворот звезды по оси z

//Цвет использует байты glColor4ub(star[loop].r,star[loop].g,star[loop].b,255); glBegin(GL_QUADS);

//Начало рисования текстурного квадрата glTexCoord2f(0.0f, 0.0f);

glVertex3f(-1.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f);

glEnd();

// Конец рисования

Далее прописываются все движения звезды:

spin+=0.01f;

// Вращение звезды

star[loop].angle+=float(loop)/num;

// Измена угла звезды

star[loop].dist-=0.01f;

 

// Измена расстояния до центра

Звезду вращать необходимо увеличением значения spin. А затем изменить угол каждой звезды. Угол каждой звезды увеличивается на loop/num, что ускоряет вращение звезды с отдалением от центра. Чем ближе к центру, тем медленнее вращается звезда. Наконец описывается уменьшение расстояния до центра для каждой звезды. Это создаёт эффект засасывания звезд в центр экрана.

Нижеследующие строки проверяют видимость звезд: if (star[loop].dist<0.0f)

// Звезда в центре экрана?

{

star[loop].dist+=5.0f;

97

// Перемещение на 5 единиц от центра

//Новое значение красной компоненты цвета star[loop].r=rand()%256;

//Новое значение зеленной компоненты цвета star[loop].g=rand()%256;

//Новое значение синей компоненты цвета star[loop].b=rand()%256;

}

}

return TRUE

}

Попала звезда в центр экрана или нет. Если попала, то звезде задается новый цвет и она двигается на пять единиц от центра, так она может снова начать своё движение к центру как новая звезда.

Теперь необходимо добавить код для проверки нажатия клавиш. Обратимся в WinMain(). Код для новой клавиши добавляем прямо под строкой SwapBuffers(hDC).

Строкой ниже идет проверка нажатия клавиши 'T': SwapBuffers(hDC);

// Смена буфера (Double Buffering)

if (keys['T'] && !tp)

// Если 'T' нажата и tp равно FALSE

{

 

 

tp=TRUE;

// То присвоение tp = TRUE

twinkle=!twinkle;

// Измена значения twinkle на обратное

}

 

 

Если нажата,

и не

была до этого нажата, то этот пункт

пропускается. Если twinkle равно FALSE, то она станет TRUE. Если была TRUE, то станет FALSE. Одно нажатие 'T' установит tp равное TRUE. Это предотвращает постоянное выполнение этого кода, если клавиша 'T' удерживается.

Код ниже проверяет выключение (повторное нажатие) клавиши

'T':

 

if (!keys['T'])

// Клавиша 'T' была отключена

{

 

tp=FALSE;

// Присваивание tp значения, равного FALSE

}

Если да, то присваивается tp=FALSE. Нажатие 'T' не делает ничего кроме установки tp равной FALSE, так что эта часть кода очень важная.

Следующий код проверяет, нажаты ли клавиши 'стрелка вверх', 'стрелка вниз', 'page up', 'page down':

if (keys[VK_UP]) // Стрелка вверх была нажата?

98

{

 

tilt-=0.5f;

// Вращение экран вверх

if (keys[VK_DOWN])

// Стрелка вниз нажата?

{

 

tilt+=0.5f;

// Вращение экран вниз

}

 

if (keys[VK_PRIOR])

// Page Up нажат?

{

 

zoom-=0.2f;

// Уменьшение

}

 

if (keys[VK_NEXT])

// Page Down нажата?

{

 

zoom+=0.2f;

// Увеличение

}

Как и других предыдущих проектах, необходимо убедиться, что

название окна корректно:

 

if (keys[VK_F1])

// Если F1 нажата?

{

 

keys[VK_F1]=FALSE;

 

KillGLWindow();

// Закрытие текущего окна

fullscreen=!fullscreen;

// Переключение режимов

Fullscreen (полноэкранный) / Windowed (обычный)

// Пересоздание OpenGL окно

if (!CreateGLWindow("Textures, Lighting & Keyboard

Tutorial",640,480,16,fullscreen))

{

 

return 0;

//Выход если не получилось

}

 

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

99

Рис. 14. Вращающаяся спираль из звезд

Попробуйте изменить код программы так, чтобы получить вместо звезд другие объекты, а также изменить вращение данной спирали (рис. 16).

Рис. 15. Вращающаяся спираль из смешанной текстуры

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

1.Какие значения могут принимать логические переменные twinkle и tp?

2.Каково назначение логической переменной Twinkle?

100

3.Каким образом было достигнуто эффект того, что, звезды направлены на наблюдателя всё время, вне зависимости от их вращения

идвижения по экрану.

4.Как получить сдвиг каждой звезды немного дальше, чем предыдущей?

5.Как храненится расстояние от наблюдателя до звезд (zoom),

икакой будет начальный угол(tilt) вращения звезд?

6.Что произойдет при увеличении параметра spin?

7.Как изменить форму звезд?

8.Как и для какой цели звезда помещается в цент экрана?

2.11. Эффект развевающегося флага

Данная программа реализует эффект развевающегося флага и основана на коде шестого примера.

Для начала необходимо добавить приведенный ниже код #include сразу за другими из кода шестого примера:

#include <math.h> // Для функции Sin()

Данный #include позволяет использовать различные библиотечные математические функции, как, например, синус и косинус.

Для хранения отдельных x, y и z – координат сетки необходимо использовать массив точек (points). Размер сетки 45x45, и она в свою очередь образует 44x44 квадрата. wiggle_count будет использоваться для определения того, насколько быстро «развивается» текстура. Каждые три кадра выглядят достаточно хорошо, и переменная hold будет содержать число с плавающей запятой для сглаживания волн. Эти строки можно добавить в начале программы под последней строчкой с

#include и перед строкой GLuint texture[1]:

float points[ 45 ][ 45 ][3];

// Массив точек сетки "волны"

int wiggle_count = 0;

// Счетчик для контроля

быстроты развевания флага

 

GLfloat hold;

// Временно содержит число с

плавающей запятой

 

В функции LoadGLTextures() необходимо заменить текстуру

LoadBMP("Data/….bmp") на LoadBMP("Data/Tim.bmp"). Таким образом,

в программе будет использоваться текстура с именем Tim.bmp: if (TextureImage[0]=LoadBMP("Data/Tim.bmp"))

// Загружаем изображение Далее необходимо добавить приведенный ниже код в конец

функции InitGL() перед return TRUE:

101

glPolygonMode( GL_BACK, GL_FILL );

// Нижняя (задняя)

сторона заполнена

 

glPolygonMode( GL_FRONT, GL_LINE );

// Верхняя (передняя)

сторона прорисована линиями

 

Этот код отвечает за то, чтобы полигоны нижней (задней) стороны были зарисованы полностью и чтобы полигоны верхней (передней) стороны были лишь очерчены.

// по оси X

for(int x=0; x<45; x++)

{

// по оси Y

for(int y=0; y<45; y++)

{

// применение волны к сетке points[x][y][0]=float((x/5.0f)-4.5f); points[x][y][1]=float((y/5.0f)-4.5f); points[x][y][2]=float(sin((((x/5.0f)*40.0f)/360.0f

)*3.141592654*2.0f));

}

}

Два цикла вверху инициализируют точки на сетке. В программе используются целочисленные циклы, чтобы предупредить неполадки, которые появляются при вычислениях с плавающей запятой. Здесь переменные x и y делятся на 5 (т.е. 45 / 9 = 5) и затем отнимается 4,5 от каждой из них, чтобы отцентрировать "волну". Того же эффекта можно достигнуть переносом (translate).

Окончательное значение points[x][y][2] – это значение синуса. Функция sin() принимает параметр в радианах. Необходимо взять градусы, которые получились умножением float_x (x/5.0f) на 40.0f, чтобы конвертировать их в радианы делением, мы берем градусы.

Далее приводится текст функции DrawGLScene:

Int DrawGLScene(GLvoid)

// Рисование сцены

{

 

Int x, y;

// Переменные циклов

// Разбиение флага на маленькие квадраты float float_x, float_y, float_xb, float_yb;

Различные переменные используются для контроля в циклах. Большинство из них служит лишь для контролирования циклов и хранения временных значений:

glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);

// Очистить экран и буфер глубины

102

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