Геометрични примитиви на OpenGL
Върховете трябва задължително да бъдат зададени по отношение на някакъв примитив. Изчертаването на примитива започва с извикване на функцията glBegin(), която се предава като параметър константа, обозначаваща типа на примитива. Примитивът завършва с функцията glEnd(). Прототипите на тези функции са:
void glBegin(режим Glenum);
void glEnd(void);
Между извикванията към glBegin() и glEnd() се правят извиквания към glVertex*(). Например, за да се опише многоъгълникът, показан на фиг. 3.5 отляво, трябва да извикате следните функции:
glVertex2d(0.0, 0.0);
glVertex2d(0.0, 3.0);
glVertex2d(3.0, 3.0);
glVertex2d(4.0, 1.5);
glVertex2d(3.0, 0.0);
Фиг. 3.5. Примитиви от два вида: многоъгълник и набор от точки.
Ако зададете GL_POINTS като примитивен тип вместо GL_POLYGON, тогава ще бъде изчертан набор от 5 точки (фиг. 3.5, вдясно). В табл. 3.1 изброява всички разрешени примитивни типове, които могат да бъдат посочени при извикване на glBegin().
Таблица 3.1. Имена и предназначение на геометричните примитиви.
Постоянно име | Предназначение |
GL_POINTS | отделни точки |
GL_LINES | Двойки върхове, които са краища на сегменти |
GL_POLYGON | Граница на прост изпъкнал многоъгълник |
GL_ТРИЪГЪЛНИЦИ | Тройки от върхове, които се интерпретират като върхове на триъгълници |
GL_QUADS | Четворки от върхове, които се интерпретират като върхове на четириъгълници |
GL_LINE_STRIP | Върхове на полилиния |
GL_LINE_LOOP | Затворени върхове на полилиния (същите като предишния тип, но последният и първият връх се свързват автоматично) |
GL_TRIANGLE_STRIP | Свързана лента от триъгълници (триъгълна лента) |
GL_TRIANGLE_FAN | Ветрило на триъгълници |
GL_QUAD_STRIP | Свързана лента от четириъгълници (квадратна лента) |
На фиг. 3.6 показва примери на примитивите, изброени в таблица. 3.1.nвърховете (v0, v1, v2, .vn-1) трябва да бъдат изброени между glBegin() и glEnd(). Както следва от фиг. 3.6, в допълнение към точки, линии и полигони,OpenGL има няколко други специални типа примитиви.
Фиг. 3.6. Видове геометрични примитиви.
Свойства на точки, линии и многоъгълници
По подразбиране точката се показва на екрана като единичен пиксел. Сегментите се изчертават като плътни с дебелина 1 пиксел. Многоъгълниците се изчертават запълнени. Следващите параграфи описват как можете да промените тези свойства на дисплея.
Точки
Размерът на точката на екрана се задава с помощта на функцията:
void glPointSize(плаващ размер);
където размерът е диаметърът на точката в пиксели (трябва да бъде по-голям от 0,0, по подразбиране 1,0).
Броят пиксели, които ще бъдат нарисувани на екрана, когато се покаже дадена точка, зависи от това дали анти-алиасингът е активиран или не. Ако изглаждането е деактивирано, тогава размерът се закръгля до цяло число и квадрат със страна от размер пиксели се запълва на екрана с текущия цвят.
Когато анти-алиасингът е активиран, точката се показва като кръг и интензитетът на пикселите вътре в кръга намалява от центъра към краищата. В режим на изглаждане,OpenGL предоставя частични размери за точки и ширини на линии. Начините за промяна на свойствата на точките са демонстрирани в програма 3.1.
void CALLBACK display();
auxInitDisplayMode(AUX_SINGLE AUX_RGBA);
auxInitPosition(0, 0, 200, 200);
auxInitWindow( "Лекция 3, Програма 3.1" );
glClearColor(0.0, 0.0, 0.0, 0.0);
void CALLBACK display()
// В първия ред има три точки с диаметър 2 пиксела, без анти-алиасинг
glColor3d(1, 0, 0);
glVertex2d(50, 180);
glColor3d(0, 1, 0);
glVertex2d(100, 180);
glColor3d(0, 0, 1);
glVertex2d(150, 180);
// Във втория ред има три точки с диаметър 5 пиксела, без антиалиас
glColor3d(1, 0, 0);
glVertex2d(50, 100);
glColor3d(0, 1, 0);
glVertex2d(100, 100);
glColor3d(0, 0, 1);
glVertex2d(150, 100);
// В 3-ти ред има три точки с диаметър 10 пиксела, с антиалиасинг
glColor3d(1, 0, 0);
glVertex2d(50, 20);
glColor3d(0, 1, 0);
glVertex2d(100, 20);
glColor3d(0, 0, 1);
glVertex2d(150, 20);
// Принудително прекратяване на всички операции по чертане
Програма 3.1. Рисуване на точки с различни размери при
изключване и включване на изглаждането.
Сегменти
Линейните сегменти вOpenGL могат да имат дебелина и стил (пунктирана линия, пунктирана линия, пунктирана точка и т.н.). Дебелината на линията (в пиксели) е 1.0 по подразбиране, има функция за промяна:
void glLineWidth(ширина на GLfloat);
Стилът на линията (тип пунктирана линия) се задава от функцията glLineStipple():
void glLineStipple(фактор GLint, шаблон GLushort);
След като извикате тази функция, не забравяйте да активирате стила с помощта на glEnable(), например:
glLineStipple(1, 0x3F07);
Видът на пунктираната линия се определя от шаблон - 16-битов числов модел, в който битове, равни на 0 и 1, означават празни изасенчени пиксели. Размерът на шаблона може да бъде увеличен с помощта на коефициента, който определя броя на повторенията на всеки бит от шаблона.
В примера по-горе моделът е 0x3F07 (в двоичен е 0011111100000111). Когато чертаете сегмент, първо 3 пиксела се рисуват, след това 5 се пропускат, след това 6 се рисуват, 2 се пропускат (моделът се обработва от дясно на ляво, от ниски битове към високи битове). Ако зададете фактор=2, тогава шаблонът ще зададе следното правило за рисуване: боядисване на 6 пиксела, пропускане на 10, боядисване на 12, пропускане на 4. На фиг. 3.7 показва сегменти от различни стилове и съответните стойности на шаблона и множителя.
Фиг. 3.7. Пунктирани линии.
Чертането на линейни сегменти с няколко стила и различни дебелини е демонстрирано в програма 3.2. Резултатът от тази програма е показан на фиг. 3.8. Интересно е да се отбележи ефектът, който програма 3.2 постига благодарение на това, че отсечката се чертае не наведнъж цялата, а от няколко отделни отсечки.
Фиг. 3.8. Сегменти с различни стилове и дебелини.
void drawOneLine( двойно x1, двойно y1, двойно x2, двойно y2);
void CALLBACK display();
auxInitDisplayMode(AUX_SINGLE AUX_RGBA);
auxInitPosition(0, 0, 400, 150);
auxInitWindow( "Лекция 3, Програма 3.2" );
glClearColor(0.0, 0.0, 0.0, 0.0);
void drawOneLine( двойно x1, двойно y1, двойно x2, двойно y2)
glVertex2d(x1, y1);
glVertex2d(x2, y2);
void CALLBACK display()
glColor3d(1.0, 1.0, 1.0); // Всички сегменти са начертани в бяло
// В първия ред има 3 сегмента с различни стилове
glLineStipple(1, 0x0101); // пунктирана линия
drawOneLine(50.0, 125.0, 150.0, 125.0);
glLineStipple(1, 0x00FF);// прекъсната линия
drawOneLine(150.0, 125.0, 250.0, 125.0);
glLineStipple(1, 0x1C47); // Тире-точка-тире
drawOneLine( 250.0, 125.0, 350.0, 125.0);
// Във втория ред има 3 сегмента с дебелина 5 пиксела и различни стилове
glLineStipple(1, 0x0101);
drawOneLine(50.0, 100.0, 150.0, 100.0);
glLineStipple(1, 0x00FF);
drawOneLine(150.0, 100.0, 250.0, 100.0);
glLineStipple(1, 0x1C47);
drawOneLine(250.0, 100.0, 350.0, 100.0);
// В 3-тия ред има 6 сегмента от стила тире-точка-тире, които
// образуват един голям сегмент
glLineStipple(1, 0x1C47);
за ( int i = 0; i 0), което се изчислява по формулата:
,
където xi и yi са екранните координати на i-тия връх на n-ъгълника. Операцията Å е обичайното събиране, с изключение на това, чеnÅ 1 = 1:
.
Когато се показва затворена повърхност от полигони с еднаква ориентация, няма да се виждат задни страни - всички те са закрити от предните страни на полигоните. В този случай можете да ускорите изобразяването на повърхността, като попречите наOpenGL да рисува задните страни. За да деактивирате рисуването на определени страни на полигони, използвайте функцията:
void glCullFace(режим GLenum);
Параметърът на режима е GL_FRONT, GL_BACK или GL_FRONT_AND_BACK. Преди да извикате тази функция, трябва да активирате отстраняването на страните на полигона, като извикате glEnable( GL_CULL_FACE).
Програма 3.3 илюстрира начините за изчертаване на различни страни на многоъгълници на примера на 6-странна пирамида без основа. С курсорните клавиши тя може да се завърта под различни ъгли, като разликата между външната и вътрешната повърхност на пирамидата е ясно видима. забележи, чеако зададете различни цветове на върховете на многоъгълника, тогаваOpenGL автоматично извършва цветова интерполация при запълване на многоъгълника.
void CALLBACK resize( int width, int height );
void CALLBACK display();
void CALLBACK addAngleX();
void CALLBACK subAngleX();
void CALLBACK addAngleY();
void CALLBACK subAngleY();
// Местоположение на пирамидата спрямо осите X и Y
int ъгъл_x = 0, ъгъл_y = 0;
auxInitDisplayMode(AUX_RGBA AUX_DEPTH AUX_DOUBLE);
auxInitPosition(50, 10, 400, 400);
auxInitWindow( "Лекция 3, Програма 3.3" );
// Активирайте някои опции на OpenGL
// Задайте позицията и посоката на нулевия източник на светлина
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, реж.);
// Регистриране на манипулатори на събития
auxKeyFunc(AUX_UP, subAngleX);
auxKeyFunc(AUX_DOWN, addAngleX);
auxKeyFunc(AUX_RIGHT, addAngleY );
auxKeyFunc(AUX_LEFT, subAngleY );
void CALLBACK преоразмеряване (int ширина, int височина)
glViewport(0, 0, ширина, височина);
gluPerspective(60.0, (двойна)ширина/(двойна)височина, 1.0, 20.0);
gluLookAt(0.0.5, 0.0.0, 0.1.0);
void CALLBACK display()
const двойно BASE_R = 1; // Основен радиус
const двойна ПИРАМА >
const двойно PI = 3.14159;
glClear( GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT);