Особенности работы с Direct 3D и основные сведения об OpenGL
Direct 3D Retained Mode (RM) как набор интерфейсов для работы с трехмерной графикой. Его использование для загрузки сеток, расположения источников освещения и оживления полученной сцены. Инициализация указателей и устройств, моделирование объектов.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курс лекций |
Язык | русский |
Дата добавления | 10.01.2014 |
Размер файла | 349,1 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
// Данные для создания плоской грани
D3DVECTOR verts_face[4] = { 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, -1.0f, 1.0f, 0.0f };
D3DVECTOR normals_face[4] = { 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f,
0.0f, 0.0f, -1.0f, 0.0f, 0.0f, -1.0f };
DWORD face_normal_data[] = { 4, 0, 0, 1, 1, 2, 2, 3, 3, 0 };
D3DCOLOR colors_face[4]={
0xFF7AFC,0x017AFC,0x057A03,0xFD7A02,
};
Построение грани делается в функции build_face.
// Построение плоской грани
BOOL build_face(LP DIRECT3DRMMESHBUILDER3 mb)
{
int i;
// Создание вершин
for (i=0; i<4; i++)
{
mb->AddVertex(verts_face[i].x,verts_face[i].y,verts_face[i].z);
mb->AddNormal(
normals_face[i].x,normals_face[i].y,normals_face[i].z);
mb->SetVertexColor(i,colors_face[i]);
}
// Создание граней
mb->AddFacesIndexed(0,face_normal_data,0,0);
// Цвет из вершин
mb->SetColorSource(D3DRMCOLOR_FROMVERTEX);
// Убрать освещение
mb->SetQuality(D3DRMRENDER_GOURAUD&(~D3DRMLIGHT_ON)|(D3DRMLIGHT_OFF));
return TRUE;
}
В цикле создаются четыре вершины. Происходит добавление позиции вершины (AddVertex), нормали (AddNormal), установка цвета вершины по номеру (SetVertexColor). Непосредственно грань создается функцией AddFacesIndexed. Первый параметр (флаги настройки) должен быть в нашем случае 0, т. к. мы задаем и нормали. Если нормали не нужны, то его значение - D3DRMADDFACES_VERTICESONLY. Второй параметр задает массив данных, которые задают номера вершин и нормалей, причем последние уже должны быть добавлены в интерфейс Построителя Сетки. Первое значение массива номеров задает число вершин в грани, далее идут пары значений, которые задают номер вершины и номер нормали. Нуль в конце задавать не надо. Последние два параметра возвращают номер первой созданной грани и число добавленных граней.
Функцией SetColorSource устанавливается тип цветового источника: из грани - D3DRMCOLOR_FROMFACE, или из вершины - D3DRMCOLOR_FROMVERTEX. Так как надо получить цветовой градиент, то устанавливается тип цветового источника из вершины.
Как упоминалось в первой статье, любая сетка должна быть освещена, чтобы быть видимой. Это так, но вполне можно обойтись и без этого, отключив освещение для данной сетки. Это сделано таким образом:
// Убрать освещение
mb->SetQuality(D3DRMRENDER_GOURAUD&(~D3DRMLIGHT_ON)|(D3DRMLIGHT_OFF));
Нужно обязательно установить режим закраски Гуро, чтобы каждая точка на грани получила свой цвет, затем отключить освещение, иначе градиент пропадет, и сетка будет закрашена в соответствие с падающим светом.
На этом мы закончим рассмотрение четырех разных способов создания объектов средствами интерфейса MeshBuilder. В следующей статье будут рассмотрены способы создания фигур вращения, таких как конус, цилиндр, шар.
§3. Основные сведения об OpenGL
OpenGL по своей концепции содержит некоторое концептуальное отличие от DirectX, причем имеет под собой гораздо более глубокую историю, ведущуюся еще от разработчиков Silicon Graphics, и, в принципе, ни для кого не секрет, что раньше большая часть трехмерной анимации делалась именно на этих компьютерах. OpenGL расшифровывается как Open Graphic Library, то есть открытая графическая библиотека, которая может пополняться за счет различных фирм и отдельных разработчиков при условии соответствия определенному стандарту и прохождения тестов. Она достаточно интересна как в рассмотрении, так и в применении. Заложенные процедуры имеют все ключевые возможности, а именно, работу с растровой и векторной графикой, двух- и трехмерным моделированием, текстуризацией, созданием сцен, управлением освещения и движения камер. Также есть весь необходимый набор эффектов, таких как, например, прозрачность, туман, смешивание цветов и т. п. Она стоит несколько ближе к пакетам 3D-моделирования, потому как может генерировать трехмерные поверхности (сферы, многогранники), позволяет использовать кривые Безье и B-сплайны (NURBS-сплайны). Основной единицей информации для программиста, использующего OpenGL, является вершина, и нет строгой привязки к примитивам, что мы можем наблюдать в Direct3D. То есть, он самостоятельно может указывать параметры соединения вершин: линиями, собирать их в различные многоугольники, их последующая триангуляция может производиться в автоматическом режиме либо с помощью специальных команд. Среди плюсов OpenGL стоит отметить надежность, практическую независимость от платформ и аппаратной части ПК (это немного спорно), стабильность отображения полученного результата на разных компьютерах (это называется переносимостью), а самый большой плюс -- это быстрая инициализация и сравнительная простота разработки в ее рамках. Минус -- медлительность, и на самом деле уже достаточно слабая распространенность именно в геймдеве, хотя из разработчиков игр у OpenGL до сих пор остается множество приверженцев, даже среди высшей касты. Хотя медлительность для современных игр -- это очень плохая характеристика.
Команды в OpenGL можно условно разделить на две части: одни применяются для создания объектов, другие -- для управления отображением оных на экране. Набор базовых команд OpenGL включает примерно 300, причем в WinAPI вы можете получить доступ к ним из разных языков программирования, например, не только С, но и Delphi, и Fortran. Кстати, именно последний указывает на то, почему OpenGL так полюбился в рамках систем автоматического проектирования (САПР) в том числе.
OpenGL оснащен специальной библиотекой утилит (GLU), команды которой дополняют базовые функции OpenGL, и, благодаря ей, можно работать с теми же кривыми Безье и так далее. Есть и еще дополнительные библиотеки, например, AUX, которая позволяет обрабатывать события, обеспечивать вывод стандартных трехмерных объектов, управлять окнами, двойной буферизацией.
То есть, по существу, OpenGL -- это универсальное и мощное средство в умелых руках. Хотя у DirectX в определенном смысле есть некоторое неоспоримое преимущество. Говоря об аппаратной независимости OpenGL, мы немного слукавили, поскольку она подразумевает уровень включения (и соответственно поддержки) драйверов основного оборудования. Разработчики DirectX, а это никто иной как Microsoft, в этом случае пошли по другому пути, а именно, они подогнули производителей видеокарт под себя.
Самым простым объектом, с помощью которого можно увидеть всю мощь OpenGL, является сфера. Давайте попытаемся ее изобразить. Для этого надо создать новый проект в VisualC++, выполните следующие действия:
1. Запустите MSVisualC++6.0.
2. Щелкните меню File->New->Win32 Console Application.
3. Выберете каталог и имя проекта, впишите - sphere, щелкните OK.
Я все свои проекты держу на диске D в каталоге Projects. Projects ветвится дальше на подкатологи с базами данных, утилитами, графикой и Java-приложениями. В общем, старайтесь присваивать разумные имена и вести разумную структуру каталогов. Это очень серьезная проблема.
4. Выберете An Empty Project, щелкните Finish.
5. Cкопируйте в каталог вашего проекта мой шаблон glaux.c и переименуйте его в sphere.c
6. Присоедините его к проекту. Project->Add To Project->Files
7. Щелкните Build->Set Active Configuration и установите тип проекта sphere - Win32 Release
8. Далее, щелкайте Project->Settings->Link->Object/library modules и добавьте туда opengl32.lib, glu32.lib и glaux.lib
9. Вставьте в функцию display следующий код:
10. glColor3d(1,0,0);
11. auxSolidSphere(1);
12. Теперь откомпилируйте и запустите Вашу программу.
13. Меню Build->Execute Sphere.exe.
Рис. 3
Исходный файл смотрите здесь. Исполняемый файл здесь.
/*
* (c) Copyright 1995-1999, Igor Tarasov
* FidoNet: 2:5020/370.2 620.20 1103.5
* Inet: itarasov@rtuis.miem.edu.ru
* Phone: (095)942-50-97
*/
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void CALLBACK resize(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-5,5, -5,5, 2,12);
gluLookAt(0,0,5, 0,0,0, 0,1,0);
glMatrixMode(GL_MODELVIEW);
}
void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/* remove next tree lines
* and enter your code here
*/
glTranslated(0.01,0,0);
glColor3d(1,0,0);
auxSolidSphere(1);
auxSwapBuffers();
}
void main()
{
float pos[4] = {3,3,3,1};
float dir[3] = {-1,-1,-1};
GLfloat mat_specular[] = {1,1,1,1};
auxInitPosition(50, 10, 400, 400);
auxInitDisplayMode(AUX_RGB | AUX_DEPTH | AUX_DOUBLE);
auxInitWindow("Glaux Template");
auxIdleFunc(display);
auxReshapeFunc(resize);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glLightfv(GL_LIGHT0, GL_SPOT_ DIRECTION, dir);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialf(GL_FRONT, GL_SHININESS, 128.0);
/*
* Enter your cod here
*/
auxMainLoop(display);
}
Теперь поясню назначение тех двух функций, что вы вставили в пункте 9. Функция glColor3d устанавливает текущий цвет, которым будут рисоваться фигуры. Тут нужно пояснить, как устанавливается цвет, и общую философию в названии функций OpenGL. Цвет устанавливается четырьмя параметрами: красный, синий, зеленый и прозрачность. Эти параметры варьируются в диапазоне от нуля до единицы. Четвертый параметр нам пока не нужен, поэтому мы вызвали glColorс тремя параметрами. В этом случае, значение четвертого параметра, прозрачности, по умолчанию считается равным единице, т. е. абсолютно непрозрачным, ноль - будет абсолютно прозрачным. Так как в языке Си нет перегрузки функций, то применяется следующий синтаксис вызова функций - FuncionName[n=число параметров][тип параметров]. Доступны следующие типы:
· b - GLbyte байт
· s - GLshort короткое целое
· i - GLint целое
· f - GLfloat дробное
· d - GLdouble дробное с двойной точностью
· ub - GLubyte беззнаковый байт
· us - GLushort беззнаковое короткое целое
· ui - GLuint беззнаковое целое
· v - массив из n параметров указанного типа
В нашем случае, glColor3d означает, что в функцию передаются три параметра типа GLdouble. Также можно было вызвать glColor3i, т.е. три параметра типа GLint. Если тип параметров короткое целое, целое, байт или длинное, то компонент цвета приводится к диапазону [0, 1]. Приведение к этому диапазону осуществляется следующим образом. В случае беззнакового типа наибольшее возможное значение приводится к единице, ноль к нулю. В случае знакового типа максимальное значение приводится к единице или к минус единице, а минус единица будет приведена к единице. Мудрено, сразу и не поймешь. На практике вы будете пользоваться одним из трех случаев, рассмотренных в качестве примера ниже. Например, для беззнакового байта приведение будет осуществлено по следующей формуле: значение_переменной_хранимой_в_байте/255, т. к. 255 максимальное число, хранимое в одном байте. Функция glColor3dv означает, что в качестве параметров передается массив из трех элементов типа GLdouble. Например:
double array[] = {0.5, 0.75, 0.3, 0.7};
glColor3dv(array);
glColor3ub(200,100,0); // приводится к 200/256, 100/256, 0,256
glColor3d(0.25,0.25,0); // темно-желтый
glColot3ub(0,100,0); // темно-зеленый
glColor3ub(0,0,255); // синий
Функция auxSolidSphere - рисует сферу в начале координат и единичным радиусом. Освещение, создание ламп и установку положения камеры мы рассмотрим чуть позже, а пока давайте получше освоимся и почувствуем, насколько здесь все просто. Первую программу под моим руководством вы уже написали. Теперь выполните самостоятельные упражнения.
Замените функцию auxSolidSphere на функцию, из указанных ниже с соответствующими параметрами. Значения параметров устанавливайте порядка единицы - 0.5-1.7. Если вы укажете слишком маленький размер, фигуру будет плохо видно; если слишком большой, то она получится урезанной. Это связано с тем, что ее край, как бы вылезет из монитора.
· auxSolidCube(width) // куб
· auxSolidBox(width, height, depth) // коробка
· auxSolidTorus(r,R) // тор
· auxSolidCylinder(r,height) // цилиндр
· auxSolidCone(r,height) // конус
· auxSolidIcosahedron(width) // многогранники
· auxSolidOctahedron(width)
· auxSolidTetrahedron(width)
· auxSolidDodecahedron(width)
· auxSolidTeapot(width) // рисует чайник
С помощью вышеуказанных функций вы можете рисовать сплошные фигуры. Если вам надо нарисовать проволочную, то вместо Solid пишите Wire.
Пример:
auxWireCube(1) // рисует проволочный куб
Переход к новым координатам.
Продолжим рисовать трехмерные фигуры. В предыдущем параграфе вы научились рисовать примитивные трехмерные объекты. Но проблема в том, что они рисуются только в начале координат, т. е. в точке (0,0,0). Для того чтобы изобразить сферу в точке (x0,y0,z0), надо переместить начало координат в эту точку, т. е. надо перейти к новым координатам. Эта процедура, довольно распространенная при программировании графики и анимации. Часто бывает очень удобно сместить координаты в новую точку и повернуть их на требуемый угол, и ваши расчеты резко упростятся. Конкретный пример, мы рассмотрим ниже, когда научимся программировать анимацию. А пока вы узнаете, как переходить к новым координатам. Для перехода к новым координатам в OpenGL есть две функции:
· glTranslated(x,y,z)
· glRotated(x0,y0,z0)
Первая функция сдвигает начало системы координат на (x,y,z). Вторая - поворачивает на угол против часовой стрелки вокруг вектора (x0,y0,z0). Теперь, стоит сказать еще о двух очень важных функциях:
· glPushMatrix()
· glPopMatrix()
Они предназначены для сохранения и восстановления текущих координат. Я не стал здесь приводить пример на то, как неудобно переходить от одной системы координат к другой и помнить все ваши переходы. Гораздо удобнее с помощью glPushMatrix() сохранить текущие координаты, потом сдвигаться, вертеться, как вам угодно, а после, вызовом glPopMatrix, вернуться к старым координатам. Итак, настало время поэкспериментировать. Назовите его sphere2. Сначала мы рассмотрим сдвиг координат. Вставьте в функцию display следующий код:
glPushMatrix(); // сохраняем текущие координаты
glTranslated(1.4,0,0); // сдвигаемся по оси Х на 1.4
glColor3d(0,1,0);
auxSolidSphere(0.5); // рисуем сферу в (1.4,0,0)
// в абсолютных координатах
glTranslated(1,0,0); // еще раз сдвигаемся
glColor3d(0,0,1);
auxSolidSphere(0.3);
glPopMatrix(); // возвращаемся к старой системе координат
glColor3d(1,0,0);
auxSolidSphere(0.75); // рисуем сферу в точке (0,0,0)
// в абсолютных координатах
Теперь, откомпилируйте и запустите вашу программу.
Меню Build->Execute Sphere.exe
Рис. 4
Исходный файл смотрите здесь. Исполняемый файл здесь.
/*
* (c) Copyright 1995-1999, Igor Tarasov
* FidoNet: 2:5020/370.2 620.20 1103.5
* Inet: itarasov@rtuis.miem.edu.ru
* Phone: (095)942-50-97
*/
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void CALLBACK resize(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-5,5, -5,5, 2,12);
gluLookAt(0,0,5, 0,0,0, 0,1,0);
glMatrixMode(GL_MODELVIEW);
}
void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix(); // сохраняем текущие координаты
glTranslated(1.4,0,0); // сдвигаемся по оси Х на единицу
glColor3d(0,1,0);
auxSolidSphere(0.5); // рисуем сферу в (1,0,0)
// в абсолютных координатах
glTranslated(1,0,0); // еще раз сдвигаемся
glColor3d(0,0,1);
auxSolidSphere(0.3);
glPopMatrix(); // возвращаемся к старой системе координат
glColor3d(1,0,0);
auxSolidSphere(0.75); // рисуем сферу в точке (0,0,0)
// в абсолютных координатах
auxSwapBuffers();
}
void main()
{
float pos[4] = {3, 3, 3, 1};
float dir[3] = {-1, -1, -1};
auxInitPosition(50, 10, 400, 400);
auxInitDisplayMode(AUX_RGB | AUX_DEPTH | AUX_DOUBLE);
auxInitWindow("Sphere2");
auxIdleFunc(display);
auxReshapeFunc(resize);
glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glLightfv(GL_LIGHT0, GL_SPOT_ DIRECTION, dir);
auxMainLoop(display);
}
В общем-то, из комментариев многое понятно. Обращаю ваше внимание только на два последних вызова auxSolidSphere. Перед вызовом glPopMatrix сфера рисуется в точке (2, 0, 0), а после - в точке (0, 0, 0).
Упражнение: "Cписок трехмерных фигур".
Используя список функций из предыдущего упражнения, нарисуйте эти фигуры в два столбца. Слева - проволочные. Справа - сплошные. Примечание: тут хочу заметить, что в версии glaux.lib от фирмы Microsoft имеется следующий баг: цилиндр и конус рисуются всегда либо проволочными, либо сплошными. Если вы первый цилиндр/конус в программе нарисовали проволочным, то далее все цилиндры/конусы будут проволочными. Соответственно, если первой была сплошная фигура, то далее все будут сплошные. Поэтому, не стоит паниковать. Это ошибка Microsoft. Могу также вас порадовать, что ниже я расскажу, как обойти эту проблему.
Рис. 5
Исходный файл смотрите здесь. Исполняемый файл здесь.
/*
* (c) Copyright 1995-1999, Igor Tarasov
* FidoNet: 2:5020/370.2 620.20 1103.5
* Inet: itarasov@rtuis.miem.edu.ru
* Phone: (095)942-50-97
*/
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void CALLBACK resize(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-5,5, -5,5, 2,12);
gluLookAt(0,0,5, 0,0,0, 0,1,0);
glMatrixMode(GL_MODELVIEW);
}
void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslated(0.5,4,0);
glColor3d(0,0,1);
auxSolidCube(1); // куб
glTranslated(0,-2,0);
glColor3d(0,1,0);
auxSolidBox(1,0.75,0.5); // коробка
glTranslated(0,-2,0);
glColor3d(0,1,1);
auxSolidTorus(0.2,0.5); // тор
glTranslated(0,-2,0);
glColor3d(1,0,0);
auxSolidCylinder(0.5,1); // цилиндер
glTranslated(0,-2,0);
glColor3d(0,1,0);
auxSolidCone(1,1); // конус
glTranslated(2,8,0);
glColor3d(1,0,1);
auxSolidIcosahedron(1); // многогранники
glTranslated(0,-2,0);
glColor3d(1,1,1);
auxSolidOctahedron(1);
glTranslated(0,-2,0);
glColor3d(0,1,1);
auxSolidTeapot(0.7); // рисует чайник
glTranslated(0,-2,0);
glColor3d(0,1,0);
auxSolidTetrahedron(1);
glTranslated(0,-2,0);
glColor3d(1,1,0);
auxSolidDodecahedron(1);
glTranslated(-6,8,0);
glColor3d(0,0,1);
auxWireCube(1); // куб
glTranslated(0,-2,0);
glColor3d(0,1,0);
auxWireBox(1,0.75,0.5); // коробка
glTranslated(0,-2,0);
glColor3d(0,1,1);
auxWireTorus(0.2,0.5); // тор
glTranslated(0,-2,0);
glColor3d(1,0,0);
auxWireCylinder(0.5,1); // цилиндер
glTranslated(0,-2,0);
glColor3d(0,1,0);
auxWireCone(1,1); // конус
glTranslated(2,8,0);
glColor3d(1,0,1);
auxWireIcosahedron(1); // многогранники
glTranslated(0,-2,0);
glColor3d(1,1,1);
auxWireOctahedron(1);
glTranslated(0,-2,0);
glColor3d(0,1,1);
auxWireTeapot(0.7); // рисует чайник
glTranslated(0,-2,0);
glColor3d(0,1,0);
auxWireTetrahedron(1);
glTranslated(0,-2,0);
glColor3d(1,1,0);
auxWireDodecahedron(1);
glPopMatrix();
auxSwapBuffers();
}
void main()
{
float pos[4] = {3,3,3,1};
float dir[3] = {-1,-1,-1};
auxInitPosition(50, 10, 400, 400);
auxInitDisplayMode(AUX_RGB | AUX_DEPTH | AUX_DOUBLE);
auxInitWindow("Shapes");
auxIdleFunc(display);
auxReshapeFunc(resize);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glLightfv(GL_LIGHT0, GL_SPOT_ DIRECTION, dir);
auxMainLoop(display);
}
Поворот координат.
Теперь рассмотрим вращение координат. Создайте новый проект с именем Rotate. Переименуйте glaux.c в rotate.c В функцию display вставьте следующий код:
glColor3d(1,0,0);
auxSolidCone(1, 2); // рисуем конус в центре координат
glPushMatrix(); // сохраняем текущие координаты
glTranslated(1,0,0); // сдвигаемся в точку (1,0,0)
glRotated(75, 1,0,0); // поворачиваем систему координат на 75 градусов
glColor3d(0,1,0);
auxSolidCone(1, 2); // рисуем конус
glPopMatrix(); // возвращаемся к старым координатам
Как видите, конус повернулся в абсолютных координатах. Так что, для того, чтобы нарисовать фигуру не в начале координат, надо:
1. сохранить текущие координаты
2. сдвинуть(glTranslated), повернуть(glRotated)
3. нарисовать то, что хотели
4. вернуться к старым координатам
Вызовы glPushMatrixglPopMatrix могут быть вложенными, т. е.:
glPushMatrix();
glPushMatrix();
glPopMatrix();
glPopMatrix();
Естественно, число вызовов glPopMatrix должно соответствовать числу вызовов glPushMatrix, иначе у вас сцена улетит в неизвестном направлении. Максимально допустимая глубина вложенности glPushMatrix/glPopMatrix определяется следующим образом:
int n;
glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, &n);
printf("n=%d\n",n);
Спецификация на OpenGL гарантирует, что глубина стека не может быть меньше 32.
Упражнение: "Снеговик".
Используя функцию glRotate, нарисуйте снеговика. Три сферы, шапка - конус, нос - тоже конус, глаза - сфера, рот можно квадратным сделать - glBox.
Исходный файл смотрите здесь. Исполняемый файл здесь.
Примечание: Имеется еще один баг в glaux.lib от Microsoft. Кажется, последний из обнаруженных мной. Функция aux[Solid/Wire]Cylinder прежде, чем нарисовать цилиндр, сдвигает и поворачивает координаты. Так что, если вы уже сместили и повернули координаты, то цилиндр нарисуется совсем не там, где вы рассчитывали. Люди из Microsoft, конечно же, будут уверять, что это особенность, и предложат вам скачать очередной ServicePack.;-)
А я ниже расскажу, как более правильно рисовать цилиндры и конусы. Если вам некогда ждать, то далее приведен исправленный код этих функций. Большинство из вас сейчас пропустят его и перейдут к следующему очень интересному разделу - "Анимация". И правильно сделаете. К исправлению ошибок вернетесь, когда немного освоитесь. Но я все же решил привести код по исправлению ошибок Microsoft именно здесь. Можете пересобрать glaux.lib, заменив соответствующий код в файле shapes.c. Где взять исходники, смотрите в приложении 'A'. По-моему, они есть в MSDN.
интерфейс трехмерный графика
void auxWireCylinder (GLdouble radius, GLdouble height)
{
GLUquadricObj *quadObj;
GLdouble *sizeArray, *tmp;
GLuint displayList;
sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2);
tmp = sizeArray;
*tmp++ = radius;
*tmp++ = height;
displayList = findList (CYLINDERWIRE, sizeArray, 2);
if (displayList == 0) {
glNewList(makeModelPtr (CYLINDERWIRE, sizeArray, 2),
GL_COMPILE_AND_EXECUTE);
quadObj = gluNewQuadric ();
gluQuadricDrawStyle (quadObj, GLU_LINE);
gluCylinder (quadObj, radius, radius, height, 12, 2);
glEndList();
}
else {
glCallList(displayList);
free (sizeArray);
}
}
void auxSolidCylinder (GLdouble radius, GLdouble height)
{
GLUquadricObj *quadObj;
GLdouble *sizeArray, *tmp;
GLuint displayList;
sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2);
tmp = sizeArray;
*tmp++ = radius;
*tmp++ = height;
displayList = findList (CYLINDERSOLID, sizeArray, 2);
if (displayList == 0) {
glNewList(makeModelPtr (CYLINDERSOLID, sizeArray, 2),
GL_COMPILE_AND_EXECUTE);
quadObj = gluNewQuadric ();
gluQuadricDrawStyle (quadObj, GLU_FILL);
gluQuadricNormals (quadObj, GLU_SMOOTH);
gluCylinder (quadObj, radius, radius, height, 12, 2);
glEndList();
}
else {
glCallList(displayList);
free (sizeArray);
}
}
void auxSolidCone (GLdouble base, GLdouble height)
{
GLUquadricObj *quadObj;
GLdouble *sizeArray, *tmp;
GLuint displayList;
sizeArray = (GLdouble *) malloc (sizeof (GLdouble) * 2);
tmp = sizeArray;
*tmp++ = base;
*tmp++ = height;
isplayList = findList (CONESOLID, sizeArray, 2);
if (displayList == 0) {
glNewList(makeModelPtr (CONESOLID, sizeArray, 2),
GL_COMPILE_AND_EXECUTE);
quadObj = gluNewQuadric ();
gluQuadricDrawStyle (quadObj, GLU_FILL);
gluQuadricNormals (quadObj, GLU_SMOOTH);
gluCylinder (quadObj, base, (GLdouble)0.0, height, 15, 10);
glEndList();
}
else {
glCallList(displayList);
free (sizeArray);
}
}
Анимация.
Давайте оживим нашего снеговика и добавим интерактивность. Для этого надо отрисовывать кадры и реагировать на внешние события от клавиатуры или мыши. Для отрисовки кадров их надо как-то различать. Для этого мы в функции display вводим переменную time типа int с модификатором static. Создайте новый проект и в функцию display введите следующее: "static int time=0;". Модификатор static означает, что значение переменной будет сохраняться при выходе из функции. Начальное значение мы устанавливаем в ноль. Если функция display не зависит от времени, то счетчик кадров можно и не вести. Теперь добавьте следующие строчки:
glPushMatrix();
glTranslated(((double)time)/100.0 ,0,0);
// здесь код из предыдущего упражнения "Cнеговик"
glPopMatrix();
Запустив приложение, вы увидите, что снеговик пополз вдоль оси Х. Вот так, вы можете делать анимацию. Т. е. теперь координаты объектов вычисляются в зависимости от времени. Я привел простой пример. Вообще говоря, для программирования сложной графики вам понадобится вычислять координаты каждого отдельного объекта в зависимости от времени.
Далее мы рассмотрим пример с более сложной анимацией. Здесь вращается тор и его ось вращения. Я приведу исходный текст с подробными комментариями. Пример программы "Гироскоп":
Рис. 6
/*
* (c) Copyright 1995-1999, Igor Tarasov
* FidoNet: 2:5020/370.2 620.20 1103.5
* Inet: itarasov@rtuis.miem.edu.ru
* Phone: (095)942-50-97
*/
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void CALLBACK resize(int width,int height)
{
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-5,5, -5,5, 2,12);
gluLookAt(0,0,5, 0,0,0, 0,1,0);
glMatrixMode(GL_MODELVIEW);
}
void CALLBACK display(void)
{
static int time = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotated(time/2, 0.0, 1.0, 0.0);
glLineWidth(5.0f);
glColor3f(1.0f,0.0f,0.0f);
glBegin(GL_LINES);
glVertex3d(-0.3,0.0,0.0);
glVertex3d(1.5,0.0,0.0);
glEnd();
glPushMatrix();
glRotated(2*time, 1,0,0);
glTranslated(-0.3,0,0);
glColor3f(0,0,1);
glPushMatrix();
glRotated(90,0,1,0);
glLineWidth(1);
auxWireTorus(0.2, 0.7);
glPopMatrix();
glLineWidth(7);
glColor3f(0,1,0);
glBegin(GL_LINES);
glVertex3d(0,0,0);
glVertex3d(0,1,0);
glVertex3d(0,0,0);
glVertex3d(0,-0.5,1);
glVertex3d(0,0,0);
glVertex3d(0,-0.5,-1);
glEnd();
glPopMatrix();
glPopMatrix();
time++;
auxSwapBuffers();
}
void main()
{
float pos[4] = {3,3,3,1};
float dir[3] = {-1,-1,-1};
auxInitPosition(50, 10, 400, 400);
auxInitDisplayMode(AUX_RGB | AUX_DEPTH | AUX_DOUBLE);
auxInitWindow("Giroscop");
auxIdleFunc(display);
auxReshapeFunc(resize);
glEnable(GL_ALPHA_TEST);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
// glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glLightfv(GL_LIGHT0, GL_SPOT_ DIRECTION, dir);
auxMainLoop(display);
}
glPushMatrix(); // сохраняем текущие координаты, т.к. при выходе
// из функции нам нужно вернуться к абсолютным
// координатам
// попробуйте закомментировать вызов glPushMatrix
// здесь и glPopMatrix в конце и вы увидите, что
// из этого получится
glRotated(time/2, 0.0, 1.0, 0.0); // поворачиваем координаты
glLineWidth(5); // устанавливаем толщину линии - пять
glColor3f(1,0,0); // устанавливаем текущий цвет - красный
glBegin(GL_LINES); // рисуем красную ось
glVertex3d(-0.3,0,0); // т.к. мы повернули координаты,
glVertex3d(1.5,0,0); // ось будет повернута в абсолютных
glEnd(); // координатах, и т.к. функция display
// вызывается в цикле, и переменная
// time увеличивается на единицу
// при каждом вызове display, мы
// получаем анимацию - вращающуюся ось
glPushMatrix(); // теперь относительно повернутых координат
// мы переходим к новым координатам
glRotated(2*time, 1,0,0); // поворачиваем их на угол
// 2*time вокруг красной оси
glTranslated(-0.3,0,0); // и сдвигаем на край оси
glColor3f(0,0,1); // устанавливаем синий цвет
glPushMatrix(); // теперь еще раз переходим к
// новым координатам,
glRotated(90,0,1,0); // чтобы развернуть тор на
// 90 градусов
// у вас крыша еще не поехала?
// немного?
// то-то же, тут не так все просто,
// но если понять что и как-то
// очень удобно
// программировать графику
glLineWidth(1);
auxWireTorus(0.2, 0.7);
glPopMatrix(); // нарисовав тор, мы возвращаемся
// к предыдущим
// координатам, если забыли,
// начало этих координат
// лежит на конце красной оси
glLineWidth(7);
glColor3f(0,1,0);
glBegin(GL_LINES); // теперь рисуем три зеленых линиии
glVertex3d(0,0,0); // что тут и как рисуется, я поясню в
glVertex3d(0,1,0); // следующей
glVertex3d(0,0,0); // главе, сейчас это не так важно
glVertex3d(0,-0.5,1);
glVertex3d(0,0,0);
glVertex3d(0,-0.5,-1);
glEnd();
glPopMatrix(); // теперь возвращаемся к повернутым
// координатам на угол time/2
glPopMatrix(); // ну и переходим к абсолютным координатам
time++; // увеличиваем счетчик кадров или вермя,
// называйте как хотите,
// на единицу
Как вы, наверное, догадались, надо создать очередной проект, скопировать туда мой шаблон, добавить его в проект, указать библиотеки opengl32.lib glu32.lib glaux.lib в Project->Setting->Link->Settings->Link->Object/library modules:, вставить этот код в функцию display. Еще вам нужно в начале функции display вставить строку static int time=0; и закомментировать строчку glEnable(GL_LIGHTING) в функции main.
Запустив это приложение, вы увидите, как оно работает. Теперь закомментируйте соответсвующие друг другу вызовы glPushMatrix и glPopMatrix и посмотрите на результат. Я бы рекомендовал такой способ для изучения и понимания работы программы: вы комментируете куски кода и смотрите, что получается.
Для того чтобы реагировать на клавиатуру или мышь, вы должны определить функцию, которая будет вызываться при поступлении событий от клавиатуры или мыши. Для кнопки клавиатуры вы определяете функцию со следующим прототипом void CALLBACK FunctionName(void) и устанавливаете ее как обработчикопределенной кнопки - auxKeyFunc(key_code, FunctionName); key_code смотри в glaux.h. Пример: auxKeyFunc(AUX_LEFT, FunctionName) Здесь вы устанавливаете FunctionName как функцию, которая будет вызываться при нажатии на клавиатуре клавиши "стрелка влево".
Для мыши вы устанавливаете свою функцию обработки событий мыши вызовом функции auxMouseFunc(int button,int action,AUXMOUSEPROC). Переменная button может принимать значения - AUX_LEFTBUTTON, AUX_MIDDLEBUTTON, AUX_RIGHTBUTTON. Переменная action принимает следующие значения - AUX_MOUSEDOWN, AUX_MOUSEUP, AUX_MOUSELOC. Функция AUXMOUSEPROC должна иметь прототип - void CALLBACK FunctionName(AUX_EVENTREC *event), где AUX_EVENTREC определено как:
typedef struct _AUX_EVENTREC
{
GLint event;
GLint data[4];
}AUX_EVENTREC;
Для более детальной информации смотрите справочные руководства и исходные тексты библиотеки OpenGL Auxiliary library. Эта книга об OpenGL, а не о программировании интерфейсов пользователя. Поэтому, за подобной информацией вам придется лезть в соответсвующие справочные руководства по Win API, MFC, Java и т. п.
В FunctionName вы можете изменить какую-нибудь глобальную переменную, и соответственно, функция display будет рисовать кадры в зависимости от этой переменной.
Размещено на Allbest.ru
...Подобные документы
Программирование приложения с использованием библиотеки OpenGL и функции для рисования геометрических объектов. Разработка процедуры визуализации трехмерной сцены и интерфейса пользователя. Логическая структура и функциональная декомпозиция проекта.
курсовая работа [1,1 M], добавлен 23.06.2011Общие сведения о OpenGL и его использование для разработки логотипа. Разработка программы: функции, их использование в программе. Построение модели и возможность перемещения объектов. Задание освещения объектов моделирования и проработка элементов фона.
курсовая работа [447,7 K], добавлен 14.07.2012Построение динамической трехмерной сцены, включающей заданные тело и поверхность определенного вида средствами графической библиотеки. Наложение текстур на тела, поверхности с помощью функции SetupTextures. Графическое представление тела с текстурой.
курсовая работа [582,9 K], добавлен 24.12.2010Ознакомление с интерфейсом, основными возможностями и преимуществами использования программы OpenGL - популярной библиотекой для работы с 2D и 3D графикой. Рассмотрение назначения, базовых компонент и правил инициализации программного движка DirectX.
презентация [19,4 K], добавлен 14.08.2013Программный код OpenGL. Синтаксис команд OpenGL. OpenGL как конечный автомат. Конвейер визуализации OpenGL. Библиотеки, относящиеся к OpenGL. Библиотека OpenGL. Подключаемые файлы. GLUT, инструментарий утилит библиотеки OpenGL.
курсовая работа [304,9 K], добавлен 01.06.2004Общие сведения о системе Компас 3D, предназначенной для графического ввода и редактирования чертежей на ПК. Ее основные функции, типы объектов, единицы измерения. Принципы работы в Компас-График LT. Пример создания файла трехмерной модели сборки детали.
курсовая работа [1,1 M], добавлен 03.11.2014Основы работы с графиков средствами OpenGL в C#. Ее спецификации, принципы и возможности. Direct3D как самостоятельная часть библиотеки Microsoft DirectX, которая отвечает за графику и вывод графической информации. Независимость от языка программирования.
курсовая работа [2,1 M], добавлен 17.02.2013Функциональные возможности библиотеки OpenGL. Разработка процедуры визуализации трехмерной сцены, интерфейса пользователя и подсистемы управления событиями с целью создания приложения для построения динамического изображения 3D-модели объекта "Самолет".
курсовая работа [1,7 M], добавлен 28.06.2011Назначение и стандарты реализации OpenGL для Windows, порядок подключения графической библиотеки. Основные функции и синтаксис команд. Рисование примитивов, видовые и аффинные преобразования. Моделирование двумерных графических объектов и анимации.
лабораторная работа [35,0 K], добавлен 04.07.2009Возможности интегрированного объектно-ориентированного пакета программ CorelDraw для работы с векторной графикой. Элементы графического интерфейса программы, панель задач, рабочие инструменты, специальные эффекты м приемы для работы с векторной графикой.
статья [528,6 K], добавлен 01.05.2010Определение понятия трехмерной компьютерной графики. Особенности создания 3D-объектов при помощи булевых операций, редактируемых поверхностей, на основе примитивов. Моделирование трехмерных объектов при помощи программного пакета Autodesk 3ds Max.
дипломная работа [4,2 M], добавлен 13.04.2014Точность чертежей и документации. Использование собственного математического ядра и параметрических технологий как ключевая особенность "Компас-3D". Основной инструментарий трехмерного моделирования. Моделирование деталей из листового материала.
реферат [16,4 K], добавлен 20.06.2013Исследование особенностей системного и прикладного программного обеспечения. Обзор языков программирования Pascal, Delphi и Assembler. Проектирование динамической трехмерной сцены в нестандартном графическом режиме. Составление математической модели.
курсовая работа [1,0 M], добавлен 17.02.2013Формулы поверхностей, матрицы основных и перспективных преобразований. Этапы проектирования трехмерной сцены в нестандартном графическом режиме 320х200 точек на 256 цветов. Блок-схема головной программы, процедуры отрисовки линии и поворота всей фигуры.
курсовая работа [565,5 K], добавлен 21.12.2012Суть программирования с использованием библиотеки OpenGL, его назначение, архитектура, преимущества и базовые возможности. Разработка приложения для построения динамического изображения трехмерной модели объекта "Компьютер", руководство пользователя.
курсовая работа [866,8 K], добавлен 22.06.2011Моделирование работы мастерской с использованием языка GPSS Wоrld. Определение основныx xарактеристик моделируемой системы: средней длины очереди неисправныx аппаратов; коэффициента загрузки мастеров. Описание машинной программы решения задачи.
курсовая работа [380,6 K], добавлен 28.06.2011Разработка трехмерной модели приложения "Гоночный автомобиль" на языке С++ с использованием библиотеки OpenGL и MFC, создание программы в среде Visual Studio 6.0. Информационное обеспечение, логическая структура и функциональная декомпозиция проекта.
курсовая работа [3,9 M], добавлен 29.06.2011Общие понятия о гироскопах, их классификация и применение. Механические гироскопы, свойства трехстепенного роторного гироскопа. Создание проекта "Гироскоп Фуко" средствами OpenGL и начальная настройка среды разработки. Инициализация объекта вывода и Glut.
курсовая работа [491,9 K], добавлен 18.11.2013Базовые приемы работы при создании трехмерной модели в пакете Компас. Абсолютная система координат, координатные плоскости. Управление изображением, цветом и свойствами поверхности объектов. Этапы процесса разработки трехмерной модели "Форма для льда".
курсовая работа [963,3 K], добавлен 11.06.2012Моделирование заданных команд, внутренних функциональных устройств и объектов ввода-вывода микроконтроллера. Разработка программа для демонстрации совместной работы микроконтроллера и моделируемого внешнего устройства. Компоненты архитектуры ATMega128.
курсовая работа [3,6 M], добавлен 12.06.2013