Опубликован: 13.07.2010 | Доступ: свободный | Студентов: 890 / 20 | Оценка: 4.40 / 4.20 | Длительность: 77:34:00
Тема: Программирование
Специальности: Программист, Архитектор программного обеспечения
Самостоятельная работа 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 реализации модели полого бруска в ортогональной проекции
-
Запустите
приложение, повращайте брусок и отметьте, что при ортогональной
проекции изделие кажется неестественным
-
Попытайтесь
разобраться с кодом!!!

