Штриховка полигонов
Штриховка полигонов
Теперь применим штриховку (stipple) к полигонам. Режим штриховки включается и выключается стандартным способом:
glEnable (GL_POLYGON_STIPPLE) ;
glDisable (GL_POLYGON_STIPPLE);
Bitmap-узор (pattern) штриховки надо предварительно подготовить в массиве такой размерности, чтобы заполнить bitmap площадью 32x32 = 1024 пиксела. Размерность массива с узором определяется так: 1024 бита можно разместить в 128 переменных по одному байту. Мы разместим их в 16 строках по 8 байт. Имеем 16 х х 8 х 8 = 1024 бита (или пиксела).
Массивы объявлены глобально. Адреса массивов с узором подаются на вход функции glPolygonStipple:
GLubyte gSpade[] = // Узор - пики
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xlf, 0xff, Oxff, 0xf8, 0xlf, 0x00, 0x00, 0xf8,
0x01, OxcO, 0x03, 0x80, 0x00, 0x70, 0xOe, 0x00,
0x00, |
0x20, |
0x04, |
0x00, |
0x00, |
0x30 |
, 0x0c, |
0x00, |
||
0x00, |
0x10, |
0x08, |
0x00, |
0x00, |
0x18 |
, 0x18, |
0x00, |
||
0x07, |
0хс4, |
0x23, |
0xe0, |
0x0f, |
0xf8 |
, 0xlf, |
0xf0, |
||
0x38, |
0xlc, |
0x38, |
0xlc, |
0x30, |
0x00 |
, 0x00, |
0x0c, |
||
0x60, |
0x00, |
0x00, |
0x06, |
0x60, |
0x00 |
, 0x00, |
0x06, |
||
0x60, |
0x00, |
0x00, |
0x06, |
0x60, |
0x00 |
, 0x00, |
0x06, |
||
0x60, |
0x00, |
0x00, |
0x06, |
0x30, |
0x00 |
, 0x00, |
0x0c, |
||
0x30, |
0x00, |
0x00, |
0x0c, |
0x18, |
0x00 |
, 0x00, |
0x18, |
||
0х0е, |
0x00, |
0x00, |
0x70, |
0x03, |
0x00 |
, 0x00, |
0xc0, |
||
0x00, |
OxcO, |
0x03, |
0x00, |
0x00, |
0x70 |
, 0x0e, |
0x00, |
||
0x00, |
0x18, |
0x18, |
0x00, |
0x00, |
0x0c |
, 0x30, |
0x00, |
||
0x00, |
0x07, |
OxeO, |
0x00, |
0x00, |
0x03 |
, 0xc0, |
0x00, |
||
0x00, |
0x01, |
0x80, |
0x00, |
0x00, |
0x00 |
, 0x00, |
0x00 |
||
GLubyte |
gStripU = |
// Другой узор - |
полоса |
|
|||||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
0x66, |
0x66, |
0x66, |
0x66, |
0x33, |
0x33 |
, 0x33, |
0x33, |
||
Функцию OnDraw замените целиком. Так же поступайте и дальше. Следите лишь за изменениями в функциях main, OnSize и init, которые понадобятся при радикальной смене режима передачи (rendering). Позже мы перейдем к передаче трехмерной графики, а пока режим тот же — двухмерная графика:
void _stdcall OnDraw()
{
//====== Стираем окно
glClear (GL_COLOR_BUFFER_BIT);
//====== Цвет фона (синеватый)
glColor3f (0.3f, 0.3f, 1.);
//== Рисуем сначала unstippled rectangle (без узора)
//== Rect - это тоже полигон
glRectf (20., 20., 115., 120.);
glColor3f (1., 0., 0.); // Меняем цвет на красный
glEnable (GL_POLYGON_STIPPLE); // Включаем штриховку
glPolygonStipple (gStrip); // Задаем узор
glRectf (120., 20., 215., 120.); // Рисуем
glColorSf (O.,0.,0.); // Меняем цвет на черный
glPolygonStipple (gSpade);
// Меняем узор glRectf (220., 20., 315., 120.);
glPolygonStipple (gStrip); // Меняем узор
glColor3f (0., 0.6f, 0.3f);
glRectf (320., 20., 415., 120.);
//== Готовимся заполнить более сложный, невыпуклый
//== (nоn convex) полигон
glPolygonStipple (gSpade);
glColorSd (0.6, O.f, 0.3f);
//======= Шесть вершин по три координаты
float c[6][3] =
{
420.,120.,0.,
420.,70.,0.,
470.,20.,0., 520., 70.,0.,
520.,120.,0.,
470.,100.,0.
};
//== Здесь мы специально выбираем nоn convex полигон,
//== чтобы увидеть как плохо с ним обходится OpenGL
glBegin (GL_POLYGON) ;
for (int i=0; i<6; i++)
glVertex3fv(c[i] ) ;
glEnd() ;
glDisable (GL_POLYGON_STIPPLE) ;
glFlush ();
}
Запустите и убедитесь в том, что последний полигон потерял одну точку. Затем замените цикл задания его вершин на:
for (int i=5; i>=0; i--) glVertex3fv(c[i]) ;
Здесь мы изменили порядок обхода вершин и начали с вогнутой вершины. Запустите и убедитесь в том, что теперь в полигоне есть все шесть вершин. OpenGL не гарантирует точную передачу вогнутых полигонов. Поэтому для надежной передачи их надо предварительно разбивать на выпуклые части. Если этими частями будут треугольники, то процесс разбиения называется tessellation (мозаика). Есть специальные функции для тесселяции полигонов. Их рассмотрение выходит за рамки этой книги. Попробуйте самостоятельно задать рассмотренный выше полигон в виде двух выпуклых четырехугольников. Для этого посмотрите справку по функции glBegin с параметром GL_QUADS.
Полигоны можно рисовать либо закрашенными (режим — GL_FILL), либо в скелетном виде (GL_LINE), либо в виде намеков (GL_POINT). Испробуйте все режимы на примере невыпуклой звезды. При рисовании точками попробуйте предварительно дать команду glPointSize (5):
void _stdcall OnDraw()
{
glClear (GL_COLOR_BUFFER_BIT);
glColor3d (1., 0.4, 1.);
//=== 2 угла, характеризующие звезду и
//=== 2 характерные точки
double pi = 4. * atan(l.),
al = pi / 10., a2 = 3. * al,
xl = costal), yl = sin(al)',
x2 = cos(a2), y2 = sin(a2);
//=== Мировые координаты вершин нормированной звезды
double с[5][3] =
{
0., 1., 0.,
-х2, -у2, 0.,
xl, yl, 0.,
-xl, yl, 0.,
х2, -у2, 0.,
};
//====== Оконные координаты
for (int i=0; i<5; i+t)
{
c[i][0] = 250 + 100*c[i][0];
c[i][l] = 100 + 100*c[i] [1] ;
}
//=== Режим заполнения полигона - скелетный
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
//=== Задаем вершины полигона
glBegin(GL_POLYGON);
for (i=0; i<5; i++)
glVertex3dv(c[i] ) ;
glEnd() ;
glFlush() ;
}