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

Геометрические примитивы в OpenGL

Другие примитивы

Треугольники в OpenGl используются чаще всего, поскольку могут аппроксимировать фигуру любой сложности. Но в OpenGL имеются также прямоугольники и универсальные многоугольники (полигоны). Для рисования прямоугольных четырехугольников применяется команда

glBegin(GL_QUADS);
  .....................
  glEnd();

Для аппроксимации сложных поверхностей прямоугольниками они строятся в ленты (как и треугольники) с помощью команды

glBegin(GL_QUAD_STRIP);
  .....................
  glEnd();

Полигоны задаются с помощью команды

glBegin(GL_POLYGON);
  .....................
  glEnd();

При задании вершин одного прямоугольника или полигона важно следить за тем, чтобы все вершины лежали в одной плоскости. Хотя это условие можно обойти, применяя опцию GL_TRIANGLE_FAN вместо GL_POLYGON.

Упражнение 7. Фактура многоугольников (PolygonStipple)

Существует два способа (помимо структурированной или градиентной заливки) наложить на поверхность многоугольника какой-либо рисунок:

  • наложение текстуры - когда изображение отображается на поверхность многоугольника
  • задание фактурного узора с помощью наложения маски - как это мы делали для линий

Здесь мы рассмотрим второй способ, а про текстуры будем говорить позднее.

Фактурный узор многоугольника - это не более чем монохромное растровое изображение-маска размером 32x32 пиксела, используемое как узор-заполнитель. Включение режима заполнения многоугольника фактурой выполняется следующей последовательностью команд

glEnable(GL_POLYGON_STIPPLE);
glPolygonStipple(pBitmap);

pBitmap - это указатель на узор-заполнитель типа ( GLubyte * - unsigned byte). Этот узор является маской подобно используемой нами при наложении фактуры на линию. Маску для многоугольников можно сравнить с полем крассворда, которые печатают в газетах. Буфер для размещения маски должен имет размер 4*32=128 байт.

Рассмотрим маску костра, которую будем реализовывать в нашем упражнении рисования многоугольников с фактурой. Построчный порядок задания значения шаблона обратно противоположный его использованию


  • Через панель Solution Explorer добавьте к проекту новый header -файл (заголовочный файл) с именем PolygonStipple.h
  • Заполните этот файл следующим кодом
// Описание битовой маски костра 32x32 снизу вверх
GLubyte fire[128] = 
{ 
  0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xc0,
  0x00, 0x00, 0x01, 0xf0,
  0x00, 0x00, 0x07, 0xf0,
  0x0f, 0x00, 0x1f, 0xe0,
  0x1f, 0x80, 0x1f, 0xc0,
  0x0f, 0xc0, 0x3f, 0x80,  
  0x07, 0xe0, 0x7e, 0x00,
  0x03, 0xf0, 0xff, 0x80,
  0x03, 0xf5, 0xff, 0xe0,
  0x07, 0xfd, 0xff, 0xf8,
  0x1f, 0xfc, 0xff, 0xe8,
  0xff, 0xe3, 0xbf, 0x70, 
  0xde, 0x80, 0xb7, 0x00,
  0x71, 0x10, 0x4a, 0x80,
  0x03, 0x10, 0x4e, 0x40,
  0x02, 0x88, 0x8c, 0x20,
  0x05, 0x05, 0x04, 0x40,
  0x02, 0x82, 0x14, 0x40,
  0x02, 0x40, 0x10, 0x80, 
  0x02, 0x64, 0x1a, 0x80,
  0x00, 0x92, 0x29, 0x00,
  0x00, 0xb0, 0x48, 0x00,
  0x00, 0xc8, 0x90, 0x00,
  0x00, 0x85, 0x10, 0x00,
  0x00, 0x03, 0x00, 0x00,
  0x00, 0x00, 0x10, 0x00 
};
  
// Рисуем полигон в форме дорожного знака
// с заливкой по битовой маске
void PolygonStipple()
{
  // Очистить окно рисования
  glClear(GL_COLOR_BUFFER_BIT);
  
  // Запомнить первоначальное состояние матрицы вращения
  glPushMatrix();
  
  // Настроить два последовательных поворота
  // для будущей визуализации сцены
  glRotatef(xRot, 1.0f, 0.0f, 0.0f);// Первое состояние матрицы вращения
  glRotatef(yRot, 0.0f, 1.0f, 0.0f);// Следующее состояние
  
  // Включить красный цвет рисования
  glColor3f(1.0f, 0.0f, 0.0f);
  
  // Включить фактуру при заполнении полигонов
  glEnable(GL_POLYGON_STIPPLE);
  
  // Адресовать битовую маску костра для фактуры
  glPolygonStipple(fire);
  
  // Нарисовать полигон в форме дорожного знака
  // "Движение без остановки запрещено",
  // закрашенного по маске костра красным цветом
  glBegin(GL_POLYGON);
    glVertex2f(-20.0f, 50.0f);
    glVertex2f(20.0f, 50.0f);
    glVertex2f(50.0f, 20.0f);
    glVertex2f(50.0f, -20.0f);
    glVertex2f(20.0f, -50.0f);
    glVertex2f(-20.0f, -50.0f);
    glVertex2f(-50.0f, -20.0f);
    glVertex2f(-50.0f, 20.0f);
  glEnd();
  
  glColor3f(0.0f, 1.0f, 0.0f); // Восстановить цвет рисования зеленый
  
  // Выключить фактуру при заполнении полигонов
  glDisable(GL_POLYGON_STIPPLE);
  
  // Восстановить матрицу вращения в исходное состояние
  glPopMatrix();
}
Листинг 21.63. Код файла PolygonStipple.h
  • Разместите в начале файла Primitives.cpp прототип функции PolygonStipple()
#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 TriangleExecuteMenu(int);
void Triangle();
void PolygonStipple();
..................................
Листинг 21.64. Объявление (прототип) функции PolygonStipple()
  • Добавьте в функцию main() файла Primitives.cpp новый пункт меню для вызова нового упражнения
// Точка входа приложения
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);
  // Число 6 у нас задействовано для субменю
  glutAddMenuEntry("Управление фактурой полигонов", 7);
  
  glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем 
  // Конец создания меню
  
  glutSpecialFunc(SpecialKeys); // Для управления с клавиатуры
  
  glutMainLoop();  // Цикл сообщений графического окна
}
Листинг 21.65. Добавление нового пункта меню в функции main()
  • Добавьте в функцию рендеринга RenderScene() файла 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;
    case 7:
      PolygonStipple();
      break;
    default:
      Prompt();
  }
  
  // Исполнить (очистить) очередь команд
  glFlush();
}
Листинг 21.66. Вызов функции PolygonStipple()
  • Добавьте в конец файла Primitives.cpp подключение файла PolygonStipple.h с кодом нового упражнения
#include "Points.h"    // Включение перенесенного кода
#include "PointsZ.h"  // Включение кода рисования точек с увеличением размера
#include "Lines.h"    // Веер линий  
#include "LinesW.h"    // Проверяется изменение ширины линий
#include "LinesStipple.h" // Линии с разной фактурой
#include "triangle.h"  // Рисовать конус
#include "PolygonStipple.h"  // Рисовать полигон с закраской по маске
#include "Prompt.h"    // Вспомогательный код для начального окна
Листинг 21.67. Подключение файла PolygonStipple.h с кодом нового упражнения
  • Запустите приложение - должен получиться следующий результат


Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000