Китай |
Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 21:
Непрограммируемый конвейер в OpenGL
Упражнение 2. Модель полого бруска в ортогональной проекции (Ortho)
Для иллюстрации преобразований модели и проекции приведем два примера, которые не будем рассматривать подробно с точки зрения их исходного кода. Мы просто будем моделировать прямоугольный полый брусок. А те новые для нас возможности управления освещением и текстурой мы пока только используем без подробных комментариев. Для нас сейчас важно проиллюстрировать вышесказанное, как один и тот же объект отображается на экране при установленном ортогональном или перспективном отсекающем объеме видимости. Начнем с ортогонального отсекающего объема.
- Через панель Solution Explorer вызовите для корневого узла проекта контекстное меню и командой Add/New Item добавьте новый заголовочный файл с именем Ortho.h
- Дополните файл ProjectionMatrix.cpp следующими изменениями для подключения второго упражнения (выделены синим цветом)
//********************************************************** // Подключение стандартного файла с библиотекой OpenGL #include "stdafx.h" //********************************************************** // Прототипы функций void ExecuteMenu(int); // Контекстное меню первого уровня void TimerFunc(int); // Обработчик события таймера void SetupRC(void); // Начальные настройки OpenGL void SpecialKeys(int, int, int); // Обработка нажатия клавиш void RenderScene(void); void ChangeSize(int, int); // Глобальная переменная выбранного варианта основного меню int choice = 1; // Глобальные переменные для создания вращения // в градусах GLfloat xRot = 0.0f; GLfloat yRot = 0.0f; GLint w, h; // Ширина и высота экрана //********************************************************** // Подключение файлов с упражнениями #include "Atom.h" // Упражнение: "1) Простая модель атома" #include "Ortho.h" // Упражнение 2: "2) Брусок в ортогональной проекции" //********************************************************** // Функция обратного вызова обработки выбора пользователя void ExecuteMenu(int choice) { // Сбрасываем углы вращения прежнего варианта xRot = yRot = 0; // Запоминаем выбор в глобальную переменную ::choice = choice; switch(::choice) { case 1: ChangeSizeAtom(w, h); break; case 2: ChangeSizeOrtho(w, h); break; } // Вызвать принудительно визуализацию glutPostRedisplay(); } //********************************************************** // Функция обратного вызова для рисования сцены void RenderScene(void) { switch(::choice) { case 1: SetupLight(false); RenderSceneAtom(); break; case 2: SetupLight(true); RenderSceneOrtho(); break; } } //********************************************************** // Вызывается библиотекой GLUT при изменении размеров окна void ChangeSize(int width, int height) { w = width; h = height; switch(::choice) { case 1: ChangeSizeAtom(width, height); break; case 2: ChangeSizeOrtho(width, height); break; } } //********************************************************** // Обработчик события таймера void TimerFunc(int value) { glutPostRedisplay(); // Перерисовка сцены glutTimerFunc(100, TimerFunc, 1); // Заряжаем новый таймер } //********************************************************** // Устанавливается состояние инициализации void SetupRC(void) { glClearColor(0.0F, 0.0F, 0.0F, 1.0F);// Фон черный непрозрачный glEnable(GL_DEPTH_TEST); // Включили проверку глубины glFrontFace(GL_CCW); // Лицевыми будем считать те грани, вершины // которых обходятся против часовой стрелки glEnable(GL_CULL_FACE); // Включили режим отсечения сторон } //********************************************************** // Управление с клавиатуры стрелками // для задания новых значений матрицы поворота void SpecialKeys(int key, int x, int y) { if(key == GLUT_KEY_UP) // Стрелка вверх xRot -= 5.0f; if(key == GLUT_KEY_DOWN)// Стрелка вниз xRot += 5.0f; if(key == GLUT_KEY_LEFT)// Стрелка влево yRot -= 5.0f; if(key == GLUT_KEY_RIGHT)// Стрелка вправо yRot += 5.0f; xRot = (GLfloat)((const int)xRot % 360); yRot = (GLfloat)((const int)yRot % 360); // Вызвать принудительно визуализацию с помощью RenderScene() glutPostRedisplay(); } //********************************************************** void main(int argc, char* argv[]) { glutInit(&argc, argv); // Двойная буферизация, цветовая модель RGB, буфер глубины glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(300, 300); // Начальные размеры окна glutCreateWindow("Матричные преобразования"); // Заголовок окна glutDisplayFunc(RenderScene); // Обновление сцены при разрушении окна glutReshapeFunc(ChangeSize); // При изменении размера окна glutTimerFunc(100, TimerFunc, 1); // Создали таймер SetupRC(); glutSpecialFunc(SpecialKeys); // Для управления с клавиатуры // Создание меню и добавление опций выбора glutCreateMenu(ExecuteMenu); glutAddMenuEntry("1) Простая модель атома", 1); glutAddMenuEntry("2) Брусок в ортогональной проекции", 2); glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем // Конец создания меню glutMainLoop(); // Цикл сообщений графического окна }Листинг 21.12. Код файла ProjectionMatrix.cpp после добавления второго упражнения
- Заполните файл Ortho.h следующим кодом, реализующим второе упражнение
//********************************************************** // Прототипы void Ortho(); void RenderSceneOrtho(void); void ChangeSizeOrtho(int, int); // При изменении размеров окна void SetupLight(bool); // Устанавливаем источник света сцены //********************************************************** // Упражнение 2: "2) Брусок в ортогональной проекции" void Ortho() { float fZ,bZ; fZ = 100.0f; bZ = -100.0f; // Сбрасываем матрицу преобразования модели в значение единичной матрицы glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Поворачиваем сцену на угол, определяемый клавишами-стрелками glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); // Устанавливаем цвет рисования красный glColor3f(1.0f, 0.0f, 0.0f); glBegin(GL_QUADS); // Рисуем наружнюю сторону // Нормаль по оси Z glNormal3f(0.0f, 0.0f, 1.0f); // Левая грань glVertex3f(-50.0f, 50.0f, fZ); glVertex3f(-50.0f, -50.0f, fZ); glVertex3f(-35.0f, -50.0f, fZ); glVertex3f(-35.0f,50.0f,fZ); // Правая грань glVertex3f(50.0f, 50.0f, fZ); glVertex3f(35.0f, 50.0f, fZ); glVertex3f(35.0f, -50.0f, fZ); glVertex3f(50.0f,-50.0f,fZ); // Верхняя грань glVertex3f(-35.0f, 50.0f, fZ); glVertex3f(-35.0f, 35.0f, fZ); glVertex3f(35.0f, 35.0f, fZ); glVertex3f(35.0f, 50.0f,fZ); // Нижняя грань glVertex3f(-35.0f, -35.0f, fZ); glVertex3f(-35.0f, -50.0f, fZ); glVertex3f(35.0f, -50.0f, fZ); glVertex3f(35.0f, -35.0f,fZ); // Левая верхняя секция // Нормаль по оси Y glNormal3f(0.0f, 1.0f, 0.0f); glVertex3f(-50.0f, 50.0f, fZ); glVertex3f(50.0f, 50.0f, fZ); glVertex3f(50.0f, 50.0f, bZ); glVertex3f(-50.0f,50.0f,bZ); // Верхняя секция glNormal3f(0.0f, -1.0f, 0.0f); glVertex3f(-50.0f, -50.0f, fZ); glVertex3f(-50.0f, -50.0f, bZ); glVertex3f(50.0f, -50.0f, bZ); glVertex3f(50.0f, -50.0f, fZ); // Левая секция glNormal3f(1.0f, 0.0f, 0.0f); glVertex3f(50.0f, 50.0f, fZ); glVertex3f(50.0f, -50.0f, fZ); glVertex3f(50.0f, -50.0f, bZ); glVertex3f(50.0f, 50.0f, bZ); // Правая секция glNormal3f(-1.0f, 0.0f, 0.0f); glVertex3f(-50.0f, 50.0f, fZ); glVertex3f(-50.0f, 50.0f, bZ); glVertex3f(-50.0f, -50.0f, bZ); glVertex3f(-50.0f, -50.0f, fZ); glEnd(); glFrontFace(GL_CW); // Лицевыми будем считать те грани, вершины // которых обходятся по часовой стрелки // для рисования задней стенки glBegin(GL_QUADS); // Рисуем внутреннюю сторону // Нормаль по оси Z glNormal3f(0.0f, 0.0f, -1.0f); // Левая грань glVertex3f(-50.0f, 50.0f, bZ); glVertex3f(-50.0f, -50.0f, bZ); glVertex3f(-35.0f, -50.0f, bZ); glVertex3f(-35.0f,50.0f,bZ); // Правая грань glVertex3f(50.0f, 50.0f, bZ); glVertex3f(35.0f, 50.0f, bZ); glVertex3f(35.0f, -50.0f, bZ); glVertex3f(50.0f,-50.0f,bZ); // Верхняя грань glVertex3f(-35.0f, 50.0f, bZ); glVertex3f(-35.0f, 35.0f, bZ); glVertex3f(35.0f, 35.0f, bZ); glVertex3f(35.0f, 50.0f,bZ); // Нижняя грань glVertex3f(-35.0f, -35.0f, bZ); glVertex3f(-35.0f, -50.0f, bZ); glVertex3f(35.0f, -50.0f, bZ); glVertex3f(35.0f, -35.0f,bZ); // Внутренняя часть glColor3f(0.75f, 0.75f, 0.75f); // Серый // Нормаль по оси Y glNormal3f(0.0f, 1.0f, 0.0f); glVertex3f(-35.0f, 35.0f, fZ); glVertex3f(35.0f, 35.0f, fZ); glVertex3f(35.0f, 35.0f, bZ); glVertex3f(-35.0f,35.0f,bZ); // Нижняя секция glNormal3f(0.0f, 1.0f, 0.0f); glVertex3f(-35.0f, -35.0f, fZ); glVertex3f(-35.0f, -35.0f, bZ); glVertex3f(35.0f, -35.0f, bZ); glVertex3f(35.0f, -35.0f, fZ); // Левая секция glNormal3f(1.0f, 0.0f, 0.0f); glVertex3f(-35.0f, 35.0f, fZ); glVertex3f(-35.0f, 35.0f, bZ); glVertex3f(-35.0f, -35.0f, bZ); glVertex3f(-35.0f, -35.0f, fZ); // Правая секция glNormal3f(-1.0f, 0.0f, 0.0f); glVertex3f(35.0f, 35.0f, fZ); glVertex3f(35.0f, -35.0f, fZ); glVertex3f(35.0f, -35.0f, bZ); glVertex3f(35.0f, 35.0f, bZ); glEnd(); // Возвращаем обход сторон к значению по умолчанию glFrontFace(GL_CCW); // Переключаем буфер кадра glutSwapBuffers(); } //********************************************************** // Вызывается библиотекой GLUT при изменении размеров окна // для второго упражнения Ortho void ChangeSizeOrtho(int width, int height) { // Предотвращаем деление на нуль if(height == 0) height = 1; // Устанавливаем поле просмотра с размерами окна glViewport(0, 0, width, height); // Устанавливает матрицу преобразования в режим проецирования glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Устанавливаем размеры перспективы (отсекающего объема) // (left, right, bottom, top, near, far) GLfloat aspectRatio = (GLfloat)width / (GLfloat)height;// Для коррекции const GLfloat nRange = 120; // Размеры отсекающих плоскостей // Первоначально задали куб, теперь его корректируем // в зависимости от искажения графического окна if (width <= height) glOrtho (-nRange, nRange, -nRange / aspectRatio, nRange / aspectRatio, -nRange * 2.0f, nRange * 2.0f); else glOrtho (-nRange * aspectRatio, nRange * aspectRatio, -nRange, nRange, -nRange * 2.0f, nRange * 2.0f); // Восстановливает матрицу преобразования в исходный режим вида glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } //********************************************************** // Устанавливаем источник света сцены void SetupLight(bool flag) { if(!flag) { glDisable(GL_LIGHTING); return; } // Определяем характеристики источника света для сцены GLfloat whiteLight[] = { 0.45f, 0.45f, 0.45f, 1.0f }; GLfloat sourceLight[] = { 0.25f, 0.25f, 0.25f, 1.0f }; GLfloat lightPos[] = { -50.f, 25.0f, 250.0f, 0.0f }; // Включаем поддержку освещения glEnable(GL_LIGHTING); // Устанавливаем и включаем источник 0 glLightModelfv(GL_LIGHT_MODEL_AMBIENT,whiteLight); glLightfv(GL_LIGHT0,GL_AMBIENT,sourceLight); glLightfv(GL_LIGHT0,GL_DIFFUSE,sourceLight); glLightfv(GL_LIGHT0,GL_POSITION,lightPos); glEnable(GL_LIGHT0); // Включаем поддержку цвета материала glEnable(GL_COLOR_MATERIAL); // Устанавливаем свойства материала для отражаемого цвета glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); } //********************************************************** // Функция обратного вызова для рисования сцены // для второго упражнения Ortho void RenderSceneOrtho(void) { // Сбрасываем буферы цвета и глубины glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Рисуем сцену Ortho(); // Прокачка сообщений glFlush(); }Листинг 21.13. Код файла Ortho.h реализации модели полого бруска в ортогональной проекции
- Запустите приложение, повращайте брусок и отметьте, что при ортогональной проекции изделие кажется неестественным
- Попытайтесь разобраться с кодом!!!