| Украина, Киев |
Геометрические примитивы в 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() при запуске приложения


