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

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

Пояснения к коду PolygonStipple

Обратите внимание, что описание строк битовой маски в массиве fire[128] выполняется в обратном порядке по отношению к самой маске, приведенной ранее на рисунке. Такой порядок заведен разработчиками OpenGL.

Если в файле PolygonStipple.h закомментировать строку

// Включить фактуру при заполнении полигонов
//  glEnable(GL_POLYGON_STIPPLE);

включения заливки по маске, то полигон в начальном положении будет отображаться так


Обратите также внимание на то, что при вращении плоского полигона в трехмерном пространстве маска не поворачивается вместе с ним. Узор-заполнитель применяется только для простой заливки многоугольника на экране. Если же нам необходимо отобразить рисунок на сам многоугольник, чтобы он имитировал поверхность многоугольника, то применяется технология наложения текстуры.

Упражнение 8. Каркасный режим: отсечение внутренних граней (Star)

Мы уже использовали ранее в упражнении Triangle каркасный режим рисования с помошью кода

// Включить/Выключить каркас задней стенки
  if(bOutline)
    glPolygonMode(GL_BACK,GL_LINE);
  else
    glPolygonMode(GL_BACK,GL_FILL);

и получали такой результат


Треугольные примитивы, составляющие фигуру, в каркасном режиме имеют границы на сторонах. Иногда некоторые границы хочется отключить - и это можно сделать. OpenGL имеет функцию glEdgeFlag() ( метка стороны ), которая может помечать сторону при рисовании как отображаемую или нет. Код glEdgeFlag(true) помечает все следующие за ним линии примитивов как отображаемые в каркасном режиме, код glEdgeFlag(false) задает альтернативный режим. Естественно, что все это действует при условии, что включен каркасный режим функцией glPolygonMode()

Синтаксис функции glEdgeFlag()
Цель: Пометить стороны многоугольника как граничные или неграничные.
Включаемый файл: <gl.h>
Прототип: void glEdgeFlag(GLboolean flag);
Описание: При объединении нескольких многоугольников внешние стороны формируют границы новой области. Функция помечает внутренние стороны как граничные (true - по умолчанию) или неграничные (false). Используется только в режимах многоугольников GL_LINE или GL_POINT.
Параметры:
  • flag = true - устанавливает метку края составляющего область многоугольника как отображаемую в режиме GL_LINE или GL_POINT функции glPolygonMode()
  • flag = false - устанавливает метку края составляющего область многоугольника как неотображаемую в режиме GL_LINE или GL_POINT функции glPolygonMode ()

Проверим, как это работает, на простом примере: нарисуем пятиконечную звезду с координатами, приведенными на рисунке


Размеры звезды будут находиться в пределах отсекающего объема, установленного в нашем приложении. Внешние стороны (красный цвет) больших треугольников однозначно пометим как внешние, а все остальные стороны будем переключать сначала как внешние, затем - как внутренние.

  • В панели Solution Explorer добавьте к приложению новый h-файл с именем Star.h
  • Скопируйте содержимое файла Triangle.h в файл Star.h и модифицируйте код, чтобы окончательно он имел следующий вид
void Star()
{
  // Очистить окно просмотра
  glClear(GL_COLOR_BUFFER_BIT);
  
  // Включить каркасный режим для обеих сторон звезды
  glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  
  // Запомнить первоначальное состояние матрицы вращения
  glPushMatrix();
  
  // Выполнить два последовательных поворота
  // для будущей визуализации сцены
  glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  glRotatef(yRot, 0.0f, 1.0f, 0.0f);
  
  //************  Рисовать внутренние контуры звезды  *************
  // Рисовать веер треугольников
  glBegin(GL_TRIANGLES);
    // Устанавливаем переключатель метки сторон
    glEdgeFlag(bEdgeFlag);
    
    // Устанавливаем вершины
    glVertex2f(0.0f, 0.0f); // Центр звезды
    glVertex2f(-18.0f, 26.0f);
    glVertex2f(18.0f, 26.0f);
  
    glVertex2f(0.0f, 0.0f);
    glVertex2f(18.0f, 26.0f);
    glVertex2f(30.0f, -10.0f);
  
    glVertex2f(0.0f, 0.0f);
    glVertex2f(30.0f, -10.0f);
    glVertex2f(0.0f, -32.0f);
  
    glVertex2f(0.0f, 0.0f);
    glVertex2f(0.0f, -32.0f);
    glVertex2f(-30.0f, -10.0f);
  
    glVertex2f(0.0f, 0.0f);
    glVertex2f(-30.0f, -10.0f);
    glVertex2f(-18.0f, 26.0f);
  glEnd(); 
  
  //***********  Рисовать внешние треугольники звезды **************
  glBegin(GL_TRIANGLES);
    glEdgeFlag(true);
    glVertex2f(-18.0f, 26.0f);
    glVertex2f(0.0f, 80.0f); glEdgeFlag(false);
    glVertex2f(18.0f, 26.0f);
  
    glEdgeFlag(true);
    glVertex2f(18.0f, 26.0f);
    glVertex2f(80.0f, 26.0f); glEdgeFlag(false);
    glVertex2f(30.0f, -10.0f);
  
    glEdgeFlag(true);
    glVertex2f(30.0f, -10.0f);
    glVertex2f(50.0f, -68.0f); glEdgeFlag(false);
    glVertex2f(0.0f, -32.0f);
  
    glEdgeFlag(true);
    glVertex2f(0.0f, -32.0f);
    glVertex2f(-50.0f, -68.0f); glEdgeFlag(false);
    glVertex2f(-30.0f, -10.0f);
  
    glEdgeFlag(true);
    glVertex2f(-30.0f, -10.0f);
    glVertex2f(-80.0f, 26.0f); glEdgeFlag(false);
    glVertex2f(-18.0f, 26.0f);
  glEnd(); 
  
  // Восстанавливаем измененные состояния в исходные значения
  glPopMatrix();
  glPolygonMode(GL_BACK,GL_FILL);
}
Листинг 21.71. Код файла Star.h
  • Внесите в файл Primitives.cpp выделенные ниже добавления для вызова упражнения
#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();
void Star(); 
void StarExecuteMenu(int);
  
// Глобальная переменная выбранного варианта основного меню
int choice = 0;
  
// Переменные для управления отбором, глубиной и каркасом в Triangle()
bool bCull = false, bDepth = true, bOutline = false; 
 
// Метки сторон
bool bEdgeFlag = true;
  
// Точка входа приложения
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);
  
  // Создаем подменю для рисования звезды
  int star_menu = glutCreateMenu(StarExecuteMenu);
  glutAddMenuEntry("Метки сторон Вкл.", 0);
  glutAddMenuEntry("Метки сторон Выкл.", 1);
  
  // Создание меню и добавление опций выбора
  glutCreateMenu(ExecuteMenu);
  glutAddSubMenu("Рисование конуса", triangle_menu);// Именно на первом месте
  glutAddMenuEntry("Рисование функцией Points", 1);
  glutAddMenuEntry("Точки с увеличением размера", 2);
  glutAddMenuEntry("Веер линий", 3);
  glutAddMenuEntry("Управление шириной линий", 4);
  glutAddMenuEntry("Управление фактурой линий", 5);
  // Число 6 у нас задействовано для субменю
  glutAddMenuEntry("Управление фактурой полигонов", 7);
  glutAddSubMenu("Рисование звезды", star_menu);
  
  glutAttachMenu(GLUT_RIGHT_BUTTON);// Присоединяем 
  // Конец создания меню
  
  glutSpecialFunc(SpecialKeys); // Для управления с клавиатуры
  
  glutMainLoop();  // Цикл сообщений графического окна
}
  
//****************************************************
// Функция обратного вызова обработки выбора пользователя в подменю
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();
}
  
//****************************************************
// Функция обратного вызова обработки выбора пользователя в подменю
void StarExecuteMenu(int choice) 
{
  switch(choice){
    case 0:
      bEdgeFlag = true;
      break;
    case 1: 
      bEdgeFlag = false;
  }
  
  // Устанавливаем режим и вызываем принудительно 
  // функцию визуализации, где размещен
  // вызов функции рисования звезды
  ::choice = 8;
  
  // Вызвать принудительно визуализацию
  glutPostRedisplay();
}
  
// Глобальные переменные для создания вращения
GLfloat xRot = 0.0f;
GLfloat yRot = 0.0f;
  
//****************************************************
// Функция обратного вызова обработки выбора пользователя
void ExecuteMenu(int choice)
{
  // Сбрасываем углы вращения прежнего варианта
  xRot = yRot = 0;
  
  // Передаем выбор в глобальную переменную
  ::choice = choice; 
  
  // Вызвать принудительно визуализацию
  glutPostRedisplay();

}
  
//****************************************************
// Функция обратного вызова для рисования сцены
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;
    case 8: 
      Star();
      break;
    default:
      Prompt();
  }
  
  // Исполнить (очистить) очередь команд
  glFlush();
}
  
#include "Points.h"    // Включение перенесенного кода
#include "PointsZ.h"  // Включение кода рисования точек с увеличением размера
#include "Lines.h"    // Веер линий  
#include "LinesW.h"    // Проверяется изменение ширины линий
#include "LinesStipple.h" // Линии с разной фактурой
#include "triangle.h"  // Рисовать конус
#include "PolygonStipple.h"  // Рисовать полигон с закраской по маске
#include "Prompt.h"    // Вспомогательный код для начального окна
#include "Star.h"    // Управление метками сторон
Листинг 21.72. Добавления в файл Primitives.cpp выделены в листинге
  • Запустите приложение и получите результат для текущего упражнения


Заметьте, что функциональность по вращению объекта у нас сохранилась во всех упражнениях.


Александр Очеретяный
Александр Очеретяный
Украина, Киев
Анастасия Балыбердина
Анастасия Балыбердина
Украина, Киев, НТУУ КПИ