De obicei poligoanele sunt afişate prin contur continuu, dar pot fi afişate şi cu conturul punctat sau numai prin vârfurile ce-l compun. Un poligon poate avea interiorul generat uniform sau folosind un anumit şablon. Poligoanele sunt afişate astfel încât pentru poligoanele adiacente care împart o latură sau un vârf, pixelii ce formează latura respectivă sau vârful respectiv sunt afişaţi o singură dată – ei sunt incluşi numai într-un singur poligon.
II.8.3.1. Modul de afişare
Un poligon este considerat ca având două feţe – cea din faţă şi cea din spate. El poate fi generat ţinând cont de ambele feţe, numai de feţele din faţă (cele aflate spre observator) sau numai de feţele din spate. În mod implicit, feţele din faţă şi din spate sunt afişate în acelaşi mod. Pentru a modifica acest lucru sau pentru a afişa poligoanele prin contur sau numai prin vârfurile ce-l compun se va folosi funcţia glPolygonMode :
void glPolygonMode(GLenum face, GLenum mode);
-
face specifică feţele la care se referă parametrul mode; poate fi GL_FRONT_AND_BACK (feţele faţă şi spate), GL_FRONT (feţele faţă), sau GL_BACK (feţele spate);
-
mode reprezintă modul de afişare a feţelor selectate; poate fi: GL_POINT (poligoanele vor fi afişate prin vârfuri), GL_LINE (poligoanele vor fi afişate prin contur), sau GL_FILL (poligoanele vor fi afişate cu interior plin)
În mod implicit, ambele tipuri de feţe sunt afişate cu interiorul plin.
Exemplu
Se cere afişarea faţelor din faţă cu interiorul plin, iar a celor din spate prin contur:
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_LINE);
II.8.3.2. Orientarea feţelor
In mod implicit, feţele ale căror vârfuri sunt parcurse în sens invers acelor de ceas sunt considerate feţe din faţă (orientate spre observator). Această convenţie poate fi modificată de programator, apelând funcţia glFrontFace.
void glFrontFace(GLenum mode);
Parametrul mode specifică orientarea feţelor din faţă ale poligoanelor. Valoarea GL_CCW (valoarea implicită) corespunde unei orientări în sensul invers acelor de ceas a conturului unei feţe proiectate în coordonate de afişare. Valoarea GL_CW, indică o orientare în sensul acelor de ceas a contururilor feţelor din faţă.
În cazul unei suprafeţe închise construită din poligoane cu o anumită orientare, toate feţele spate nu vor fi vizibile niciodată – ele vor fi ascunse de feţele din faţă ale poligoanelor. În această situaţie se poate mări viteza de afişare prin eliminarea poligoanelor imediat ce s-a determinat dacă ele reprezintă feţe spate. În mod similar dacă suntem în interiorul unui obiect atunci vor fi vizibile numai poligoanele care reprezintă feţele spate. Pentru a specifica eliminarea feţelor faţă, respectiv feţelor spate se va folosi funcţia glCullFace iar activarea eliminării feţelor respective se va face folosind funcţia glEnable având ca parametru GL_ CULL_FACE. Pentru dezactivare se va apela glDisable cu acelaşi argument.
void glCullFace(GLenum mode);
Funcţia indică ce poligoane vor fi eliminate înainte de a fi convertite în coordonate ecran. Parametrul mode poate avea una din valorile :
-
GL_FRONT : se elimină feţele faţă
-
GL_BACK :se elimină feţele spate
-
GL_FRONT_AND_BACK :se elimină atât feţele faţă cât şi feţele spate.
II.8.3.3. Tipul interiorului
În mod implicit poligoanele cu interiorul plin sunt generate folosind un şablon plin. De asemenea pentru generarea interiorului unui poligon se poate folosi un şablon de 32x32 biţi, care se va specifica folosind funcţia glPolygonStipple.
void glPolygonStipple(const GLubyte *mask);
Funcţia defineşte şablonul curent pentru generarea interiorului poligoanelor. Argumentul mask este un pointer catre un bitmap de 32×32 care este interpretat ca o masca de 0 şi 1. Pixelul din poligon corespunzator valorii 1 din mască va fi afişat.
Folosirea şablonului curent la generarea poligoanelor este activată, respectiv dezactivată, apelând funcţiile glEnable respectiv glDisable cu argumentul GL_POLYGON_STIPPLE.
In programul din fişierul exemplu4.c este exemplificată folosirea şabloanelor pentru generarea interioarelor poligoanelor.
/* exemplu4.c */
#include "glut.h"
void display(void)
{ GLubyte fly[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x80, 0x01, 0xC0, 0x06, 0xC0, 0x03, 0x60,
0x04, 0x60, 0x06, 0x20, 0x04, 0x30, 0x0C, 0x20,
0x04, 0x18, 0x18, 0x20, 0x04, 0x0C, 0x30, 0x20,
0x04, 0x06, 0x60, 0x20, 0x44, 0x03, 0xC0, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x44, 0x01, 0x80, 0x22, 0x44, 0x01, 0x80, 0x22,
0x66, 0x01, 0x80, 0x66, 0x33, 0x01, 0x80, 0xCC,
0x19, 0x81, 0x81, 0x98, 0x0C, 0xC1, 0x83, 0x30,
0x07, 0xe1, 0x87, 0xe0, 0x03, 0x3f, 0xfc, 0xc0,
0x03, 0x31, 0x8c, 0xc0, 0x03, 0x33, 0xcc, 0xc0,
0x06, 0x64, 0x26, 0x60, 0x0c, 0xcc, 0x33, 0x30,
0x18, 0xcc, 0x33, 0x18, 0x10, 0xc4, 0x23, 0x08,
0x10, 0x63, 0xC6, 0x08, 0x10, 0x30, 0x0c, 0x08,
0x10, 0x18, 0x18, 0x08, 0x10, 0x00, 0x00, 0x08};
GLubyte halftone[] = {
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
glClear (GL_COLOR_BUFFER_BIT);
glColor3f (1.0, 1.0, 1.0);
glRectf (25.0, 25.0, 125.0, 125.0);
glEnable (GL_POLYGON_STIPPLE);
glPolygonStipple (fly);
glRectf (125.0, 25.0, 225.0, 125.0);
glPolygonStipple (halftone);
glRectf (225.0, 25.0, 325.0, 125.0);
glDisable (GL_POLYGON_STIPPLE);
glFlush ();
}
void myinit (void)
{ glClearColor (0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 400.0, -100.0, 300.0, -1.0, 1.0);
}
int main(int argc, char** argv)
{ glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA);
glutInitWindowSize (350, 150);
glutInitWindowPosition (0, 0);
glutCreateWindow (argv[0]);
myinit ();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
In mod implicit, pentru fiecare octet primul bit este considerat bitul cel mai semnificativ, Ordinea biţilor se poate modifica prin apelul funcţiei glPixelStore*().
OpenGL permite desenarea de poligoane convexe, dar în practică apar deseori şi poligoane concave. Pentru a desena poligoane concave, de regulă acestea se descompun în poligoane convexe – de obicei triunghiuri, aşa cum se arată în figura II.7, şi apoi sunt desenate aceste triunghiuri.
Dacă se descompune un poligon în triunghiuri şi se face afişarea triunghiurilor nu se poate folosi functia glPolygonMode pentru a se desena numai laturile poligonului, deoarece laturile triunghiurilor se află în interiorul poligonului. Pentru a rezolva această problema se poate specifica dacă un vârf aparţine sau nu unei muchii de contur prin păstrarea pentru fiecare vârf a unui bit. La afişarea poligonului în modul GL_LINE nu vor fi desenate laturile care nu aparţin muchiilor de contur. În figura II.6 liniile punctate reprezintă laturi false.
F igura II.6. Divizarea unui poligon concav
În mod implicit orice vârf aparţine unei muchii de contur. Acestă convenţie poate fi controlată prin setarea flag-ului de apartenenţă la o muchie de contur cu ajutorul funcţiei glEdgeFlag*. Funcţia se apelează între comenzile glBegin şi glEnd şi acţionează asupra tuturor vârfurilor specificate după apelul sau până la următorul apel al funcţiei glEdgeFlag. Ea se aplică doar vârfurilor care aparţin poligoanelor (GL_POLYGON), triunghiurilor (GL_TRIANGLES) şi patrulaterelor (GL_QUADS). Nu are efect asupra primitivelor de tipurile GL_QUAD_STRIP, GL_TRIANGLE_STRIP şi GL_TRIANGLE_FAN.
void glEdgeFlag(GLboolean flag);
void glEdgeFlagv(const GLboolean *flag);
Dacă flag este GL_TRUE, atunci flag-ul de contur va fi setat la TRUE (valoarea implicită ), şi orice vârf definit în continuare va fi considerat ca aparţinând muchiilor de contur până la un nou apel al funcţiei glEdgeFlag* cu parametrul GL_FALSE.
Exemplu: Marcarea muchiilor de contur ale unui poligon
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_POLYGON);
glEdgeFlag(GL_TRUE);
glVertex3fv(V0);
glEdgeFlag(GL_FALSE);
glVertex3fv(V1);
glEdgeFlag(GL_TRUE);
glVertex3fv(V2);
glEnd();
Efectul acestor instrucţiuni este următorul (figura II.7):
Figura II.7.
II.8.3.5. Vectori normală
Un vector normală este un vector care are orientarea perpendiculară pe o suprafaţă. Pentru o suprafaţă plană este suficientă o singură direcţie perpendiculară, ea fiind aceeaşi pentru orice punct de pe suprafaţă, dar pentru o suprafaţă oarecare direcţia vectorului normală poate diferi pentru fiecare punct. În OpenGL se poate specifica un vector normală pentru fiecare vârf. Vectorii normală pot fi asociaţi numai vârfurilor. Ei sunt necesari în calculul iluminării suprafeţelor aproximate prin reţele poligonale.
Funcţia glNormal* se apelează pentru a specifica normala curentă. Normala curentă va fi asociată tuturor vârfurilor definite în continuare prin apeluri ale funcţiei glVertex*. Dacă fiecare vârf are asociată o normală diferită se va proceda ca în exemplul următor:
glBegin (GL_POLYGON);
glNormal3fv(n0);
glVertex3fv(v0);
glNormal3fv(n1);
glVertex3fv(v1);
glNormal3fv(n2);
glVertex3fv(v2);
glNormal3fv(n3);
glVertex3fv(v3);
glEnd();
void glNormal3{bsidf}(TYPE nx, TYPE ny, TYPE nz);
void glNormal3{bsidf}v(const TYPE *v);
Funcţia glNormal3 setează componentele vectorului « normală curentă » la valoarile (nx,ny,nz), specificate prin parametri.
Versiunea glNormal3*v a acestei funcţii primeşte ca parametru un vector de 3 elemente pentru a specifica normala curentă.
Versiunile b, s şi i scalează liniar valorile parametrilor în domeniul [-1.0,1.0].
Pe o suprafaţă, într-un punct dat, sunt doi vectori perpendiculari având orientări în direcţii opuse. Prin convenţie, normala este acel vector care are direcţia spre exteriorul suprafeţei. Dacă se doreşte folosirea vectorului normală orientat spre interiorul suprafeţei unui obiect se va modifica fiecare vector normală de la (x, y, z) la (-x, -y, -z).
Vectorii normală pot fi specificaţi având orice lungime, dar ei vor trebui normalizaţi înainte de efectuarea calculelor de iluminare. În general, este bine ca vectorii normală să fie furnizaţi normalizaţi. Dacă se specifică vectori normală nenormalizaţi sistemul OpenGL îi poate normaliza în mod automat. Pentru a cere această operaţie se va apela funcţia glEnable având ca parametru GL_NORMALIZE. Implicit este dezactivată normalizarea automată. În unele implementari ale OpenGL-ului normalizarea automată necesită calcule suplimentare care pot reduce performanţele aplicaţiei.
Dostları ilə paylaş: |