2009. szeptember 27., vasárnap

OpenGL - A NAGY Bevezetés


Azoknak akik C# nyelven kívánnak OpenGL-ezni, van egy rossz hírem. Hivatalosan nincsen OpenGL támogatás menedzselt környezetben, de még DirectX sem! Ezt el kell fogadni, de nem kell beletörődni…

De mi is az OpenGL?

Az OpenGL (Open Graphics Library) egy szabvány specifikáció, ami több nyelven és több platformon elérhető API-t (Application Programming Interface) definiál, két- és háromdimenziós grafikai programok írásához. Ez az interfész több mint 250 különböző függvényhívást tartalmaz, melyek segítségével komplex háromdimenziós jeleneteket rajzolhatunk egyszerű primitívekből.


Az OpenGL-t (kezdetben még IrisGL) a Silicon Graphics Inc. (SGI) nevű amerikai cég fejlesztette ki, eredetileg saját grafikus munkaállomásainak programozására. Az SGI munkaállomások közismert előnye a gyors és igényes grafika volt, amit hardver oldalról a grafikus kártyába épített egy vagy több geometriai társprocesszor (geometry engine) segítségével értek el. A koncepció rövid idő alatt olyan sikeressé vált, hogy a legnagyobb hardver- és szoftvergyártó cégek – többek között a DEC, IBM, Intel, Microsoft és Silicon Graphics – összefogásával létrehozták az OpenGL-t amely segítségével az SGI megoldásai más rendszerekre is átültethetővé vált.
Az első OpenGL specifikációt 1992 július 1-én mutatták be. Öt nappal később, a legelső Win32 fejlesztői konferencián az SGI az OpenGL működését egy Iris Indigo gépen demonstrálta több grafikus alkalmazáson keresztül, mint pl. orvosi képfeldolgozó rendszerek, ill. részletek a Terminator 2 című filmből. Ezek után az SGI és a Microsoft együtt fejlesztették tovább az OpenGL-t.
Az OpenGL nem más, mint egy szoftver interfész a grafikus hardverhez. Vagyis a hardvernek (grafikus kártyának) tudnia kell beszélnie az OpenGL nyelvét. A gyakorlatban ez annyit jelent, hogy a 3D videokártya meghajtó programja megfelelően fel van telepítve, azaz képes az OpenGL utasításait feldolgozni. Itt jegyezném meg, hogy tulajdonképpen nincs is olyan, hogy „OpenGL könyvtár” a specifikáció csak és kizárólag az interfészt definiálja, éppen ezért minden hardvergyártónak saját OpenGL megvalósítása van, ezért az elérhető sebesség is nagyban függ az éppen használt videokártyától és annak meghajtójától. Tehát az OpenGL egy szoftverinterfész a grafikus hardverhez. Ez a szoftver interfész pár száz eljárásból és függvényből áll, melyek lehetővé teszik 2 és 3 dimenziós grafikai objektumok létrehozását, és ezeken az objektumokon műveletek elvégzését.
Az OpenGL tehát egy eljárás- és függvénygyűjtemény, melyek 2 és 3 dimenziós geometriai objektumok specifikációját tartalmazzák ezenkívül olyan eszközöket is nyújt, melyekkel szabályozni lehet ezen objektumok leképezését a képpufferbe, amelyben az OpenGL az eredményként létrejövő képet tárolja. Ennek megjelenítése már az operációs rendszer, vagy az ahhoz tartozó ablakozó rendszer feladata.
Az OpenGL nem tartalmaz ablakozó rendszert, és nem támogatja az input eszközök kezelését sem, mivel az OpenGL platformfüggetlenségét az adatbeviteli és megjelenítési rendszertől való függetlenség biztosítja. Ezeket a feladatokat az adott nyelven a programozónak kell megoldania. A Linux-os OpenGL rendszerek grafikus felülete többnyire az X-Window, amely tartalmazza az ablakozást. Windows esetén maga az operációs rendszer szolgáltatja a grafikus felületet.
Az OpenGL az ügyfél-kiszolgáló (kliens-szerver) felépítést követi. Ezáltal lehetővé válik, hogy a grafikus alkalmazást futtató, és a végeredményt létrehozó gép egyazon, vagy két különböző gép legyen. A grafikus alkalmazás – mint ügyfél – parancsokat ad az OpenGL kiszolgálónak, amely létrehozza a képet. Mivel a parancsok átadására szabványos protokollt dolgoztak ki, ezért az ügyfél és a kiszolgáló gépek különböző típusúak is lehetnek.

OpenGL menedzselt környezetben

Ahhoz, hogy az OpenGL által rögzített interfészt kényelmesen tudjuk kezelni, első lépéséként össze kell kötnünk az OpenGL-t a .NET rendszerrel. Vagyis létre kell hoznunk egy olyan osztályt ami kapcsolatot teremt az OpenGL függvényeket tartalmazó opengl32.dll és a .NET rendszer között. Ehhez kapcsolódni kell az InteropServices névtérhez. Az opengl32.dll-t be kell importálni a [DllImport("opengl32")] hívással, majd külső (extern) függvényként deklarálni kell a felhasználandó függvényt. Az OpenGL könyvtár függvényeinek használatához tehát három lépést kell megtenni:
  1. A DllImport attribútumnak meg kell mondani annak a DLL fájlnak a nevét amit használni kívánunk.
  2. A könyvtárban lévő függvényt a fordító számára deklarálni kell, ebben az extern kulcsszó segít. A függvényeket egyúttal statikusnak is kell jelölni.
  3. A System.Runtime.InteropServices névteret kell használni.
Az osztály egyik lehetséges felépítése a következő lehet:
 using System;
 using System.Runtime.InteropServices;
 namespace OpenGL
 {
   public static class gl
   {
     public const uint     GL_ACCUM=0x0100;
     public const uint     GL_LOAD=0x0101;
     …
     [DllImport("opengl32",EntryPoint ="glAccum")]
     public static extern void glAccum(uint op, float valuex);
     [DllImport("opengl32",EntryPoint ="glAlphaFunc")]
     public static extern void glAlphaFunc(uint func, float refx);
     …
   }
 }
Már csak egy kérdés maradt hátra, hogy honnan tudjuk meg a függvények betöltéséhez szükséges definíciókat? Az OpenGL-hez sok helyről le lehet tölteni az információkat tartalmazó header fájlt. Így az OpenGL függvények leírását a gl.h fájlban találjuk meg. A fenti példának megfelelő leírás a header fájlban:
#define GL_ACCUM 0x0100
#define GL_LOAD  0x0101
…
/*************************************************************/
WINGDIAPI void APIENTRY glAccum (GLenum op, GLfloat value);
WINGDIAPI void APIENTRY glAlphaFunc (GLenum func, GLclampf ref);
…
Az OpenGL szabványos függvényei mellet célszerű az extension-ök menedzselését is megoldani. Az OpenGL-be implementált és opcionálisan támogatott funkciókat hívják röviden extension-nek. A glext.h fájl tartalmazza az egyes extension-ök betöltéséhez szükséges definíciókat. A fenti gl osztály tulajdonképpen magába burkolja a natív kódot és kényelmesen elérhetővé teszi, minta csak menedzselt kódban íródott volna egész. Ezért az ilyen típusú osztályokat wrapper-nek nevezzük. Azért, hogy a több száz OpenGL függvényt, konstanst és extension-t ne magunknak kelljen „beburkolnunk”, felhasználhatunk már kész OpenGL wrapper-t és framework-őt C# nyelven:
  1. Tao Framework v2.1 (May 1, 2008)
    http://www.taoframework.com/
  2. Open Toolkit v0.9.9 (Sep 6, 2009)
    http://www.opentk.com
  3. CsGL v1.4.1 (Nov 3, 2002) by Lloyd Dupont, Randy Ridge and Amir Ghezelbash
    http://csgl.sourceforge.net/
  4. C# OpenGL Interface (CSGL) v12 (Jul 25, 2009) by Colin Fahey
    http://www.colinfahey.com/csharp_wrapper_for_opengl/csharp_wrapper_for_opengl_en.html
  5. WOGL Sharp (beta) v1.00.09 (Jan 27, 2008) by Wiktor K. & Mark T.
    http://sourceforge.net/projects/wogl-sharp/files/
A felsorolás valószínűleg nem teljes, de az egyszerűbb megvalósításoktól a teljes keretrendszerekig találhatunk megoldásokat az OpenGL használatára C# nyelven. Így mindenki kiválaszthatja a számára legmegfelelőbb wrapper-t.
A TAO Framework (cross-platform system) egy apró projektből nőtte ki magát az évek alatt. Mára már egy jelentős open-source keretrendszerré vált, amely folyamatosan fejlődik. Elsődleges célja az OpenGL-el kapcsolatos API-k használatának lehetővé tételét .NET alatt. A keretrendszer tartalmazza az összes kiterjesztést. Röviden a szolgáltatásairól: OpenGL, OpenAL (audio), SDL, Open Dynamics Engine (ODE), stb. Ezenfelül támogatja a Windows mellett a Linux és Mac OSX platformokat is. Valamint jelentős internetes közösséggel rendelkezik. A legjobb választás komolyabb alkalmazások készítéséhez.
Az OpenTK (Open ToolKit) erősen a TAO alapjain nyugszik, a fő különbség a két megoldás között az, hogy míg a TAO amennyire csak lehetséges követi a natív API-t, addig az OpenTK megpróbálja kihasználni a menedzselt környezet előnyeit és így kényelmesebb fejlesztést tesz lehetővé. A következő forráskódrész jól szemlélteti a wrapper-ek közötti különbségeket:
// OpenTK.Graphics code:
GL.Begin(BeginMode.Points);
GL.Color3(Color.Yellow);
GL.Vertex3(Vector3.Up);
GL.End();
// Tao.OpenGl code:
Gl.glBegin(Gl.GL_POINTS);
Gl.glColor3ub(255, 255, 0);
Gl.glVertex3f(0, 1, 0);
Gl.glEnd();
Kisebb programok estében jól jöhet egy jóval egyszerűbb és átláthatóbb interfész az OpenGL függvények eléréséhez. Erre kiválóan alkalmas a C# Wrapper for OpenGL ami Colin Fahey keze munkáját dicséri. A szolgáltatásai terén nem érdemes párhuzamot vonni a nagy wrapper-ekkel, mivel a Tao és az OpenTK messze kimagaslik minden területen. A fő előnye mégis az egyszerűsége és nagyszerűsége. Ezért esett kezdésként a választásunk erre a megoldásra. A későbbiekben az OpenTK használata is bemutatásra fog kerülni. Folytatás következik…

0 megjegyzés :

Megjegyzés küldése