
2633
.pdf{
done=TRUE; // ESC или DrawGLScene просигналили "выход"
}
else // Не время выходить, обновляет экран
{
SwapBuffers(hDC); // Переключает буферы
Встроке ниже проверяется, нажата ли клавиша '+' на цифровой клавиатуре, если она нажата, и slowdown больше чем 1.0f, то slowdown уменьшается на 0.01f. в таком случае частицы будут двигаться быстрее:
if (keys[VK_ADD] && (slowdown>1.0f)) slowdown-=0.01f; //Скорость частицы увеличилась Далее проверяется, нажата ли клавиша '-' на цифровой клавиатуре,
если она нажата, и slowdown меньше чем 4.0f, то увеличивается slowdown, это заставляет частицы двигаться медленнее:
if (keys[VK_SUBTRACT] && (slowdown<4.0f)) slowdown+=0.01f;
//Торможение частиц
Встроке ниже проверяется, нажата ли клавиша PAGE UP, если она нажата, то переменная zoom увеличивается. Это заставит частицы двигаться на крупном плане:
if (keys[VK_PRIOR]) zoom+=0.1f; // Крупный план
Можно задать возможность противоположного эффекта: нажимая клавишу Page down, уменьшиться zoom, и сцена сместиться глубже в
экран: |
|
if (keys[VK_NEXT]) zoom-=0.1f; |
// Мелкий план |
Вследующей части кода происходит проверка, была ли нажата клавиша Enter:
if (keys[VK_RETURN] && !rp) // нажата клавиша Enter
{
rp=true; // Установка флага, что клавиша нажата rainbow=!rainbow; // Переключение режима радуги в Вкл/Выкл
}
if (!keys[VK_RETURN]) rp=false; // Если клавиша Enter не нажата – сбросить флаг
Если она нажата в первый раз, и она не удерживается некоторое время, то устанавливается rp в true. Тем самым переключается режим радуги. Если радуга была true, она станет false. Если она была false, то станет true. В последней строке проверяется, была ли клавиша Enter отпущена. Если это так, то rp устанавливается в false, сообщая компьютеру, что клавиша больше не нажата.
Впервой строке ниже идет проверка, нажата ли клавиша 'пробел' и не удерживается ли она. Тут же проверяется, включен ли режим радуги,
иесли так, то проверяется значение переменной delay больше чем 25.
163
delay – счетчик, который используется для создания эффекта радуги. При помощи создания задержки, группа частиц останется с одним цветом, прежде чем цвет будет изменен на другой.
Если клавиша 'пробел' была нажата, или радуга включена, и задержка больше чем 25сек., цвет будет изменен:
if ((keys[' '] && !sp) || (rainbow && (delay>25))) // Пробел или режим радуги
{
Строка ниже была добавлена, для того чтобы режим радуги был выключен, если клавиша 'пробел' была нажата:
if (keys[' ']) rainbow=false; // Если пробел нажат запрет режима радуги
Таким образом, если клавиша 'пробел' была нажата, или режим радуги включен, и задержка больше чем 25 сек. – 'пробел' был нажат, делая sp равной true. Затем задается задержка равная 0, чтобы снова начать считать до 25 сек.:
sp=true; // Установка флага нам скажет, что пробел нажат
delay=0; |
// Сброс задержки циклической смены цветов радуги |
|
col++; |
// Изменить цвет частицы |
|
Если цвет превышает значение одиннадцать, сбрасывается |
||
обратно в ноль: |
|
|
if (col>11) col=0; |
// Если цвет выше, то сбросить его |
}
if (!keys[' ']) sp=false; // Если клавиша пробел не нажата, то сбросим флаг
В строке ниже проверяется, нажата ли 'стрелка вверх'. Если это так, то yspeed будет увеличено. Это заставит частицы двигаться вверх:
//Если нажата клавиша вверх и скорость по Y меньше чем 200, то увеличить скорость
if (keys[VK_UP] && (yspeed<200)) yspeed+=1.0f;
Далее в строке проверяется, нажата ли клавиша 'стрелка вниз':
//Если стрелка вниз и скорость по Y больше чем – 200, то увеличить скорость падения
if (keys[VK_DOWN] && (yspeed>-200)) yspeed-=1.0f;
Если это так, то yspeed будет уменьшено. Это заставит частицу двигаться вниз. И снова, задан максимум скорости вниз не больше чем
200.
Теперь осуществим проверку нажата ли клавиша 'стрелка вправо':
//Если стрелка вправо и X скорость меньше чем 200, то увеличить скорость вправо
if (keys[VK_RIGHT] && (xspeed<200)) xspeed+=1.0f;
164
// Если стрелка влево и X скорость больше чем –200, то увеличить скорость влево
if (keys[VK_LEFT] && (xspeed>-200)) xspeed-=1.0f;
delay управляет скоростью смены цветов, когда используется
режим радуги: |
|
delay++; |
// Увеличить счетчик задержки циклической |
смены цветов в режиме радуги |
Если это так, то xspeed будет увеличено. Это заставит частицы двигаться вправо. Задан максимум скорости не больше чем 200.
Далее приведен код проверки заголовока сверху окна:
if (keys[VK_F1]) |
// Была нажата кнопка F1? |
{ |
|
keys[VK_F1]=FALSE; |
// Если так – установит значение |
FALSE |
|
KillGLWindow(); |
// Закроет текущее окно OpenGL |
fullscreen=!fullscreen; |
// Переключит режим "Полный |
экран"/"Оконный" |
|
// Заново создаст окно OpenGL |
|
if (!CreateGLWindow(640,480,16,fullscreen)) |
|
{ |
|
return 0; |
// Выйти, если окно не было создано |
} |
|
} |
|
} |
|
} |
|
} |
|
// Сброс |
|
KillGLWindow(); |
// Закроет окно |
return (msg.wParam); |
// Выйдет из программы |
} |
|
Таким образом, в рассмотренном примере были детально объяснены все шаги, которые требуются для создания системы моделирования частиц. Эта система моделирования частиц может использоваться в играх для создания эффектов типа огня, воды, снега, взрывов, падающих звезд, и так далее. Код может быть легко модифицирован для обработки большего количество параметров, и создания новых эффектов (например, фейерверк). Примеры реализации программного кода с небольшими изменениями приведены на рис.3436.
Контрольные вопросы
165

1.Какие параметры должна содержать текстура частицы?
2.Как создать эффект радуги?
3.Как изменить скорость движения частицы?
4.Зачем нужны переменные life и fade?
5.Как реализовать движение частиц вниз или вверх?
6.В какой части кода надо внести изменения и дополнения чтобы реализовать эффект взрыва?
7.Как разместить тот или иной эффект на крупном плане?
8.Поясните смысл команды: particle[loop].x+=particle[loop].xi/(slowdown*1000).
9.Поясните смысл команды: if (keys[VK_NUMPAD8] && (particle[loop].yg<1.5f)) particle[loop].yg+=0.01f.
Рис. 34. Эффект огненного фонтана
166

Рис. 35 Эффект бенгальского огня
Рис. 36 Эффект взрыва
Заключение
Сложность компьютерной графики определяется тем, что она базируется на знаниях многих и многих дисциплин, например, тригономтрии, начертательной геометрии, физики, оптики и др. Компьютерная графика «требовательна» к знаниям и опыту
167
программирования. Несмотря на это «Компьютерная графика» – дисциплина, которая позволяет программисту в полной мере проявить свои творческие способности и неординарные способности к программированию.
Изучение данного пособия – первый шаг в программировании компьютерной графики. Пособие рассчитано на узучение дисциплины в объеме одного семестра и не может охватить обширный теоретический материал зарубежных авторов и, к сожалению, не многие разработки российских авторов.
Всети Inernet любой заинтересованный программист может найти
иочень похожие примеры, и множество более интересных и сложных. Наибольший интерес представляют выложенные коды для реализации сложнейших, в смысле эффектов компьютерной графики, анимационных 3D игр.
168
Библиографический список
1. Ву М., Дэвис Т., Нейдер Дж., Шрайндер Д. OpenGL. Руководство по программированию. Библиотека программиста. 4-е издание. – Питер, 2006. – 624 с.
2.Баяковский Ю.М., Игнатенко А.В. Начальный курс OpenGL. М: – Планета знаний, – 2007. – 221с.
3.Дональд Херн, М. Паулин Бейкер. Компьютерная графика и стандарт OpenGL = Computer Graphics with OpenGL. – 3-е изд. – М.: Вильямс, 2005. – 1168 с.
4.Поляков А.Ю. Методы и алгоритмы компьютерной графики примерах на
Visual C++: Спб.: БХВ-Петербург, 2004 – 416 с.
5.Пореев В.Н. Компьютерная графика. – СПб.: БХВ-Петербург, 2004. – 432 с.
6.Ричард С. Райт мл, Липчак Б. OpenGL. Суперкнига – 3 изд. – М.: Вильямс, 2006. – 1040 с.
7.Энджел Э. Интерактивная компьютерная графика. Вводный курс на базе
OpenGL – 2-е изд. – М.: Вильямс, 2001. – 592 с.
8.Каверин М. OpenGL. Официальное Руководство программиста. [Электронный ресурс] // URL: http://www.geo3dcgp.com/opengl/books/OpenGL_RedBook_rus.pdf (дата обращения 10.01.2012)
9.Тарасов И. OpenGL. [Электронный ресурс] // URL: http://www.helloworld.ru/texts/comp/games/opengl/opengl2/index.html (дата обращения 10.01.2012)
10.OpenGL. Программирование с использованием OpenGL. [Электронный ресурс] //URL:http://opengl.org.ru/books/open_gl/chapter2.8.html (дата обращения 12.01.2012)
11.Программирование в Интернет и под Windows. Программирование графики. [Электронный ресурс] // URL: http://www.ru-coding.com/index.php (дата обращения 22.12.2011)
12.Работа с OpenGL. Электронный ресурс. OpenGL – уроки от NeHe (англ.).
[Электронныйресурс]//URL: http://nehe.gamedev.net/tutorial/volumetric_fog_ipicture_image_loading (дата обращения 08.11.2011)
13.Программирование с использованием OpenGL. Уроки OpenGL. [Электронный ресурс]//URL: http://opengl.org.ru/lesson/index.html (дата обращения: 05.11.2012)
14.Работа с OpenGL. [Электронный ресурс] // URL: http://pmg.org.ru/nehe/index.html (датаобращения:05.12.2011).
169
Приложение 1
Листинг программы создания 3D объкета Стеклянная ваза
#include <windows.h> |
Windows |
Заголовочный файл для |
|
#include <stdio.h> |
стандартной библиотеки ввода/вывода |
Заголовочный файл для |
|
#include <gl\glaux.h> |
библиотеки GLaux |
Заголовочный файл для |
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 нажата? |
|
|
GLfloat xrot; |
|
Xвращение
GLfloat yrot;
Yвращение
GLfloat xspeed;
Xскорость вращения
GLfloat yspeed;
Yскорость вращения
GLfloat z=5.0f;
Глубина экрана
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[1];
Место для текстуры
170
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
Объявление WndProc
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/Wall.bmp"))
{
Status=TRUE;
Установим Status в TRUE
171
glGenTextures(3, &texture[0]);
Создание трех текстур
glBindTexture(GL_TEXTURE_2D, texture[2]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINE AR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINE AR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, TextureImage[0]>sizeX, TextureImage[0]>sizeY, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]>data);
Создание текстуры с фильтром по соседним пикселям
}
if (TextureImage[0])
Если текстура существует
{
if (TextureImage[0]>data)
Если изображение текстуры существует
{
free(TextureImage[0]>data);
Освобождение памяти изображения текстуры
}
free(TextureImage[0]);
Освобождение памяти под структуру
}
return Status;
Возвращаем статус
}
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
Изменить размер и инициализировать окно GL
{
if (height==0)
Предотвращение деления на ноль
{
height=1;
}
glViewport(0,0,width,height);
Сброс текущей области вывода
glMatrixMode(GL_PROJECTION);
Выбор матрицы проекций
glLoadIdentity();
Сброс матрицы проекции
Вычисление соотношения геометрических размеров для окна
172