Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 20:

Геометрические примитивы в 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
  • Добавьте в начало файла Primitives.cpp прототип функции LinesStipple()
.................................................  
// Прототипы функций
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"

в конец файла Primitives.cpp

#include "Points.h"    // Включение перенесенного кода
#include "PointsZ.h"  // Включение кода рисования точек с увеличением размера
#include "Lines.h"    // Веер линий  
#include "LinesW.h"    // Проверяется изменение ширины линий
#include "LinesStipple.h" // Линии с разной фактурой
#include "Prompt.h"
Листинг 21.38. Включение временного файла в приложение
  • Добавьте в начало файла Primitives.cpp прототип функции Prompt()
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() при запуске приложения
Александр Очеретяный
Александр Очеретяный
Украина, Киев
Анастасия Балыбердина
Анастасия Балыбердина
Украина, Киев, НТУУ КПИ