OpenGL

Kurz počítačové grafiky

Autor: Jiří Hnídek / jiri.hnidek@tul.cz

Historie OpenGL

  • Firma Silicon Graphics (SGI) v 90. letech
  • Předchůdce knihovna IRIS GL
  • Aplikační programové rozhraní (API) pro akcelerované grafické karty
  • Původně pouze pro IRIX, později dostupná na ostatních UNIXech, Windows i Linuxu
  • Konkurent Direct3D od Microsoftu (polovina 90. let)
  • Specifikaci a vývoj zaštiťuje https://www.khronos.org/
  • Aktuální verze OpenGL: 4.5
  • Pro Web: WebGL, pro přenosná zařízení: OpenGL ES
  • Budoucnost: Vulkan

Základní vlastnosti

  • Akcelerace 2D a 3D grafiky
  • Multiplatformní a nezávislá na použitém: operačním systému, grafickém akcelerátoru, správci oken, atd.
  • Z toho důvodu nemá žádnou podporu pro:
    • Práci s okny
    • Vytváření uživatelského rozhraní
    • Práci s fonty
    • Obsluhu událostí
  • Výše popsané vlastnostmi podporují např.: GLUT nebo GLFW
  • Při absenci grafického akcelerátoru možno použít softwarovou emulaci pomocí Mesa.

Základní vlastnosti - pokračování

  • Knihovna je použitelná téměř v libovolném programovacím rozhraní (C/C++, Java, Python, Fortran, atd.)
  • Standardně dodáván hlavičkový soubor pro C/C++
  • Knihovnu není většinou nutné instalovat. Je součástí ovladačů grafické karty.
  • Definuje vlastní datové typy (př.: GLint, GLdouble, atd.)
  • Chová se jako stavový automat
  • Podporuje vykreslení pouze základních primitiv: bod, úsečka, trojúhelník, polygon, bitmapa, pixmapa.
  • Pro další funkcionalitu nutné použít knihovny: GLU, OpenInventor, atd.

Syntaxe funkcí

glVertex3f(1.0, 0.0, 1.0);
  • Všechny funkce začínají přefixem "gl"
  • Následuje tělo funkce
  • Počet parametrů a typ proměné

Základní primitiva

glBegin(GL_LINES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(1.0, 0.0, 0.0);
glEnd();

Ve funkci glBegin() mohou být následující parametry: GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_POINTS, GL_LINE_LOOP, GL_TRIANLES, GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP, GL_QUADS, GL_QUAD_STRIP, GL_POLYGON

Překlad programu

Pokud píšete program v programovacím jazyku C, tak se program přeloží pomocí:

$ gcc -o app ./main.c -lglut -lGL -lGLU -lm -lX11 -lXmu

Vlastnosti primitiv

Vlastnost pro primitiva lze povolit například takto:

glEnable(GL_LI­NE_SMOOTH);
  • Bod
    • glColor4f(); glPointSize(); GL_PO­INT_SMOOTH
  • Hrana
    • glColor4f(); glLineWidth(); glLineStipple(); GL_LI­NE_SMOOTH
  • Ploška
    • glPolygonMode(); glFrontFace(); glCullFace(); glPolygonStip­ple();

Transformační matice

Nejprve je potřeba říci jakou matici budeme měnit:

glMatrixMode(GLenum mode);
  • Matice mohou být následující:
    • GL_MODELVIEW - transformace objektů a kamery
    • GL_PROJECTION - projekce objektů do kamery
    • GL_TEXTURE - mapování textur
  • Příklady funkcí pro nastavení matic: glLoadIdentity(), glLoadMatrix(), glMultMatrix(), glTran­slate(), glScale() a glRotate()

Display-listy

  • Umožňuje si příkazy zapamatovat na grafické kartě a pak je znovu zavolat.
  • glNewList(i, GL_COMPILE); glEndList(); glCallList(i);
  • Ve srovnání s Vertex Arrays nebo VBO málo efektivní.

Bitmapy a pixmapy

  • Bitmapa: každý pixel uložen pomocí jednoho bitu. Využití: např.: jednoduché rastrové fonty
  • Pixmapa: obrázek s větším počtem barev

Bitmapa

Bitmapu můžeme vykreslit takto:

const GLubyte bitmap[24] = {
	0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
	0xc0, 0x00, 0xff, 0x00, 0xff, 0x00, 0xc0, 0x00,
	0xc0, 0x00, 0xc0, 0x00, 0xff, 0xc0, 0xff, 0xc0
};
glColor3f(1.0, 0.0, 0.0);
glRasterPos2i(100, 100);
glBitmap(10, 12, 0.0f, 0.0f, 0.0f, 0.0f, bitmap);

Pixmapa

Pixmapu je možné vykreslovat v několika barevných módech:

#define PIXMAP_WIDTH    256
#define PIXMAP_HEIGHT   256

unsigned char pixmap[PIXMAP_HEIGHT][PIXMAP_WIDTH][3];
glRasterPos2i(0, 0);
glDrawPixels(
		PIXMAP_WIDTH, PIXMAP_HEIGHT,
		GL_RGB,
		GL_UNSIGNED_BYTE,
		pixmap);

Framebuffer

  • Ve framebufferu je několik bufferů, které se používají pro vytvoření finálního 3D obrazu:
    • Color buffer - barevná informace o fragmentu (většinou dva)
    • Depth buffer - vzdálenost fragmentu od kamery (řeší viditelnost)
    • Stencil buffer - UI, stereo obraz, VR
    • Accumulation buffer - podobný jako color buffer, ale barvy se sčítají (motion blur)
  • Lze vytvářet i uživatelsky definované. Jednotlivé buffery lze zapínat/vypínat.
glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_STENCIL);

Double-buffering

  • Je vhodné při "animaci" do jednoho barevného bufferu vykreslovat a druhý zobrazovat.
  • Zamezuje nepříjemnému problikávání

glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
// Draw scene ...
glFlush();
glutSwapBuffers();

Kamera

  • Kamera může být ortogonální (rovinné promítání) nebo perspektivní
  • Je vhodné využít knihovny GLU

Ortogonální kamera

Nastavení ortogonální kamery je možné provést takto:

glViewport(0, 0, window_width, window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-20, 20, -20, 20, -30, 30);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(5.0, 5.0, 20.0,	// Position of camera
          0.0, 0.0,  0.0,	// LookAt point
          0.0, 0.0,  1.0);	// Direction UP

Perspektivní kamera

Nastavení perspektivní kamery:

float fov = 70.0; // Field of View
float near_plane = 0.1;
float far_plane = 100.0;

glViewport(0, 0, window_width, window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fov,
	(double)window_width/(double)window_height,
	near_plane, far_plane);

Vertex Arrays

  • Snižuje množství volání API při velkém množství vykreslovaných elementů:
  • Efektivnější jak display listy
static GLint vertices[]={
	0, 0, 0,
	1, 0, 0,
	1, 1, 0
	0, 1, 0
}
int i;
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_INT, 0, vertices);
glBegin(GL_QUADS);
    for (i=0; i<4; i++)
        glArrayElement(i);
glEnd();

VBO

  • Vertex Buffer Objects
  • Data (vertexy) se nahrají do paměti grafického akcelerátoru optimálně pouze jednou
  • Zobrazovaná data jsou v jednoduchém případě statická
  • I jednoduchý příklad se nevejde na jeden slajd.

Mlha

  • Jednoduchá simulace mlhy s konstantní hustotou (žádná objemová data)
  • GLfloat fog_color[4] = {0.5, 0.5, 0.5, 1.0};
    glEnable(GL_FOG);
    glFogi(GL_FOG_MODE, GL_EXP);
    glFogfv(GL_FOG_COLOR, fog_color);
    glFogf(GL_FOG_DENSITY, 0.1);
    glHint(GL_FOG_HINT, GL_DONT_CARE);
    glFogf(GL_FOG_START, 1.0);
    glFogf(GL_FOG_END, 10.0);
    

Světla

  • OpenGL v základu podporuje pouze bodové zdroje světla a reflektor
GLfloat light_position[] = {100.0, 100.0, 100.0, 1.0};
GLfloat light_direction[] = {-1, -1, -1};
GLfloat light_color[] = {1.0, 1.f, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, light_direction);
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 7);	// Spot angle
glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 0.5f);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);
glEnable(GL_LIGHTING); // Enable ligthing in the scen
glEnable(GL_LIGHT0); // Enable light

Phongův osvětlovací model

  • Defaultní osvětlovací model v OpenGL
  • Je potřeba před vykreslením objektů nastavit použitý materiál:

GLfloat material_ambient[] = {0.6, 0.6, 0.6, 1.0};
GLfloat material_diffuse[] = {0.8, 0.4, 0.4, 1.0};
GLfloat material_specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat material_shininess[] = {50.0};
glMaterialfv(GL_FRONT, GL_AMBIENT, material_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, material_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, material_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, material_shininess);

Texturování

  • Texturu je nutné načíst z externího souboru nebo vygenerovat a nastavit pár parametrů
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
             TEXTURE_WIDTH, TEXTURE_HEIGHT,
             0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glEnable(GL_TEXTURE_2D);

Textura UV souřadnice

glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f); glVertex2i(100, 100);
	glTexCoord2f(1.0f, 0.0f); glVertex2i(300, 100);
	glTexCoord2f(1.0f, 1.0f); glVertex2i(300, 300);
	glTexCoord2f(0.0f, 1.0f); glVertex2i(100, 300);
glEnd();

Reference

Děkuji za pozornost