Геометрические примитивы в OpenGL
Упражнение 5. Фактура линий (LinesStipple)
Пунктирная или штриховая форма линий называется фактурой (stippling). Фактура линий включается командой
glEnable(GL_LINE_STIPPLE);
а выключается командой
glDisable(GL_LINE_STIPPLE);
После включения режима фактуры сама фактура, которая будет применяться при рисовании, устанавливается функцией
void glLineStipple(GLint factor, GLushort pattern);
Параметр pattern - это 16 - битовое значение, задающее шаблон (маску), который нужно использовать при рисовании линии. Ненулевой бит шаблона представляет рисуемый пиксел в линии, нулевой - нерисуемый. Параметр factor используется как множитель, увеличивающий ширину шаблона. Порядок задания значения шаблона обратно противоположный его использованию и представлен на рисунке
Начало линии определяет самый младший бит машинного представления шаблона. Такой запутанный порядок определения фактуры связан с тем, что OpenGL гораздо быстрее смещать шаблон на одну позицию влево всякий раз, когда требуется новое значение маски.
Теперь рассмотрим это на практике. Зададим шаблон 0x5555 = {0101'0101'0101'0101}, который определит равными штрихи и промежутки в фактуре линии. Нарисуем несколько линий, для каждой из которых будем увеличивать множитель шаблона.
- Через панель Solution Explorer добавьте к проекту новый файл с именем LinesStipple.h.
- Скопируйте в него содержимое файла LinesW.h и модифицируйте содержимое, чтобы окончательно файл LinesStipple.h выглядел так
//********************************************************** // Функция рисования линий с разной фактурой void LinesStipple() { // Запомнить первоначальное состояние матрицы вращения glPushMatrix(); // Настроить два последовательных поворота // для будущей визуализации сцены glRotatef(xRot, 1.0f, 0.0f, 0.0f);// Первое состояние матрицы вращения glRotatef(yRot, 0.0f, 1.0f, 0.0f);// Следующее состояние GLfloat sizes[2]; // Емкость для определения диапазона ширины линий glGetFloatv(GL_LINE_WIDTH_RANGE, sizes);// Извлекаем диапазон // Устанавливаем минимальный размер ширины линий glLineWidth(sizes[0]); // Устанавливаем начальные параметры фактуры GLint factor = 1; // Начальный множитель шаблона GLushort pattern = 0x5555; // Шестнадцатиричное представление шаблона // Включаем режим фактуры glEnable(GL_LINE_STIPPLE); // Пошаговый проход по оси y с шагом 20 единиц снизу вверх // Получится 10 линий по размеру отсекающего куба в плоскости z = 0 for(GLfloat y = -90.0f; y <= 90.0f; y += 20.0f){ // Устанавливаем множитель и шаблон glLineStipple(factor, pattern); // Посылаем на визуализацию каждую линию по отдельности glBegin(GL_LINES); // Задаем два конца линии в плоскости z = 0 glVertex2f(-90.0f, y); glVertex2f(90.0f, y); glEnd(); // Закончили визуализацию factor += 3; // Увеличиваем множитель шаблона } // Восстанавливаем матрицу вращения в исходное состояние glPopMatrix(); // Отключаем режим фактуры glDisable(GL_LINE_STIPPLE); }Листинг 21.31. Управление фактурой линий в файле LinesStipple.h
- Разместите в конце файла Primitives.cpp включение файла LinesStipple.h
................................................. #include "Points.h" // Включение перенесенного кода #include "PointsZ.h" // Включение кода рисования точек с увеличением размера #include "Lines.h" // Веер линий #include "LinesW.h" // Проверяется изменение ширины линий #include "LinesStipple.h" // Линии с разной фактурой .................................................Листинг 21.32. Конец файла Primitives.cpp
................................................. // Прототипы функций 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(); .................................................Листинг 21.33. Добавление прототипа функции LinesStipple() в начало файла Primitives.cpp
- Скорректируйте меню в функции main()
................................................. // Создание меню и добавление опций выбора glutCreateMenu(ExecuteMenu); glutAddMenuEntry("Рисование функцией Points", 1); glutAddMenuEntry("Точки с увеличением размера", 2); glutAddMenuEntry("Веер линий", 3); glutAddMenuEntry("Управление шириной линий", 4); glutAddMenuEntry("Управление фактурой линий", 5); glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем // Конец создания меню .................................................Листинг 21.34.png. Корректировка меню в файле 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; } // Исполнить (очистить) очередь команд glFlush(); }Листинг 21.35.png. Корректировка функции RenderScene() в файле Primitives.cpp
- Запустите приложение и получите следующий результат при управлении стрелками
Рисование многоугольников в трехмерном пространстве
В предыдущих упражнениях были рассмотрены вопросы, как рисовать точки, линии и даже замкнутые многоугольники в трехмерном пространстве. Но таких примитивов достаточно, чтобы нарисовать каркас объекта, и недостаточно, чтобы представить его объем. Для этого нужны многоугольники, как замкнутая форма, которая может быть (а может и не быть) закрашена внутри текущим цветом. Многоугольник является основой визуализации всех твердотельных композиций в OpenGL.
Добавление заставки
В нашем изложении понадобятся промежуточные результаты, иллюстрирующие некоторые вспомогательные положения темы. Давайте добавим к приложению вспомогательный файл, содержимое которого будем наполнять по мере необходимости некоторым временным кодом. Пусть этот файл отображается сразу же при запуске приложения.
- В панели Solution Explorer выделите узел Primitives и командой меню Project/Add New Item добавьте к проекту файл Prompt.h
Пусть содержимое файла будет таким
//********************************************************** // Вспомогательный файл для примеров void Prompt() { // Запомнить первоначальное состояние матрицы вращения glPushMatrix(); // Настроить два последовательных поворота // для будущей визуализации сцены glRotatef(xRot, 1.0f, 0.0f, 0.0f);// Первое состояние матрицы вращения glRotatef(yRot, 0.0f, 1.0f, 0.0f);// Следующее состояние // Блок визуализации glBegin(GL_TRIANGLES); glEnd(); // Закончили визуализацию // Восстанавливаем матрицу вращения в исходное состояние glPopMatrix(); }Листинг 21.36.png. Временный файл Prompt.h
- Включите этот файл инструкцией
#include "Prompt.h"
#include "Points.h" // Включение перенесенного кода #include "PointsZ.h" // Включение кода рисования точек с увеличением размера #include "Lines.h" // Веер линий #include "LinesW.h" // Проверяется изменение ширины линий #include "LinesStipple.h" // Линии с разной фактурой #include "Prompt.h"Листинг 21.38. Включение временного файла в приложение
void Prompt();
- Настройте функцию рендеринга на вызов Prompt() сразу при запуске приложения без вызова меню пользователя
//**************************************************** // Функция обратного вызова для рисования сцены 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; default: Prompt(); } // Исполнить (очистить) очередь команд glFlush(); }Листинг 21.40. Вызов функции Prompt() при запуске приложения