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

Конвейерный принцип обработки графической информации позволяет
распределить однотипные операции на специализированных аппаратных
средствах помимо
В данной лабораторной работе мы познакомимся с процессом преобразования
графической информации, который реализован в библиотеке как непрограммируемый конвейер.
Выполните команду меню оболочки File/New/Project.
В появившемся
окне мастера создания заготовки проекта задайте имя проекта ProjectionMatrix и выберите
каталог размещения проекта, как показано на снимке
В следующем
окне оставьте установки мастера по умолчанию и щелкните на
кнопке Finish
Переименуйте
функцию _tmain() файла ProjectionMatrix.cpp в main(),
измените в заголовке main() тип
#include "stdafx.h"
void main()
{
}
Через
панель Solution Explorer оболочки откройте файл stdafx.h,
который создал мастер проекта, и добавьте в
самое его начало после инструкции #pragma
once код подключения стандартных OpenGL // stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include <iostream>
#include <tchar.h>
// TODO: reference additional headers your program requires here
В этой лабораторной работе мы опять выполним несколько упражнений,
которые упакуем в одно приложение. Соответственно, для вызова
каждого отдельного упражнения предусмотрим свой пункт контекстного
меню. Для взаимодействия с пользователем и рисования простых
геометрических объектов применим инструментальные средства
библиотеки GLUT. Код приложения будем постепенно наращивать
по мере выполнения упражнений рассматриваемой темы.
При моделировании компьютерной графики можно представить, что через экран монитора мы смотрим в окно на некоторый трехмерный мир, который существует внутри компьютера в виде некоторой сцены, движущимися актерами которой и взглядом на нее стороннего наблюдателя мы хотим управлять в нашем приложении. Сцена разворачивается в мировых ( базовых ) координатах, которые представляют собой правую систему координат и изначально направлены по отношению к наблюдателю так

При моделировании взгляда наблюдателя обычно его отождествляют
с фотокамерой и наделяют теми же характеристиками:
направление оптической оси на сцену, угол поворота относительно
оптической оси и ракурс видимости сцены. В исходном состоянии камера находится в начале мировых координат,
смотрит в отрицательную сторону оси z,
Управление объектами на сцене и камерой осуществляется с помощью
последовательных преобразований, реализуемых матрицами 4x4.
Конвейер преобразований в состоит из трех частей, которые
настраиваются по отдельности. Выбор требуемого режима осуществляется
командой glMatrixMode(GLenum mode),
которая с помощью значения перечисления mode определяет,
какую из матриц преобразования
размером 4x4 сделать текущей и
вносить в нее изменения последующими
командами:
В начальном состоянии по умолчанию любая из этих матриц преобразования размером 4x4 является единичной.
glLoadIdentity().m из 16 элементов, с помощью команды glLoadMatrix{fd}(const
TYPE *m).glLoadTransposeMatrix{fd}(const
TYPE *m) также загружает в текущую матрицу
преобразования желаемое значение, определяемое
массивом m из
16 элементов, только предварительно транспонирует этот массив.
Окончания f или d - для команд с аргументами типа float или double.glMultMatrix{fd}(const
TYPE *m). Результат умножения помещается
в текущую матрицу преобразования.
Окончания f или d - для команд
с аргументами типа float или double.glMultTratsposeMatrix{fd}(const
TYPE *m) также умножает текущую матрицу преобразования справа на
произвольную матрицу, определяемую массивом из 16 элементов,
только предварительно транспонирует этот массив. Результат
умножения помещается в текущую матрицу преобразования.
Окончания f или d - для команд
с аргументами типа float или double.Любой текущей матрицы преобразования можно передать значение с помощью указанных функций. Но весь вопрос в том, как правильно определить эти значения. При решении геометрических задач человеку всегда удобнее мыслить категориями элементарных последовательных преобразований (элементарных переходов), таких как плоскопараллельные смещения, повороты и изменения масштаба.
В мировой
glTranslate{fd}(TYPE
x, TYPE y, TYPE z).
Окончания f или d - для команд
с аргументами типа float или double. В
аналитических выкладках принято обозначать как матрицу T.glRotate{fd}(TYPE
angle ,TYPE
x,TYPE
y,TYPE
z).
Окончания f или d - для команд
с аргументами типа float или double. В
аналитических выкладках принято обозначать как матрицу R.glScale{fd}(TYPE
x, TYPE y, TYPE z).
Окончания f или d - для команд
с аргументами типа float или double. В
аналитических выкладках принято обозначать как матрицу S. Масштабирование
со значением больше +1.0 растягивает объект по соответствующей
оси, со значением меньше +1.0 - уменьшает объект. Значение
-1.0 приводит к зеркальному Все модельные преобразования применяются к объектам, заданным координатами вершин, последовательным домножением текущей матрицы справа на новую матрицу, определяющую нужное геометрическое преобразование. Последовательность применение тех или иных действий имеет значение. Например, при прочих равных условиях разные результаты дадут действия, выполненные в последовательности: переместить/повернуть и повернуть/переместить. Это и понятно, поскольку совершенно разными будут итоговые матрицы для таких действий:
M = M * T * R; M = M * R * T
Операции перемещения, вращения и масштабирования можно назвать элементарными преобразованиями, последовательно формирующими
итоговую матрицу преобразования M. Если вспомнить,
что итоговая матрица преобразования будет применена к каждой
вершине-v объекта, который будет умножаться
справа, то порядок фактических матричных преобразований модели
будет обратным порядку следования элементарных преобразований
в
В результате последовательности действий с текущей матрицей
проецирования мы определяем отсекающий
объем видимости, который
настраивает в следующих аспектах:
Для формирования матрицы проецирования нужно сделать ее текущей,
выполнив команду glMatrixMode(GL_PROJECTION).
Ортогональный отсекающий объем видимости устанавливается командой
glOrtho(left, right, bottom, top);
с аргументами типа GLdouble.
Для плоских
сцен, где отсекающий объем превращается в отсекающую
рамку видимости с координатой z=0,
можно применить упрощенный вариант команды из библиотеки GLU
gluOrtho2D(left, right, bottom, top, near, far);
с аргументами типа GLdouble.
Отсекающий объем видимости перспективной
glFrustum(left, right, bottom, top, near, far);
с аргументами типа GLdouble. Функция glFrustum() не
требует, чтобы отсекающий объем был симметричным. Значения
параметров near и far должны быть положительными.
Перспективный отсекающий объем можно задать и другой командой gluPerspective() из
библиотеки GLU, которая делает то же самое, что и glFrustum(),
но несколько иным способом.
gluPerspective(fovy, aspectratio, near, far);
с аргументами типа GLdouble fovy означает
угол ракурса; aspectratio - характеристическое
число, равное отношению ширины к высоте основания усеченной
Изначально созданные ортогональный или перспективный отсекающие
объемы видимости определяют наблюдателя, находящегося в начале
мировой 0z. Чтобы поставить наблюдателя перед сценой
или определить иной угол зрения, можно поступить двумя способами:
Способы равноценные и какой из них применить, решает программист. Но конечно, более привычным и простым является первый способ. Считается, что объект установлен в фиксированной точке, а наблюдатель "бегает" вокруг него в поисках подходящего ракурса. Ведь в музеях не экспозиции перемещаются относительно посетителей, а наоборот.
Для ориентации отсекающего объема видимости относительно системы мировых координат, т.е. назначения требуемого ракурса наблюдения, применяют функцию
gluLookAt(x1, y1, z1, x2, y2, z2, x3, y3, z3);
имеющую девять аргументов типа GLdouble.
Нужная точка обзора (положение глаза) описывается первой тройкой
аргументов. Вторая тройка аргументов определяет любую точку
на линии взгляда, но обычно координаты центра сцены. Третья
тройка определяет
По умолчанию камера располагается в начале системы мировых
координат, смотрит вниз по оси z, а положительное
направление оси y указывает
gluLookAt(0.0, 0.0, 0.0, 0.0, 0.0, -100.0, 0.0, 1.0, 0.0);
Значение z для линии взгляда равно -100.0, но может быть любым
отрицательным значением z, так как линия взгляда останется
такой же. Подобный вызов не имеет смысла, поскольку эти значения
приняты по умолчанию.
Для хранения промежуточных значений текущих матриц преобразования
в предусмотрен специальный механизм памяти, работающий
по схеме " первый пришел - первый ушел ". Применение стеков удобно
при формировании сложных объектов. Пусть, например, на сцене
нужно разместить автомобиль с четырьмя колесами. Вначале формируется
матрица размещения самого автомобиля, которая сохраняется в
стеке перед размещением колес. После размещения очередного
колеса текущая матрица модели восстанавливается в позицию
размещения автомобиля и продолжает модифицироваться для размещения
нового колеса. Применение стеков освобождает от необходимости
повторять все вычисления до точки разветвления процесса заново.

Глубина стека в реализации Microsoft равна:
Глубину соответствующего стека, поддерживаемого платформой, можно узнать командами:
glGet(GL_MAX_MODELVIEW_STACK_DEPTH);glGet(GL_MAX_PROJECTION_STACK_DEPTH); glGet(GL_MAX_TEXTURE_STACK_DEPTH); Управление стеком выполняется командами:
glPushMatrix(); -
запомнить промежуточное значение текущей матрицы преобразованияglPopMatrix(); -
восстановить значение текущей матрицы преобразованияЕсли глубина стека превышена, то система генерирует сообщение
об ошибке GL_STACK_OVERFLOW,
а при попытке извлечь матрицу из пустого стека генерируется
ошибка GL_STACK_UNDERFLOW.
В принципе, любую промежуточную матрицу можно скопировать
в отдельную переменную, не используя стек. Но тогда такая
операция будет реализована программно и будет выполняться центральным
процессором. Стековые операции по возможности реализуются аппаратно, а значит - с максимальным
быстродействием.
Используем рассмотренные преобразования для решения простейшей задачи - формирования модели атома. Разместим в файле ProjectionMatrix.cpp общую часть программы, а код каждого упражнения будем размещать в отдельном файле.
Заполните
файл 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) Простая модель атома"
//**********************************************************
// Функция обратного вызова обработки выбора пользователя
void ExecuteMenu(int choice)
{
// Сбрасываем углы вращения прежнего варианта
xRot = yRot = 0;
// Запоминаем выбор в глобальную переменную
::choice = choice;
switch(::choice)
{
case 1:
ChangeSizeAtom(w, h);
break;
}
// Вызвать принудительно визуализацию
glutPostRedisplay();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
// для первого упражнения Atom
void RenderScene(void)
{
switch(::choice)
{
case 1:
RenderSceneAtom();
break;
}
}
//**********************************************************
// Вызывается библиотекой GLUT при изменении размеров окна
// для первого упражнения Atom
void ChangeSize(int width, int height)
{
w = width;
h = height;
switch(::choice)
{
case 1:
ChangeSizeAtom(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);
glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем
// Конец создания меню
glutMainLoop(); // Цикл сообщений графического окна
}
Добавьте
к проекту новый Atom .h и
заполните его следующим кодом//**********************************************************
// Прототипы
void Atom();
void RenderSceneAtom(void);
void ChangeSizeAtom(int, int); // При изменении размеров окна
void ShowOrbit(GLfloat radius);
//**********************************************************
// Упражнение 1: "1) Простая модель атома"
void Atom()
{
// Угол поворота вокруг ядра
static GLfloat fElect = 0.0f;
GLfloat radius;
// Сбрасываем буфер цвета и глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Сбрасываем матрицу наблюдения модели в значение единичной матрицы
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Отодвигаем всю сцену назад по оси z
// чтобы видеть ее
glTranslatef(0.0f, 0.0f, -100.0f);
// Управление видом
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
// Красное ядро прямо по центру линии наблюдения
glColor3ub(255, 0, 0);
glutSolidSphere(10.0f, 15, 15);
// Задаем желтый цвет для всех электронов
glColor3ub(255,255,0);
// ПЕРВЫЙ ЭЛЕКТРОН
radius = 90.0f;
// Сохраняем исходное преобразование наблюдения в стеке матриц
glPushMatrix();
ShowOrbit(radius); // Рисуем орбиту
// Формируем точку центра первого электрона
// поворотом на угол относительно оси 0y
glRotatef(fElect, 0.0f, 1.0f, 0.0f);
// Сдвинули точку по оси 0x на radius единиц
glTranslatef(radius, 0.0f, 0.0f);
// Рисуем электрон
glutSolidSphere(6.0f, 15, 15);
// Восстанавливаем исходную матрицу преобразования наблюдения
glPopMatrix();
// ВТОРОЙ ЭЛЕКТРОН
radius = 70.0f;
glPushMatrix();
glRotatef(120.0f, 0.0f, 0.0f, 1.0f);
ShowOrbit(radius); // Рисуем орбиту
glRotatef(fElect + 90.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(-radius, 0.0f, 0.0f);
glutSolidSphere(6.0f, 15, 15);
glPopMatrix();
// ТРЕТИЙ ЭЛЕКТРОН
radius = 60.0f;
glPushMatrix();
glRotatef(-120.0f,0.0f, 0.0f, 1.0f);
ShowOrbit(radius); // Рисуем орбиту
glRotatef(fElect - 90.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, radius);
glutSolidSphere(6.0f, 15, 15);
glPopMatrix();
// Увеличиваем угол поворота
fElect += 10.0f;
fElect = fElect > 360.0f ? 0.0f : fElect;
// Переключаем буферы рисования
glutSwapBuffers();
}
//**********************************************************
#define GL_PI 3.1415f
#include <math.h> // Для тригонометрических функций
void ShowOrbit(GLfloat radius)
{
// Переменные орбиты
GLfloat x, y = 0.0f, z, angle;
glBegin(GL_LINE_LOOP);
for(angle = 0.0f; angle < 2.0f * GL_PI; angle += 0.1f)
{
x = radius * sin(angle);
z = radius * cos(angle);
glVertex3f(x, y, z);
}
glEnd();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
// для первого упражнения Atom
void RenderSceneAtom(void)
{
// Сбрасываем буфер цвета и буфер глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Рисуем сцену
Atom();
// Прокачка сообщений
glFlush();
}
//**********************************************************
// Вызывается библиотекой GLUT при изменении размеров окна
// для первого упражнения Atom
void ChangeSizeAtom(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 = 100; // Размеры отсекающих плоскостей
// Первоначально задали куб, теперь его корректируем
// в зависимости от искажения графического окна
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();
}
Разберитесь
с кодом, запустите упражнение, поуправляйте изображением
с помощью клавиш-стрелокНа
![]() |
![]() |
Для иллюстрации преобразований модели и
Через
панель Solution Explorer вызовите для корневого
узла проекта контекстное меню и командой Add/New
Item добавьте
новый
Дополните
файл 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(); // Цикл сообщений графического окна
}
Заполните
файл 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();
}
Запустите
приложение, повращайте брусок и отметьте, что при ортогональной
![]() |
![]() |
Попытайтесь
разобраться с кодом!!!Перейдем к перспективной
Через
панель Solution Explorer добавьте к проекту новый заголовочный
файл с именем Perspect.h
Наполните
этот файл следующим кодом, который будет определять перспективный
отсекающий объем видимости//**********************************************************
// Прототипы
void ChangeSizePerspect(int, int); // При изменении размеров окна
void Perspect();
void RenderScenePerspect(void);
//**********************************************************
// Упражнение 3: "3) Брусок в перспективной проекции"
void Perspect()
{
float fZ,bZ;
fZ = 100.0f;
bZ = -100.0f;
// Сбрасываем матрицу преобразования модели в значение единичной матрицы
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Отодвигаем всю сцену назад по оси z
// чтобы видеть ее
glTranslatef(0.0f, 0.0f, -300.0f);
// Поворачиваем сцену на угол, определяемый клавишами-стрелками
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();
}
//**********************************************************
void ChangeSizePerspect(int width, int height)
{
// Предотвращаем деление на нуль
if(height == 0)
height = 1;
// Устанавливаем поле просмотра с размерами окна
glViewport(0, 0, width, height);
// Устанавливаем размеры перспективы (отсекающего объема)
// (left, right, bottom, top, near, far)
GLfloat aspectRatio = (GLfloat)width / (GLfloat)height;// Для коррекции
// Устанавливает матрицу преобразования в режим проецирования
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Устанавливаем перспективную проекцию
gluPerspective(60.0f, aspectRatio, 0.5, 400.0);
// Восстановливает матрицу преобразования в исходный режим вида
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
void RenderScenePerspect(void)
{
// Сбрасываем буферы цвета и глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Рисуем сцену
Perspect();
// Прокачка сообщений
glFlush();
}
Скорректируйте
файл 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) Брусок в ортогональной проекции"
#include "Perspect.h" // Упражнение 3: "3) Брусок в перспективной проекции"
//**********************************************************
// Функция обратного вызова обработки выбора пользователя
void ExecuteMenu(int choice)
{
// Сбрасываем углы вращения прежнего варианта
xRot = yRot = 0;
// Запоминаем выбор в глобальную переменную
::choice = choice;
switch(::choice)
{
case 1:
ChangeSizeAtom(w, h);
break;
case 2:
ChangeSizeOrtho(w, h);
break;
case 3:
ChangeSizePerspect(w, h);
break;
}
// Вызвать принудительно визуализацию
glutPostRedisplay();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
void RenderScene(void)
{
switch(::choice)
{
case 1:
SetupLight(false);
RenderSceneAtom();
break;
case 2:
SetupLight(true);
RenderSceneOrtho();
break;
case 3:
SetupLight(true);
RenderScenePerspect();
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;
case 3:
ChangeSizePerspect(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);
glutAddMenuEntry("3) Брусок в перспективной проекции", 3);
glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем
// Конец создания меню
glutMainLoop(); // Цикл сообщений графического окна
}
Запустите
приложение, повращайте брусок и отметьте, что при перспективной
Ортогональная |
Ортогональная |
Перспективная |
Перспективная |
Попытайтесь
разобраться с кодом!!!Переделаем нашу модель атома, построенную в " Упражнении
1 ",
с использованием перспективной
Через
панель Solution Explorer добавьте к проекту новый заголовочный
файл с именем AtomPerspect.h
Скопируйте
в файл AtomPerspect.h содержимое
файла Atom.h и откорректируйте
его следующим образом//**********************************************************
// Прототипы
void AtomPerspect();
void RenderSceneAtomPerspect(void);
void ChangeSizeAtomPerspect(int, int); // При изменении размеров окна
void ShowOrbitPerspect(GLfloat radius);
//**********************************************************
// Упражнение 4: "4) Модель атома в перспективе"
void AtomPerspect()
{
// Угол поворота вокруг ядра
static GLfloat fElect = 0.0f;
GLfloat radius;
// Сбрасываем буфер цвета и глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Сбрасываем матрицу наблюдения модели в значение единичной матрицы
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Отодвигаем всю сцену назад по оси z
// чтобы видеть ее
glTranslatef(0.0f, 0.0f, -250.0f);
// Управление видом
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
// Красное ядро прямо по центру линии наблюдения
glColor3ub(255, 0, 0);
glutSolidSphere(10.0f, 15, 15);
// Задаем желтый цвет для всех электронов
glColor3ub(255,255,0);
// ПЕРВЫЙ ЭЛЕКТРОН
radius = 90.0f;
// Сохраняем исходное преобразование наблюдения в стеке матриц
glPushMatrix();
ShowOrbit(radius); // Рисуем орбиту
// Формируем точку центра первого электрона
// поворотом на угол относительно оси 0y
glRotatef(fElect, 0.0f, 1.0f, 0.0f);
// Сдвинули точку по оси 0x на radius единиц
glTranslatef(radius, 0.0f, 0.0f);
// Рисуем электрон
glutSolidSphere(6.0f, 15, 15);
// Восстанавливаем исходную матрицу преобразования наблюдения
glPopMatrix();
// ВТОРОЙ ЭЛЕКТРОН
radius = 70.0f;
glPushMatrix();
glRotatef(120.0f, 0.0f, 0.0f, 1.0f);
ShowOrbit(radius); // Рисуем орбиту
glRotatef(fElect + 90.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(-radius, 0.0f, 0.0f);
glutSolidSphere(6.0f, 15, 15);
glPopMatrix();
// ТРЕТИЙ ЭЛЕКТРОН
radius = 60.0f;
glPushMatrix();
glRotatef(-120.0f,0.0f, 0.0f, 1.0f);
ShowOrbit(radius); // Рисуем орбиту
glRotatef(fElect - 90.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, radius);
glutSolidSphere(6.0f, 15, 15);
glPopMatrix();
// Увеличиваем угол поворота
fElect += 10.0f;
fElect = fElect > 360.0f ? 0.0f : fElect;
// Переключаем буферы рисования
glutSwapBuffers();
}
//**********************************************************
#define GL_PI 3.1415f
#include <math.h> // Для тригонометрических функций
void ShowOrbitPerspect(GLfloat radius)
{
// Переменные орбиты
GLfloat x, y = 0.0f, z, angle;
glBegin(GL_LINE_LOOP);
for(angle = 0.0f; angle < 2.0f * GL_PI; angle += 0.1f)
{
x = radius * sin(angle);
z = radius * cos(angle);
glVertex3f(x, y, z);
}
glEnd();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
void RenderSceneAtomPerspect(void)
{
// Сбрасываем буфер цвета и буфер глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Рисуем сцену
AtomPerspect();
// Прокачка сообщений
glFlush();
}
//**********************************************************
// Вызывается библиотекой GLUT при изменении размеров окна
void ChangeSizeAtomPerspect(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;// Для коррекции
gluPerspective(45.0, aspectRatio, 1.0, 500.0);
// Восстановливает матрицу преобразования в исходный режим вида
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
Скорректируйте
файл 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) Брусок в ортогональной проекции"
#include "Perspect.h" // Упражнение 3: "3) Брусок в перспективной проекции"
#include "AtomPerspect.h" // Упражнение 4: "4) Модель атома в перспективе"
//**********************************************************
// Функция обратного вызова обработки выбора пользователя
void ExecuteMenu(int choice)
{
// Сбрасываем углы вращения прежнего варианта
xRot = yRot = 0;
// Запоминаем выбор в глобальную переменную
::choice = choice;
switch(::choice)
{
case 1:
ChangeSizeAtom(w, h);
break;
case 2:
ChangeSizeOrtho(w, h);
break;
case 3:
ChangeSizePerspect(w, h);
break;
case 4:
ChangeSizeAtomPerspect(w, h);
break;
}
// Вызвать принудительно визуализацию
glutPostRedisplay();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
void RenderScene(void)
{
switch(::choice)
{
case 1:
SetupLight(false);
RenderSceneAtom();
break;
case 2:
SetupLight(true);
RenderSceneOrtho();
break;
case 3:
SetupLight(true);
RenderScenePerspect();
break;
case 4:
SetupLight(false);
RenderSceneAtomPerspect();
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;
case 3:
ChangeSizePerspect(width, height);
break;
case 4:
ChangeSizeAtomPerspect(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);
glutAddMenuEntry("3) Брусок в перспективной проекции", 3);
glutAddMenuEntry("4) Модель атома в перспективе", 4);
glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем
// Конец создания меню
glutMainLoop(); // Цикл сообщений графического окна
}
Разберитесь
с кодом, запустите упражнение, поуправляйте изображением
с помощью клавиш-стрелок.На
![]() |
![]() |
Рассмотрим еще один пример, демонстрирующий взаимодействие
матрицы наблюдения модели и матрицы перспективной
В нашей модели Земля движется вокруг Солнца, а Луна - вокруг
Земли. Источник света находится в центре Солнца, которое нарисовано
без освещения, создавая иллюзию сияющего источника света. Пример
демонстрирует, насколько просто с помощью получать сложные
эффекты.
Добавьте
к приложению новый
Наполните
файл Solar.h следующим кодом//**********************************************************
// Прототипы
void Solar();
void SetupLightSolar(bool);
void ChangeSizeSolar(int, int);
void RenderSceneSolar(void);
void ShowOrbitSolar(GLfloat);
//**********************************************************
// Упражнение 5: "5) Система \"Солнце-Земля-Луна\""
void Solar()
{
GLfloat lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
// Начальные значения углов поворота Землм и Луны
static float fMoonRot = 0.0f; // Поворот Луны
static float fEarthRot = 0.0f;// Поворот Земли
GLfloat radius;
// Сбрасываем буфер цвета и глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Сохраняем матрицу модели перед выполнением поворотов
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// Отодвигаем всю сцену вниз оси z в поле зрения
// и рисуем Солнце
glTranslatef(0.0f, 0.0f, -300.0f);
glDisable(GL_LIGHTING);
glColor3ub(255, 255, 0); // Желтый
glutSolidSphere(15.0f, 30, 17); // Рисуем Солнце
glEnable(GL_LIGHTING);
// Поворачиваем сцену на угол, определяемый клавишами-стрелками
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
// Помещаем в точку Солнца источник света
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
// Поворачиваем систему координат, связанную с Солнцем
// и рисуем Землю
radius = 105.0f;
ShowOrbitSolar(radius); // Рисуем орбиту
glRotatef(fEarthRot, 0.0f, 1.0f, 0.0f);
glTranslatef(radius,0.0f,0.0f);
glColor3ub(0,0,255); // Синий
glutSolidSphere(15.0f, 30, 17);// Рисуем Землю
// Поворачиваем систему координат, связанную с Землей
// и рисуем Луну
radius = 30.0f;
ShowOrbitSolar(radius); // Рисуем орбиту
glRotatef(fMoonRot,0.0f, 1.0f, 0.0f);
glTranslatef(radius, 0.0f, 0.0f);
glColor3ub(200,200,200); // Серый
fMoonRot+= 15.0f;
fMoonRot = fMoonRot < 360.0f ? fMoonRot : 0.0;
glutSolidSphere(6.0f, 30, 17); // Рисуем Луну
// Восстанавливаем матрицу модели
glPopMatrix();
// Увеличиваем угол поворота на орбите Земли
fEarthRot += 5.0f;
fEarthRot = fEarthRot < 360.0f ? fEarthRot : 0.0;
// Переключить буфер и показать изображение
glutSwapBuffers();
}
//**********************************************************
// Устанавливаем источник света сцены
void SetupLightSolar(bool flag)
{
if(!flag)
{
glDisable(GL_LIGHTING);
return;
}
// Определяем характеристики источника света для сцены
GLfloat whiteLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
GLfloat sourceLight[] = { 0.8f, 0.8f, 0.8f, 1.0f };
GLfloat lightPos[] = { 0.0f, 0.0f, 0.0f, 1.0f };
// Включаем поддержку освещения
glEnable(GL_LIGHTING);
// Устанавливаем и включаем источник 0
glLightModelfv(GL_LIGHT_MODEL_AMBIENT,whiteLight);
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);
}
//**********************************************************
void ChangeSizeSolar(int width, int height)
{
// Предотвращаем деление на нуль
if(height == 0)
height = 1;
// Устанавливаем поле просмотра с размерами окна
glViewport(0, 0, width, height);
// Устанавливаем размеры перспективы (отсекающего объема)
// (left, right, bottom, top, near, far)
GLfloat aspectRatio = (GLfloat)width / (GLfloat)height;// Для коррекции
// Устанавливает матрицу преобразования в режим проецирования
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Устанавливаем перспективную проекцию
gluPerspective(45.0f, aspectRatio, 1.0, 425.0);
// Восстановливает матрицу преобразования в исходный режим вида
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
void RenderSceneSolar(void)
{
// Сбрасываем буферы цвета и глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Рисуем сцену
Solar();
// Прокачка сообщений
glFlush();
}
//**********************************************************
#define GL_PI 3.1415f
#include <math.h> // Для тригонометрических функций
void ShowOrbitSolar(GLfloat radius)
{
// Переменные орбиты
GLfloat x, y = 0.0f, z, angle;
glColor3ub(255, 255, 0); // Желтый
glBegin(GL_LINE_LOOP);
for(angle = 0.0f; angle < 2.0f * GL_PI; angle += 0.1f)
{
x = radius * sin(angle);
z = radius * cos(angle);
glVertex3f(x, y, z);
}
glEnd();
}
Скорректируйте
файл 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) Брусок в ортогональной проекции"
#include "Perspect.h" // Упражнение 3: "3) Брусок в перспективной проекции"
#include "AtomPerspect.h" // Упражнение 4: "4) Модель атома в перспективе"
#include "Solar.h" // Упражнение 5: "5) Система \"Солнце-Земля-Луна\""
//**********************************************************
// Функция обратного вызова обработки выбора пользователя
void ExecuteMenu(int choice)
{
// Сбрасываем углы вращения прежнего варианта
xRot = yRot = 0;
// Запоминаем выбор в глобальную переменную
::choice = choice;
switch(::choice)
{
case 1:
ChangeSizeAtom(w, h);
break;
case 2:
ChangeSizeOrtho(w, h);
break;
case 3:
ChangeSizePerspect(w, h);
break;
case 4:
ChangeSizeAtomPerspect(w, h);
break;
case 5:
ChangeSizeSolar(w, h);
break;
}
// Вызвать принудительно визуализацию
glutPostRedisplay();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
void RenderScene(void)
{
switch(::choice)
{
case 1:
SetupLight(false);
RenderSceneAtom();
break;
case 2:
SetupLight(true);
RenderSceneOrtho();
break;
case 3:
SetupLight(true);
RenderScenePerspect();
break;
case 4:
SetupLight(false);
RenderSceneAtomPerspect();
break;
case 5:
SetupLightSolar(true);
RenderSceneSolar();
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;
case 3:
ChangeSizePerspect(width, height);
break;
case 4:
ChangeSizeAtomPerspect(width, height);
break;
case 5:
ChangeSizeSolar(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);
glutAddMenuEntry("3) Брусок в перспективной проекции", 3);
glutAddMenuEntry("4) Модель атома в перспективе", 4);
glutAddMenuEntry("5) Система \"Солнце-Земля-Луна\"", 5);
glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем
// Конец создания меню
glutMainLoop(); // Цикл сообщений графического окна
}
Разберитесь
с кодом, запустите упражнение, поуправляйте изображением
с помощью клавиш-стрелокНа
![]() |
![]() |
В начале этой работы мы упоминали возможность прямой загрузки значений в текущие матрицы преобразования командами:
glLoadIdentity()glLoadMatrix{fd}(const
TYPE *m)glLoadTransposeMatrix{fd}(const
TYPE *m)В данном упражнении мы применим эти возможности
для моделирования вращающегося тора.
Мы сами будем предварительно вычислять матрицу преобразования M размером 4x4, и применять команду загрузки glLoadMatrix(),
передавая в качестве аргумента указатель на M. В программном
представлении матрица M должна быть одномерным массивом m,
элементы которого следуют в порядке расположения столбцов.
Это связано с тем, что двумерные массивы в языке C, C++ располагаются
в памяти в порядке следования строк. рассматривает последовательность расположенных в памяти 16 элементов как следующие друг за другом 4 столбца матрицы M.
Это значит, что имея математическое представление матрицы
преобразования M для правильной ее загрузки
командой glLoadMatrix() мы
должны массив m сформировать в порядке следования
столбцов матрицы M.
Другой способ - загружать матрицу M с помощью
команды glLoadTransposeMatrix() как

Добавьте
к приложению новый
Наполните
файл Transform.h следующим кодом//**********************************************************
// Упражнение 6: "6) Каркасный тор - своя матрица"
#include <math.h>
#define GLT_PI 3.14159265358979323846
#define GLT_PI_DIV_180 0.017453292519943296
typedef GLfloat GLTVector3[3]; // Вещественная точка
typedef GLfloat GLTMatrix[16];
//**********************************************************
// Прототипы
void DrawTorus(void);
void RenderSceneTransform(void);
void ChangeSizeTransform(int, int);
void RotationMatrix(float, float, float, float, GLTMatrix);
void LoadIdentityMatrix(GLTMatrix);
void TransformPoint(const GLTVector3, const GLTMatrix, GLTVector3);
//**********************************************************
void DrawTorus(void)
{
GLTMatrix mTransform; // Объявление матрицы поворота
static GLfloat yRot = 0.0f; // Угол поворота для анимации в градусах
// Строим матрицу преобразования
// Угол преобразуем в радианы
RotationMatrix(GLT_PI_DIV_180 * yRot, 0.0f, 1.0f, 0.0f, mTransform);
mTransform[12] = 0.0f;
mTransform[13] = 0.0f;
mTransform[14] = -2.5f;
GLfloat majorRadius = 0.35f;
GLfloat minorRadius = 0.15f;
GLint numMajor = 40;
GLint numMinor = 20;
GLTVector3 objectVertex; // Вершины в исходном состоянии
GLTVector3 transformedVertex; // Преобразованные вершины
double majorStep = 2.0f * GLT_PI / numMajor;
double minorStep = 2.0f * GLT_PI / numMinor;
int i, j;
for (i=0; i<numMajor; ++i)
{
double a0 = i * majorStep;
double a1 = a0 + majorStep;
GLfloat x0 = (GLfloat) cos(a0);
GLfloat y0 = (GLfloat) sin(a0);
GLfloat x1 = (GLfloat) cos(a1);
GLfloat y1 = (GLfloat) sin(a1);
glBegin(GL_TRIANGLE_STRIP);
for (j=0; j<=numMinor; ++j)
{
double b = j * minorStep;
GLfloat c = (GLfloat) cos(b);
GLfloat r = minorRadius * c + majorRadius;
GLfloat z = minorRadius * (GLfloat) sin(b);
// Первая точка
objectVertex[0] = x0 * r;
objectVertex[1] = y0 * r;
objectVertex[2] = z;
TransformPoint(objectVertex, mTransform, transformedVertex);
glVertex3fv(transformedVertex);
// Вторая точка
objectVertex[0] = x1 * r;
objectVertex[1] = y1 * r;
objectVertex[2] = z;
TransformPoint(objectVertex, mTransform, transformedVertex);
glVertex3fv(transformedVertex);
}
glEnd();
}
// Наращиваем анимацию
yRot += 1.5f;
// Переключаем буферы
glutSwapBuffers();
}
//**********************************************************
void RenderSceneTransform(void)
{
// Сохраняем атрибуты в стеке атрибутов!!!
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_POLYGON_BIT);
// Устанавливаем белый цвет и голубой фон
glColor3ub(255, 255, 255); // Белый
glClearColor(0.0f, 0.0f, .50f, 1.0f );
// Сбрасываем буферы цвета и глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Рисовать в каркасном режиме
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
DrawTorus();
// Восстанавливаем атрибуты из стека атрибутов!!!
glPopAttrib();
// Прокачка сообщений
glFlush();
}
//**********************************************************
void ChangeSizeTransform(int width, int height)
{
// Предотвращаем деление на нуль
if(height == 0)
height = 1;
// Устанавливаем поле просмотра с размерами окна
glViewport(0, 0, width, height);
// Характеристическое число для соблюдения пропорций
GLfloat aspectRatio = (GLfloat)width / (GLfloat)height;// Для коррекции
// Устанавливает матрицу преобразования в режим проецирования
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Устанавливаем перспективную проекцию
gluPerspective(35.0f, aspectRatio, 1.0f, 50.0f);
// Восстановливает матрицу преобразования в исходный режим вида
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
//**********************************************************
// Создание матрицы поворота 4x4
void RotationMatrix(float angle, float x, float y, float z, GLTMatrix mMatrix)
{
float vecLength, sinSave, cosSave, oneMinusCos;
float xx, yy, zz, xy, yz, zx, xs, ys, zs;
if(x == 0.0f y == 0.0f z == 0.0f)
{
LoadIdentityMatrix(mMatrix);
return;
}
// Нормализуем вектор
vecLength = (float)sqrt( x*x + y*y + z*z );
x /= vecLength;
y /= vecLength;
z /= vecLength;
sinSave = (float)sin(angle);
cosSave = (float)cos(angle);
oneMinusCos = 1.0f - cosSave;
xx = x * x;
yy = y * y;
zz = z * z;
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * sinSave;
ys = y * sinSave;
zs = z * sinSave;
mMatrix[0] = (oneMinusCos * xx) + cosSave;
mMatrix[4] = (oneMinusCos * xy) - zs;
mMatrix[8] = (oneMinusCos * zx) + ys;
mMatrix[12] = 0.0f;
mMatrix[1] = (oneMinusCos * xy) + zs;
mMatrix[5] = (oneMinusCos * yy) + cosSave;
mMatrix[9] = (oneMinusCos * yz) - xs;
mMatrix[13] = 0.0f;
mMatrix[2] = (oneMinusCos * zx) - ys;
mMatrix[6] = (oneMinusCos * yz) + xs;
mMatrix[10] = (oneMinusCos * zz) + cosSave;
mMatrix[14] = 0.0f;
mMatrix[3] = 0.0f;
mMatrix[7] = 0.0f;
mMatrix[11] = 0.0f;
mMatrix[15] = 1.0f;
}
//**********************************************************
// Загрузка матрицы как единичной
void LoadIdentityMatrix(GLTMatrix m)
{
static GLTMatrix identity = { 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
memcpy(m, identity, sizeof(GLTMatrix));
}
//**********************************************************
void TransformPoint(const GLTVector3 vSrcVector, const GLTMatrix mMatrix, GLTVector3 vOut)
{
vOut[0] = mMatrix[0] * vSrcVector[0] + mMatrix[4] * vSrcVector[1] + mMatrix[8] * vSrcVector[2] + mMatrix[12];
vOut[1] = mMatrix[1] * vSrcVector[0] + mMatrix[5] * vSrcVector[1] + mMatrix[9] * vSrcVector[2] + mMatrix[13];
vOut[2] = mMatrix[2] * vSrcVector[0] + mMatrix[6] * vSrcVector[1] + mMatrix[10] * vSrcVector[2] + mMatrix[14];
}
Скорректируйте
файл 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) Брусок в ортогональной проекции"
#include "Perspect.h" // Упражнение 3: "3) Брусок в перспективной проекции"
#include "AtomPerspect.h" // Упражнение 4: "4) Модель атома в перспективе"
#include "Solar.h" // Упражнение 5: "5) Система \"Солнце-Земля-Луна\""
#include "Transform.h" // Упражнение 6: "6) Каркасный тор - своя матрица"
//**********************************************************
// Функция обратного вызова обработки выбора пользователя
void ExecuteMenu(int choice)
{
// Сбрасываем углы вращения прежнего варианта
xRot = yRot = 0;
// Запоминаем выбор в глобальную переменную
::choice = choice;
switch(::choice)
{
case 1:
ChangeSizeAtom(w, h);
break;
case 2:
ChangeSizeOrtho(w, h);
break;
case 3:
ChangeSizePerspect(w, h);
break;
case 4:
ChangeSizeAtomPerspect(w, h);
break;
case 5:
ChangeSizeSolar(w, h);
break;
case 6:
ChangeSizeTransform(w, h);
break;
}
// Вызвать принудительно визуализацию
glutPostRedisplay();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
void RenderScene(void)
{
switch(::choice)
{
case 1:
SetupLight(false);
RenderSceneAtom();
break;
case 2:
SetupLight(true);
RenderSceneOrtho();
break;
case 3:
SetupLight(true);
RenderScenePerspect();
break;
case 4:
SetupLight(false);
RenderSceneAtomPerspect();
break;
case 5:
SetupLightSolar(true);
RenderSceneSolar();
break;
case 6:
SetupLight(false);
RenderSceneTransform();
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;
case 3:
ChangeSizePerspect(width, height);
break;
case 4:
ChangeSizeAtomPerspect(width, height);
break;
case 5:
ChangeSizeSolar(width, height);
break;
case 6:
ChangeSizeTransform(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);
glutAddMenuEntry("3) Брусок в перспективной проекции", 3);
glutAddMenuEntry("4) Модель атома в перспективе", 4);
glutAddMenuEntry("5) Система \"Солнце-Земля-Луна\"", 5);
glutAddMenuEntry("6) Каркасный тор - своя матрица", 6);
glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем
// Конец создания меню
glutMainLoop(); // Цикл сообщений графического окна
}
Разберитесь
с кодом, запустите упражнениеНа 0y тора могут быть
такими
![]() |
![]() |
В качестве еще одного примера, использующего прямую загрузку матриц преобразований, рассмотрим модель некоторого фантастического мира, населенного сферами, которые располагаются в случайных местах.
Добавьте
к приложению новый
Наполните
файл SphereWorld.h следующим кодом//**********************************************************
// Упражнение 7: "7) Фантастический мир со сферами"
#include <math.h>
#define GLT_PI 3.14159265358979323846
#define GLT_PI_DIV_180 0.017453292519943296
#define gltDegToRad(x) ((x)*GLT_PI_DIV_180)
#define NUM_SPHERES 50 // Количество сфер
typedef GLfloat GLTVector3[3]; // Вектор
typedef GLfloat GLTMatrix[16]; // Матрица 4x4
typedef struct{ // Фрейм 3x3
GLTVector3 vLocation;
GLTVector3 vUp;
GLTVector3 vForward;
} GLTFrame;
GLTFrame spheres[NUM_SPHERES];
GLTFrame frameCamera;
//**********************************************************
// Прототипы
void SphereWorld();
void DrawGround();
void RenderSceneSphereWorld();
void ChangeSizeSphereWorld(int, int);
void SpecialKeysSphereWorld(int);
void SetupSphereWorld();
void gltApplyCameraTransform(GLTFrame *);
void gltApplyActorTransform(GLTFrame *);
void gltGetMatrixFromFrame(GLTFrame *, GLTMatrix);
void gltDrawTorus(GLfloat, GLfloat, GLint, GLint);
void gltNormalizeVector(GLTVector3);
void gltScaleVector(GLTVector3, const GLfloat);
GLfloat gltGetVectorLength(const GLTVector3);
GLfloat gltGetVectorLengthSqrd(const GLTVector3);
void gltInitFrame(GLTFrame *);
void gltMoveFrameForward(GLTFrame *, GLfloat);
void gltRotateFrameLocalY(GLTFrame *, GLfloat);
void gltRotationMatrix(float, float, float, float, GLTMatrix);
void gltRotateVector(const GLTVector3, const GLTMatrix, GLTVector3);
void gltVectorCrossProduct(const GLTVector3, const GLTVector3, GLTVector3);
void gltLoadIdentityMatrix(GLTMatrix);
//**********************************************************
// Формировать сцену
void SphereWorld(void)
{
static GLfloat yRot = 0.0f; // Угол поворота для анимации в градусах
glPushMatrix();
gltApplyCameraTransform(frameCamera);
// Рисуем сетку
DrawGround();
// Рисовать сферы по ранее сгенерированным случайным координатам
for(int i = 0; i < NUM_SPHERES; i++)
{
glPushMatrix();
gltApplyActorTransformspheres[i]);
glutSolidSphere(0.1f, 13, 26);
glPopMatrix();
}
glPushMatrix();
glTranslatef(0.0f, 0.0f, -2.5f);
glPushMatrix();
glRotatef(-yRot * 2.0f, 0.0f, 1.0f, 0.0f);
glTranslatef(1.0f, 0.0f, 0.0f);
glutSolidSphere(0.1f, 13, 26);
glPopMatrix();
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
gltDrawTorus(0.35, 0.15, 40, 20);
glPopMatrix();
glPopMatrix();
// Наращиваем анимацию
yRot += 0.5f;
// Переключаем буферы
glutSwapBuffers();
}
//**********************************************************
// Рисовать сетку основания
void DrawGround(void)
{
GLfloat fExtent = 20.0f;
GLfloat fStep = 1.0f;
GLfloat y = -0.4f;
GLint iLine;
glBegin(GL_LINES);
for(iLine = -fExtent; iLine <= fExtent; iLine += fStep)
{
glVertex3f(iLine, y, fExtent); // Рисовать Z-линии
glVertex3f(iLine, y, -fExtent);
glVertex3f(fExtent, y, iLine);
glVertex3f(-fExtent, y, iLine);
}
glEnd();
}
//**********************************************************
// Рендеринг
void RenderSceneSphereWorld()
{
// Сохраняем атрибуты в стеке атрибутов!!!
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_POLYGON_BIT);
// Устанавливаем белый цвет и голубой фон
glColor3ub(255, 255, 255); // Белый
glClearColor(0.0f, 0.0f, .50f, 1.0f );
// Сбрасываем буферы цвета и глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Рисовать с двух сторон в каркасном режиме
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
SphereWorld(); // Рисуем сцену
// Восстанавливаем атрибуты из стека атрибутов!!!
glPopAttrib();
// Прокачка сообщений
glFlush();
}
//**********************************************************
void ChangeSizeSphereWorld(int width, int height)
{
// Предотвращаем деление на нуль
if(height == 0)
height = 1;
// Устанавливаем поле просмотра с размерами окна
glViewport(0, 0, width, height);
// Характеристическое число для соблюдения пропорций
GLfloat aspectRatio = (GLfloat)width / (GLfloat)height;// Для коррекции
// Устанавливает матрицу преобразования в режим проецирования
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Устанавливаем перспективную проекцию
gluPerspective(35.0f, aspectRatio, 1.0f, 50.0f);
// Восстановливает матрицу преобразования в исходный режим вида
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
//**********************************************************
// Управление фреймом камеры
void SpecialKeysSphereWorld(int key)
{
if(key == GLUT_KEY_UP)
gltMoveFrameForward(frameCamera, 0.1f);
if(key == GLUT_KEY_DOWN)
gltMoveFrameForward(frameCamera, -0.1f);
if(key == GLUT_KEY_LEFT)
gltRotateFrameLocalY(frameCamera, 0.1);
if(key == GLUT_KEY_RIGHT)
gltRotateFrameLocalY(frameCamera, -0.1);
}
//**********************************************************
// Формируем матрицу проекции
void gltApplyCameraTransform(GLTFrame *pCamera)
{
GLTMatrix mMatrix;
GLTVector3 vAxisX;
GLTVector3 zFlipped;
zFlipped[0] = -pCamera->vForward[0];
zFlipped[1] = -pCamera->vForward[1];
zFlipped[2] = -pCamera->vForward[2];
// Получим вектор X
gltVectorCrossProduct(pCamera->vUp, zFlipped, vAxisX);
// Формируем матрицу поворота и транспонируем ее
mMatrix[0] = vAxisX[0];
mMatrix[4] = vAxisX[1];
mMatrix[8] = vAxisX[2];
mMatrix[12] = 0.0f;
mMatrix[1] = pCamera->vUp[0];
mMatrix[5] = pCamera->vUp[1];
mMatrix[9] = pCamera->vUp[2];
mMatrix[13] = 0.0f;
mMatrix[2] = zFlipped[0];
mMatrix[6] = zFlipped[1];
mMatrix[10] = zFlipped[2];
mMatrix[14] = 0.0f;
mMatrix[3] = 0.0f;
mMatrix[7] = 0.0f;
mMatrix[11] = 0.0f;
mMatrix[15] = 1.0f;
// Выполним поворот
glMultMatrixf(mMatrix);
// Теперь отодвигаемся назад
glTranslatef(-pCamera->vLocation[0], -pCamera->vLocation[1], -pCamera->vLocation[2]);
}
//**********************************************************
void gltApplyActorTransform(GLTFrame *pFrame)
{
GLTMatrix mTransform;
gltGetMatrixFromFrame(pFrame, mTransform);
glMultMatrixf(mTransform);
}
//**********************************************************
void gltGetMatrixFromFrame(GLTFrame *pFrame, GLTMatrix mMatrix)
{
GLTVector3 vXAxis;
gltVectorCrossProduct(pFrame->vUp, pFrame->vForward, vXAxis);
memcpy(mMatrix, vXAxis, sizeof(GLTVector3));
mMatrix[3] = 0.0f;
memcpy(mMatrix+4, pFrame->vUp, sizeof(GLTVector3));
mMatrix[7] = 0.0f;
memcpy(mMatrix+8, pFrame->vForward, sizeof(GLTVector3));
mMatrix[11] = 0.0f;
memcpy(mMatrix+12, pFrame->vLocation, sizeof(GLTVector3));
mMatrix[15] = 1.0f;
}
//**********************************************************
void gltDrawTorus(GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor)
{
GLTVector3 vNormal;
double majorStep = 2.0f*GLT_PI / numMajor;
double minorStep = 2.0f*GLT_PI / numMinor;
for (int i=0; i<numMajor; ++i)
{
double a0 = i * majorStep;
double a1 = a0 + majorStep;
GLfloat x0 = (GLfloat) cos(a0);
GLfloat y0 = (GLfloat) sin(a0);
GLfloat x1 = (GLfloat) cos(a1);
GLfloat y1 = (GLfloat) sin(a1);
glBegin(GL_TRIANGLE_STRIP);
for (int j=0; j<=numMinor; ++j)
{
double b = j * minorStep;
GLfloat c = (GLfloat) cos(b);
GLfloat r = minorRadius * c + majorRadius;
GLfloat z = minorRadius * (GLfloat) sin(b);
glTexCoord2f((float)(i)/(float)(numMajor), (float)(j)/(float)(numMinor));
vNormal[0] = x0*c;
vNormal[1] = y0*c;
vNormal[2] = z/minorRadius;
gltNormalizeVector(vNormal);
glNormal3fv(vNormal);
glVertex3f(x0*r, y0*r, z);
glTexCoord2f((float)(i+1)/(float)(numMajor), (float)(j)/(float)(numMinor));
vNormal[0] = x1*c;
vNormal[1] = y1*c;
vNormal[2] = z/minorRadius;
glNormal3fv(vNormal);
glVertex3f(x1*r, y1*r, z);
}
glEnd();
}
}
//**********************************************************
void gltNormalizeVector(GLTVector3 vNormal)
{
GLfloat fLength = 1.0f / gltGetVectorLength(vNormal);
gltScaleVector(vNormal, fLength);
}
//**********************************************************
void gltScaleVector(GLTVector3 vVector, const GLfloat fScale)
{
vVector[0] *= fScale; vVector[1] *= fScale; vVector[2] *= fScale;
}
//**********************************************************
GLfloat gltGetVectorLength(const GLTVector3 vVector)
{
return (GLfloat)sqrt(gltGetVectorLengthSqrd(vVector));
}
//**********************************************************
GLfloat gltGetVectorLengthSqrd(const GLTVector3 vVector)
{
return (vVector[0]*vVector[0]) + (vVector[1]*vVector[1]) + (vVector[2]*vVector[2]);
}
//**********************************************************
void gltInitFrame(GLTFrame *pFrame)
{
pFrame->vLocation[0] = 0.0f;
pFrame->vLocation[1] = 0.0f;
pFrame->vLocation[2] = 0.0f;
pFrame->vUp[0] = 0.0f;
pFrame->vUp[1] = 1.0f;
pFrame->vUp[2] = 0.0f;
pFrame->vForward[0] = 0.0f;
pFrame->vForward[1] = 0.0f;
pFrame->vForward[2] = -1.0f;
}
//**********************************************************
void gltMoveFrameForward(GLTFrame *pFrame, GLfloat fStep)
{
pFrame->vLocation[0] += pFrame->vForward[0] * fStep;
pFrame->vLocation[1] += pFrame->vForward[1] * fStep;
pFrame->vLocation[2] += pFrame->vForward[2] * fStep;
}
//**********************************************************
void gltRotateFrameLocalY(GLTFrame *pFrame, GLfloat fAngle)
{
GLTMatrix mRotation;
GLTVector3 vNewForward;
gltRotationMatrix((float)gltDegToRad(fAngle), 0.0f, 1.0f, 0.0f, mRotation);
gltRotationMatrix(fAngle, pFrame->vUp[0], pFrame->vUp[1], pFrame->vUp[2], mRotation);
gltRotateVector(pFrame->vForward, mRotation, vNewForward);
memcpy(pFrame->vForward, vNewForward, sizeof(GLTVector3));
}
//**********************************************************
// Создание матрицы поворота 4x4
void gltRotationMatrix(float angle, float x, float y, float z, GLTMatrix mMatrix)
{
float vecLength, sinSave, cosSave, oneMinusCos;
float xx, yy, zz, xy, yz, zx, xs, ys, zs;
if(x == 0.0f y == 0.0f z == 0.0f)
{
gltLoadIdentityMatrix(mMatrix);
return;
}
// Нормализуем вектор
vecLength = (float)sqrt( x*x + y*y + z*z );
x /= vecLength;
y /= vecLength;
z /= vecLength;
sinSave = (float)sin(angle);
cosSave = (float)cos(angle);
oneMinusCos = 1.0f - cosSave;
xx = x * x;
yy = y * y;
zz = z * z;
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * sinSave;
ys = y * sinSave;
zs = z * sinSave;
mMatrix[0] = (oneMinusCos * xx) + cosSave;
mMatrix[4] = (oneMinusCos * xy) - zs;
mMatrix[8] = (oneMinusCos * zx) + ys;
mMatrix[12] = 0.0f;
mMatrix[1] = (oneMinusCos * xy) + zs;
mMatrix[5] = (oneMinusCos * yy) + cosSave;
mMatrix[9] = (oneMinusCos * yz) - xs;
mMatrix[13] = 0.0f;
mMatrix[2] = (oneMinusCos * zx) - ys;
mMatrix[6] = (oneMinusCos * yz) + xs;
mMatrix[10] = (oneMinusCos * zz) + cosSave;
mMatrix[14] = 0.0f;
mMatrix[3] = 0.0f;
mMatrix[7] = 0.0f;
mMatrix[11] = 0.0f;
mMatrix[15] = 1.0f;
}
//**********************************************************
void gltRotateVector(const GLTVector3 vSrcVector, const GLTMatrix mMatrix, GLTVector3 vOut)
{
vOut[0] = mMatrix[0] * vSrcVector[0] + mMatrix[4] * vSrcVector[1] + mMatrix[8] * vSrcVector[2];
vOut[1] = mMatrix[1] * vSrcVector[0] + mMatrix[5] * vSrcVector[1] + mMatrix[9] * vSrcVector[2];
vOut[2] = mMatrix[2] * vSrcVector[0] + mMatrix[6] * vSrcVector[1] + mMatrix[10] * vSrcVector[2];
}
//**********************************************************
void gltVectorCrossProduct(const GLTVector3 vU, const GLTVector3 vV, GLTVector3 vResult)
{
vResult[0] = vU[1]*vV[2] - vV[1]*vU[2];
vResult[1] = -vU[0]*vV[2] + vV[0]*vU[2];
vResult[2] = vU[0]*vV[1] - vV[0]*vU[1];
}
//**********************************************************
// Загрузка матрицы как единичной
void gltLoadIdentityMatrix(GLTMatrix m)
{
static GLTMatrix identity = { 1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
memcpy(m, identity, sizeof(GLTMatrix));
}
//**********************************************************
// Устанавливается состояние инициализации
void SetupSphereWorld(void)
{
gltInitFrame(frameCamera); // Инициализируем камеру
// Генерируем центры 50 сфер случайным образом
// в плоскости x0z внутри рамки от -20 до 20
for(int iSphere = 0; iSphere < NUM_SPHERES; iSphere++)
{
gltInitFramespheres[iSphere]); // Инициализируем фрейм
// На плоскости x0z размещаем случайно центры
// сфер в диапазоне от -20 до 20 с шагом .1
spheres[iSphere].vLocation[0] = (float)((rand() % 400) - 200) * 0.1f;
spheres[iSphere].vLocation[1] = 0.0f;
spheres[iSphere].vLocation[2] = (float)((rand() % 400) - 200) * 0.1f;
}
}
Скорректируйте
файл 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: "1) Простая модель атома"
#include "Ortho.h" // Упражнение 2: "2) Брусок в ортогональной проекции"
#include "Perspect.h" // Упражнение 3: "3) Брусок в перспективной проекции"
#include "AtomPerspect.h" // Упражнение 4: "4) Модель атома в перспективе"
#include "Solar.h" // Упражнение 5: "5) Система \"Солнце-Земля-Луна\""
#include "Transform.h" // Упражнение 6: "6) Каркасный тор - своя матрица"
#include "SphereWorld.h" // Упражнение 7: "7) Фантастический мир со сферами"
//**********************************************************
// Функция обратного вызова обработки выбора пользователя
void ExecuteMenu(int choice)
{
// Сбрасываем углы вращения прежнего варианта
xRot = yRot = 0;
// Запоминаем выбор в глобальную переменную
::choice = choice;
switch(::choice)
{
case 1:
ChangeSizeAtom(w, h);
break;
case 2:
ChangeSizeOrtho(w, h);
break;
case 3:
ChangeSizePerspect(w, h);
break;
case 4:
ChangeSizeAtomPerspect(w, h);
break;
case 5:
ChangeSizeSolar(w, h);
break;
case 6:
ChangeSizeTransform(w, h);
break;
case 7:
ChangeSizeSphereWorld(w, h);
break;
}
// Вызвать принудительно визуализацию
glutPostRedisplay();
}
//**********************************************************
// Функция обратного вызова для рисования сцены
void RenderScene(void)
{
switch(::choice)
{
case 1:
SetupLight(false);
RenderSceneAtom();
break;
case 2:
SetupLight(true);
RenderSceneOrtho();
break;
case 3:
SetupLight(true);
RenderScenePerspect();
break;
case 4:
SetupLight(false);
RenderSceneAtomPerspect();
break;
case 5:
SetupLightSolar(true);
RenderSceneSolar();
break;
case 6:
SetupLight(false);
RenderSceneTransform();
break;
case 7:
SetupLight(false);
RenderSceneSphereWorld();
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;
case 3:
ChangeSizePerspect(width, height);
break;
case 4:
ChangeSizeAtomPerspect(width, height);
break;
case 5:
ChangeSizeSolar(width, height);
break;
case 6:
ChangeSizeTransform(width, height);
break;
case 7:
ChangeSizeSphereWorld(width, height);
break;
}
}
//**********************************************************
// Обработчик события таймера
void TimerFunc(int value)
{
glutPostRedisplay(); // Перерисовка сцены
switch(::choice)
{
case 6:
glutTimerFunc(33, TimerFunc, 1); // Заряжаем новый таймер
break;
case 7:
glutTimerFunc(3, TimerFunc, 1); // Заряжаем новый таймер
break;
default:
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); // Включили режим отсечения сторон
SetupSphereWorld(); // Формируем сферы для упражнения 7
}
//**********************************************************
// Управление с клавиатуры стрелками для
// задания новых значений матрицы поворота
void SpecialKeys(int key, int x, int y)
{
switch(::choice)
{
default:
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;
break;
case 7:
SpecialKeysSphereWorld(key);
break;
}
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);
glutAddMenuEntry("3) Брусок в перспективной проекции", 3);
glutAddMenuEntry("4) Модель атома в перспективе", 4);
glutAddMenuEntry("5) Система \"Солнце-Земля-Луна\"", 5);
glutAddMenuEntry("6) Каркасный тор - своя матрица", 6);
glutAddMenuEntry("7) Фантастический мир со сферами", 7);
glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем
// Конец создания меню
glutMainLoop(); // Цикл сообщений графического окна
}
Попробуйте
разобраться с кодом, запустите упражнение, поуправляйте сценой
с помощью стрелок клавиатурыНа
![]() |
![]() |
Сдайте
работу преподавателю
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.