| Украина, Киев |
Геометрические примитивы в OpenGL
Упражнение 6. Рисование конуса (Triangle)
В качестве иллюстрации к сказанному построим простую программу, в которой с помощью двух вееров треугольников создается конус в наблюдаемом объеме. Первый веер задает форму конуса, используя первую точку в качестве вершины конуса, а все остальные - как точки на окружности, удаленной от наблюдателя в отрицательном направлении оси z. Второй веер формирует окружность и целиком лежит в плоскости x0y, образуя основание конуса. Сочлененные треугольники веера выделим разным цветом.
-
Добавьте
к проекту новый файл с именем Triangle.h и наполните его
следующим кодом (который тщательно изучите!!!)
void Triangle()
{
GLfloat x,y,angle; // Переменные для координат и угла
int iColor = 1; // Флаг переключения цвета
// Устанавливаем неструктурированный цвет модели затенения
glShadeModel(GL_FLAT);
// Устанавливаем направление обхода по часовой стрелке
glFrontFace(GL_CW);
// Очистить окно и буфер глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Включить/Выключить отбор
if(bCull)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
// Включить/Выключить глубину
if(bDepth)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
// Включить/Выключить каркас задней стенки
if(bOutline)
glPolygonMode(GL_BACK,GL_LINE);
else
glPolygonMode(GL_BACK,GL_FILL);
// Запомнить первоначальное состояние матрицы вращения
glPushMatrix();
// Выполнить два последовательных поворота
// для будущей визуализации сцены
glRotatef(xRot, 1.0f, 0.0f, 0.0f);// Новое состояние матрицы вращения
glRotatef(yRot, 0.0f, 1.0f, 0.0f);// Следующее новое состояние
//************ Рисовать конус ***********************************
// Рисовать веер треугольников
glBegin(GL_TRIANGLE_FAN);
// Устанавливаем первую точку - вершину конуса ближе к наблюдателю
glVertex3f(0.0f, 0.0f, 75.0f);
// Проходим оборот в плоскости x0y
for(angle = 0.0f; angle <= 2.0f * GL_PI; angle += GL_PI / 8.0f){
// Вычисляем очередную точку на окружности
x = 50.0f * sin(angle);
y = 50.0f * cos(angle);
// Чередуем цвета
if(iColor % 2) // Деление по модулю
glColor3f(0.0f, 1.0f, 0.0f); // Зеленый
else
glColor3f((GLfloat)0xFF, (GLfloat)0xFF, (GLfloat)0x00); // Желтый
iColor++; // Для переключения цвета
// Установливаем вычисленную точку на плоскости x0y
glVertex2f(x, y);
}
glEnd(); // Рисуем веер, имитирующий конус
//*********** Рисовать основание конуса *************************
// Начинаем строить новый веер в плоскости x0y
// Имитирующий основание конуса в начале координат
glBegin(GL_TRIANGLE_FAN);
// Устанавливаем первую точку центра основания при z=0
glVertex2f(0.0f, 0.0f);
// Проходим оборот в плоскости x0y
for(angle = 0.0f; angle <= 2.0f * GL_PI; angle += GL_PI / 8.0f){
// Вычисляем очередную точку на окружности
x = 50.0f * sin(angle);
y = 50.0f * cos(angle);
// Чередуем цвета
if(!(iColor % 2)) // Деление по модулю
glColor3f(0.0f, 0.0f, 1.0f); // Синий
else
glColor3f(1.0f, 0.0f, 0.0f); // Красный
iColor++; // Для переключения цвета
// Установливаем вычисленную точку на плоскости x0y
glVertex2f(x, y);
}
glEnd(); // Рисуем веер, имитирующий основание
// Восстанавливаем измененные состояния в исходные значения
glPopMatrix();
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glPolygonMode(GL_BACK,GL_FILL);
glColor3f(0.0f, 1.0f, 0.0f); // Зеленый
}
Листинг
21.43.
Код функции построения конуса Triangle()
-
Включите
этот файл инструкцией
#include "triangle.h"
#include "Points.h" // Включение перенесенного кода #include "PointsZ.h" // Включение кода рисования точек с увеличением размера #include "Lines.h" // Веер линий #include "LinesW.h" // Проверяется изменение ширины линий #include "LinesStipple.h" // Линии с разной фактурой #include "triangle.h" // Рисовать конус #include "Prompt.h" // Вспомогательный код для начального окнаЛистинг 21.45. Включение файла triangle.h в приложение
// Прототипы функций ................................................... void Triangle();Листинг 21.46. Добавление прототипа функции Triangle() в начало файла Primitives.cpp
//****************************************************
// Функция обратного вызова для рисования сцены
void RenderScene(void)
{
// Окно очищается текущим цветом,
// установленным функцией glClearColor()
glClear(GL_COLOR_BUFFER_BIT);
// Отработка выбора пользователя
switch(::choice){
case 1:
Points();
break;
case 2:
PointsZ();
break;
case 3:
Lines();
break;
case 4:
LinesW();
break;
case 5:
LinesStipple();
break;
case 6:
Triangle();
break;
default:
Prompt();
}
// Исполнить (очистить) очередь команд
glFlush();
}
Листинг
21.47.
Корректировка функции рендеринга в файле Primitives.cpp
В функции построения конуса Triangle() выделен код, обеспечивающий установки трех флагов для управления отбором, глубиной и рисованием каркаса. Эти флаги bCull, bDepth, bOutline нужно сделать глобальными, чтобы они виделись во всех требуемых местах программы.
-
Поместите перед функцией main() файла Primitives.cpp объявление глобальных флагов
.......................
// Глобальная переменная выбранного варианта основного меню
int choice = 0;
// Переменные для управления отбором, глубиной и каркасом в Triangle()
bool bCull = false, bDepth = true, bOutline = false;
// Точка входа приложения
void main(void)
{
....................................
}
Листинг
21.48.
Объявление глобальных флагов включения отбора, глубины и каркаса
Для того, чтобы иметь возможность управлять этими параметрами при рисовании конуса, воспользуемся средством библиотеки GLUT для создания подменю.
-
Дополните
код функции main() возможностью создания подменю
// Точка входа приложения
void main(void)
{
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutCreateWindow("Primitives"); // Заголовок окна
glutDisplayFunc(RenderScene); // Обновление сцены при разрушении окна
glutReshapeFunc(ChangeSize); // При изменении размера окна
SetupRC();
// Создаем окно пунктов подменю для рисования конуса
int triangle_menu = glutCreateMenu(TriangleExecuteMenu);
glutAddMenuEntry("Показать с начальными установками", 0);
glutAddMenuEntry("Отбор Вкл/Выкл", 1);
glutAddMenuEntry("Глубина Вкл/Выкл", 2);
glutAddMenuEntry("Каркас задней стенки Вкл/Выкл", 3);
// Создание меню и добавление опций выбора
glutCreateMenu(ExecuteMenu);
glutAddSubMenu("Рисование конуса", triangle_menu);// Именно на первом месте !!!
glutAddMenuEntry("Рисование функцией Points", 1);
glutAddMenuEntry("Точки с увеличением размера", 2);
glutAddMenuEntry("Веер линий", 3);
glutAddMenuEntry("Управление шириной линий", 4);
glutAddMenuEntry("Управление фактурой линий", 5);
glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем
// Конец создания меню
glutSpecialFunc(SpecialKeys); // Для управления с клавиатуры
glutMainLoop(); // Цикл сообщений графического окна
}
Листинг
21.49.
Добавление в функцию main() кода поддержки подменю
-
Добавьте
вначало файла Primitives.cpp объявление прототипа функции
обратного вызова подменю TriangleExecuteMenu()
#include "stdafx.h" // Искать в текущем каталоге проекта
// Прототипы функций
void RenderScene(void);
void SetupRC(void);
void ExecuteMenu(int);
void ChangeSize(int, int);
void Points(); // Пустой аргумент необязателен
void SpecialKeys(int key, int x, int y);// Можно указать только типы
void PointsZ();
void Lines();
void LinesW();
void LinesStipple();
void Prompt();
void Triangle();
void TriangleExecuteMenu(int);
// Глобальная переменная выбранного варианта основного меню
int choice = 0;
// Переменные для управления отбором, глубиной и каркасом в Triangle()
bool bCull = false, bDepth = true, bOutline = false;
// Точка входа приложения
void main(void)
{
....................................
}
Листинг
21.50.
Объявление прототипа для TriangleExecuteMenu()
-
Разместите
после функции main() код заготовки функции TriangleExecuteMenu() обработки
выбора пользователя в подменю
//****************************************************
// Функция обратного вызова обработки выбора пользователя в подменю
void TriangleExecuteMenu(int choice)
{
}
Листинг
21.51.
Код заготовки функции TriangleExecuteMenu()
-
Запустите
приложение - теперь меню пользователя должно выглядеть так
-
Заполните
заготовку функции TriangleExecuteMenu() следующим
кодом
//****************************************************
// Функция обратного вызова обработки выбора пользователя в подменю
void TriangleExecuteMenu(int choice)
{
switch(choice){
case 0:
bCull = false;
bDepth = true;
bOutline = false;
break;
case 1:
bCull = !bCull;
break;
case 2:
bDepth = !bDepth;
break;
case 3:
bOutline = !bOutline;
break;
default: // Просто так! - можно не вводить
;
}
// Устанавливаем режим и вызываем принудительно
// функцию визуализации, где размещен
// вызов функции рисования конуса
::choice = 6;
// Вызвать принудительно визуализацию
glutPostRedisplay();
}
Листинг
21.52.
Код функции TriangleExecuteMenu()
-
Запустите
приложение, выберите режим рисования конуса и получите следующий
результат при управлении стрелками и с разными установками




