Ugrás a tartalomhoz

3D megjelenítési technikák

Dr. Fekete Róbert Tamás, Dr. Tamás Péter, Dr. Antal Ákos, Décsei-Paróczi Annamária (2014)

BME-MOGI

Az OpenGL Használata

Az OpenGL Használata

Az Open GL rendszert használhatjuk klasszikus módon, illetve az egy a felhasználást könnyítő könyvtárral.

Az OpenGL klasszikus inicializálása

Az OpenGL rendszer API függvényeit az OpenGL32.lib, a glu32.lib, a gdi32.lib és a User32.lib könyvtárak tartalmazzák. A könyvtárakat be kell építeni programunkba (Project Properties/ Configuration Properties/ Linker/ Input/ Additional Dependencies = openGL32.lib glu32.lib gdi32.lib User32.lib $(NoInherit)) eléréséhez be kell építenünk program stdafx.h-ba a kapcsolódó deklarációs állományokat:

#include <windows.h>
#include <winuser.h>
#include <GL/gl.h>
#include <GL/glu.h>

A fenti könyvtárak és fejállományok beépítése a projektünkbe lehetővé teszi, hogy használjuk a rendszer konstansait, típusait és függvényeit.

Az OpenGL eszközkapcsolata

Az OpenGL pixeles eszközökön működik. Első lépésben definiálnunk kell, hogy mely lehetőségeit szeretnénk használni a raszteres eszköznek. Ha ezt megtettük, informálódni kell arról, hogy az aktuális konfiguráció mit támogat az igényeink közül. Az így meghatározott lehetőségek alapján OpenGL-eszközkapcsolatot építhetünk, és kezdhetjük a geometriai modellezést. Ha már nincs szükségünk az OpenGL-eszközkapcsolatra, töröljük annak adatait.

A használni kívánt megjelenítési kapcsolat meghatározása

A Windows API (Application Programming Interface) függvényei az objektumokat számokkal azonosítják. Ezeket a számokat leírónak (handle) hívjuk. Az ablakok leírója a HWND típus (Handle of WiNdoW). Hasonlóan a grafikus eszközök rajzlapjainak objektumát egy számmal azonosíthatjuk HDC típus (Handle of Device Context). Az API rajzoló függvényeket is használhatjuk ezekkel az azonosítókkal. A .NET rendszerben az objektumok Handle tulajdonsága tartalmazza a leírókat.

Az alábbi példa a HWND típusú hwnd változóba lekéri az ablakleírót, majd a GetDC() API függvénnyel lekéri az ablak rajzlapjának leíróját, és a HDC típusú m_hDC változóba helyezi.

HWND hwnd=(HWND)this->Handle.ToInt32();
HDC m_hDC = GetDC(hwnd);

PictureBox-ba is rajzolhatunk, csak akkor a PictureBox ablakleírójával kell dolgoznunk.

hwnd=(HWND)pictureBox1->Handle.ToInt32();
m_hDC = GetDC(hwnd);

A pixelformátum meghatározása

Az OpenGL használatához meg kell határozzuk, hogyan használjuk a pixeleket. A pixelformátum megadásához a PIXELFORMATDESCRIPTOR struktúrát alkalmazhatjuk. A struktúra adattagjaival előírhatjuk, miként szeretnénk használni a grafikus hardver lehetőségeit. Beállíthatjuk a takartvonalas ábrázolásra, a színezésre, a pufferek használatára vonatkozó igényeinket. A pixelformátum struktúra definíciója:

typedef struct tagPIXELFORMATDESCRIPTOR { // pfd 
    WORD  nSize;
    WORD  nVersion;
    DWORD dwFlags;
    BYTE  iPixelType;
    BYTE  cColorBits;
    BYTE  cRedBits;   
    BYTE  cRedShift;  
    BYTE  cGreenBits;  
    BYTE  cGreenShift; 
    BYTE  cBlueBits; 
    BYTE  cBlueShift;
    BYTE  cAlphaBits; 
    BYTE  cAlphaShift;
    BYTE  cAccumBits;
    BYTE  cAccumRedBits;
    BYTE  cAccumGreenBits;
    BYTE  cAccumBlueBits;
    BYTE  cAccumAlphaBits;
    BYTE  cDepthBits; 
    BYTE  cStencilBits;
    BYTE  cAuxBuffers;
    BYTE  iLayerType; 
    BYTE  bReserved;
    DWORD dwLayerMask;
    DWORD dwVisibleMask;
    DWORD dwDamageMask;
} PIXELFORMATDESCRIPTOR;

A struktúra egyes adattagjait a Windows nem használja, a támogatott adattagok az alábbiak:

nSize

A struktúra mérete sizeof(PIXELFORMATDESCRIPTOR)

nVersion

Ennek értéke 1 kell legyen.

dwFlags

A megadott konstansokat bitenkénti vagy (|) művelettel adjuk meg. Néhány jól használható beállítás:

PFD_DRAW_TO_WINDOW

Akkor használjuk a konstanst, ha azt szeretnénk, hogy ablakban jelenjen meg a rajz. Alkalmazhatjuk még a PFD_DRAW_TO_BITMAP konstanst is.

PFD_SUPPORT_OPENGL

Az OpenGL lehetőségeit használjuk, egyébként PFD_SUPPORT_GDI.

PFD_DOUBLEBUFFER

Több puffert alkalmazva a képeket cserélgethetjük (pl. animáció).

iPixelType

PFD_TYPE_RGBA

RGBA színmegadás

PFD_TYPE_COLORINDEX

Színmegadás palettaindexszel

cColorBits

Színdefiniáló bitek száma.

cAcumBits

A speciális tárolópuffer színdefiniáló bitjeinek száma.

cDepthBits

A Z-puffer bitjeinek száma.

cStencilBits

A stencilpuffer bitjeinek száma.

iLayerType

PFD_MAIN_PLANE

Rajzolás az alap fóliára.

PFD_OVERLAY_PLANE

Rajzolás a felső fóliára

PFD_UNDERLAY_PLANE

Rajzolás az alsó fóliára

Ha az adatokat a struktúrában rögzítettük, akkor a ChoosePixelFormat() függvény hívásával lekérdezhetjük a sorszámát annak a pixelformátumnak, amelyet OpenGL-eszközkapcsolatunk a igényeinkhez legjobban illeszkedőnek talál, és támogat. Ezt a sorszámot használjuk majd az OpenGL eszközkapcsolat megteremtéséhez:

int ChoosePixelFormat( HDC hdc,
CONST PIXELFORMATDESCRIPTOR * ppfd );

A hdc paraméter az eszközkapcsolat-leíró, a ppfd a formátumdefiniáló struktúrára mutató pointer. A függvény sikeres választás esetén 0-tól különböző értékkel tér vissza.

A kiválasztott pixelformátum tényleges adatai lekérdezhetők a DescribePixelFormat() függvénnyel.

int WINAPI DescribePixelFormat( HDC hdc, int iPixelFormat,
    UINT nBytes,
    LPPIXELFORMATDESCRIPTOR ppfd);

a hdc az eszközkapcsolat leíró, megadhatjuk a kiválasztott pixelformátumot iPixelFormat, az nBytes a ppfd által mutatott struktúra mérete. A visszatérési érték az adott eszközkapcsolaton használható formátumok száma.

Ha megvan a legközelebbi pixelformátum, akkor azt a

bool SetPixelFormat(HDC hdc, int iPixelFormat,
                    PIXELFORMATDESCRIPTOR * ppfd)

függvénnyel állíthatjuk be egy hDC-re. A hdc az eszközkapcsolat leíró, az iPixelFormat egész a meghatározott legközelebbi pixelformátum, a ppfdPIXELFORMATDESCRIPTOR-ra mutató pointer.

A megjelenítési kapcsolat létrehozása, kiválasztása és törlése

A

HGLRC wglCreateContext(HDC hdc);

függvény segítségével, az eszközkapcsolat-leírót felhasználva létrehozhatunk OpenGL megjelenítési kapcsolatokat (HGLRC típusú Handle of GLRendering Context):

A

BOOL wglMakeCurrent( HDC hdc, HGLRC  hglrc);

függvénnyel, melynek paraméterei az eszköz- és megjelenítési kapcsolat, beállíthatjuk azt, hogy az esetlegesen több megjelenítési kapcsolat közül melyik legyen az aktuális. Ha sikerrel jártunk, a visszatérési érték igaz.

Az aktuális beállítások lekérdezésére a HGLRC típusú  wglGetCurrentContext() és a HDC típusú wglGetCurrentDC() függvényeket használhatjuk.

Az adott programszál megjelenítési kapcsolatának felszabadításához először meg kell szüntetnünk a kapcsolat kiválasztott állapotát, a wglMakeCurrent(0, 0); hívással, majd törölhetjük azt a

BOOL wglDeleteContext ( HGLRC hglrc);

függvénnyel, melynek visszatérési értéke a törlés sikerességét jelzi.

Az alábbi példa MySetPixelFormat() függvénye a hdc eszközkapcsolattal beállítja az m_hglrc megjelenítési kapcsolatot.

HDC m_hDC;
HWND hwnd;
HGLRC m_hglrc;
GLint MySetSetPixelFormat(HDC hdc) {
static PIXELFORMATDESCRIPTOR pfd= {
sizeof(PIXELFORMATDESCRIPTOR),// méret
        1,                    // verzió
        PFD_DRAW_TO_WINDOW |        // ablakba
        PFD_SUPPORT_OPENGL |        // OpenGL
        PFD_DOUBLEBUFFER,            // Dupla puffer
        PFD_TYPE_RGBA,            // Színmodell
        32,                    // Színmélység
        0, 0, 0, 0, 0, 0,            // Color Bits Ignored
        0,                    // Nincs alfa
        0,                    // Nincs eltolás bit
        0,                    // Nincs akkumulátorpuffer
        0, 0, 0, 0,                // Akku bitek nincsenek
        32,                    // 32Bit Z-puffer
        0,                    // Nincs stencilpuffer
        0,                    // Nincs Auxpuffer
        PFD_MAIN_PLANE,            // Rajz a fősíkra
        0,                    // Foglalt
        0, 0, 0                // Nincsenek Layer mMaszkok
    }; GLint  iPixelFormat;
    if((iPixelFormat = ChoosePixelFormat(hdc, &pfd)) == 0) {
        MessageBox::Show("ChoosePixelFormat nem OK");
        return 0;
    }
    if(SetPixelFormat(hdc, iPixelFormat, &pfd) == FALSE) {
        MessageBox::Show("SetPixelFormat nem OK ");
        return 0;
    }
    if((m_hglrc = wglCreateContext(m_hDC)) == NULL) {
        MessageBox::Show("wglCreateContext nem OK ");
        return 0;
    }
    if((wglMakeCurrent(m_hDC, m_hglrc)) == NULL) {
        MessageBox::Show("wglMakeCurrent nem OK ");
        return 0;
    }
    return 1;
}

A megjelenítési kapcsolat felépítése a Load eseményben:

private: System::Void Form1_Load(System::Object^  sender,
System::EventArgs^  e) {
hwnd=(HWND)this->Handle.ToInt32();
    m_hDC = GetDC(hwnd);
    if(m_hDC) {
        MySetPixelFormat(m_hDC);
    }
}

A megjelenítési kapcsolat megszüntetése a FormClosing eseményben:

private: System::Void Form1_FormClosing(System::Object^  sender,
            System::Windows::Forms::FormClosingEventArgs^  e) {
        wglMakeCurrent(0, 0);
        wglDeleteContext(m_hglrc);
        ReleaseDC(m_hDC);
}