Západočeská univerzita v Plzni Západočeská univerzita v Plzni Fakulta Fakulta aplikovaných aplikovaných věd věd Katedra informatiky a výpočetní techniky
BAKALÁŘSKÁ PRÁCE
Plzeň, 2007
Jan Tichava
Západočeská univerzita v Plzni Západočeská univerzita v Plzni Fakulta aplikovaných věd Fakulta aplikovaných věd Katedra informatiky a výpočetní techniky Katedra informatiky a výpočetní techniky
Bakalářská práce OpenGL v Javě
Plzeň, 2007 Plzeň, 2007
Jan Tichava Jan Tichava
Abstract OpenGL in Java This bachelor thesis investigates and describes possible connection of Java and OpenGL via different bindings. Java OpenGL (JOGL) was chosen as a main Java binding for the OpenGL API. In this thesis the installation procedure and system requirements of JOGL are described. The second practical part begins with a tutorial which describes solving several basic problems of computer graphics in JOGL. The tutorial is followed by comparison of advantages and disadvantages of using JOGL according to DirectX and C#. For comparing were written two similar 3D Mazes. At the end of this thesis there is confrontation of these two technologies from different points of view, such as installation, user friendliness and especially OpenGL in Java versus DirectX in C#.
iii
Obsah 1
Úvod............................................................................................................................ 1 1.1 Cíl bakalářské práce................................................................................................ 2 1.2 Struktura dokumentu............................................................................................... 2
Teoretická část
3
2
Možnosti OpenGL v Javě ........................................................................................... 4 2.1 Úvod........................................................................................................................ 4 2.2 Propojení Javy a OpenGL....................................................................................... 4 2.2.1 GL4Java ........................................................................................................... 4 2.2.2 Lightweight Java Game Library (LWJGL) ..................................................... 5 2.2.3 Java OpenGL (JOGL) ...................................................................................... 5 2.2.4 Java 3D ............................................................................................................ 6 2.3 Rozšiřující knihovny pro OpenGL v Javě .............................................................. 6 2.3.1 jMonkey Engine............................................................................................... 6 2.3.2 Xith3D ............................................................................................................. 6 2.3.3 Java is Doomed................................................................................................ 7
3
JOGL – Java OpenGL................................................................................................. 8 3.1 Úvod........................................................................................................................ 8 3.2 Požadavky na systém .............................................................................................. 8 3.3 Instalace .................................................................................................................. 9 3.4 Provoz aplikace bez nainstalovaného JOGL ........................................................ 10
Realizační část 4
11
Základní techniky v JOGL........................................................................................ 12 4.1 Úvod...................................................................................................................... 12 4.2 Vykreslení trojúhelníku pomocí OpenGL ............................................................ 12 4.2.1 Třída Lesson .................................................................................................. 13 4.2.2 Třída Renderer ............................................................................................... 14 4.3 Rotující jehlan....................................................................................................... 18 4.3.1 Třída Renderer ............................................................................................... 18 4.4 Textury na krychli, použití kláves ........................................................................ 20 4.4.1 Třída Renderer ............................................................................................... 20 4.5 Světla .................................................................................................................... 26 4.5.1 Třída Renderer ............................................................................................... 26 4.6 Text a 2D grafika .................................................................................................. 29 4.6.1 Třída Renderer ............................................................................................... 30
iv
5
3D Bludiště ............................................................................................................... 32 5.1 Zadání ................................................................................................................... 32 5.1.1 Formát vstupního souboru s mapou............................................................... 34 5.2 Popis řešení ........................................................................................................... 34 5.2.1 Detekce kolizí ................................................................................................ 34 5.2.2 Popis tříd a metod .......................................................................................... 35 5.3 Implementované vlastnosti ................................................................................... 38 5.3.1 Textury........................................................................................................... 38 5.3.2 Modely ........................................................................................................... 38 5.3.3 Sběr předmětů ................................................................................................ 39 5.3.4 Teleport .......................................................................................................... 39 5.3.4 Osvětlení ........................................................................................................ 39 5.3.5 Dynamika hráče ............................................................................................. 40 5.3.6 Konzole.......................................................................................................... 40 5.4 Uživatelská dokumentace ..................................................................................... 41 5.4.1 Systémové požadavky a spuštění................................................................... 41 5.4.2 Ovládání......................................................................................................... 41 5.5 Shrnutí................................................................................................................... 41
6
Porovnání OpenGL a DirectX .................................................................................. 42 6.1 OpenGL ................................................................................................................ 42 6.2 DirectX.................................................................................................................. 42 6.3 OpenGL vs. DirectX ............................................................................................. 43 6.3.1 Instalace vývojového prostředí ...................................................................... 43 6.3.2 Práce s IDE .................................................................................................... 44 6.3.3 Java a C#........................................................................................................ 44 6.3.4 Implementační rozdíly OpenGL a DirectX ................................................... 44 6.3.5 Výkon............................................................................................................. 46 6.3.6 Zatížení procesoru, využití paměti RAM a grafické paměti.......................... 47 6.3.7 Rychlost vývoje aplikací................................................................................ 47
7
Závěr ......................................................................................................................... 48 7.1 Shrnutí možností propojení Javy a OpenGL......................................................... 48 7.2 Zhodnocení ukázkové aplikace............................................................................. 48
Použité zkratky ............................................................................................................... 51 Literatura......................................................................................................................... 53
v
Seznam obrázků Obrázek 1 Obrázek 2 Obrázek 3 Obrázek 4 Obrázek 5 Obrázek 6 Obrázek 7 Obrázek 8 Obrázek 9 Obrázek 10 Obrázek 11 Obrázek 12 Obrázek 13 Obrázek 14 Obrázek 15 Obrázek 16 Obrázek 17 Obrázek 18 Obrázek 19 Obrázek 20 Obrázek 21 Obrázek 22 Obrázek 23 Obrázek 24 Obrázek 25
: Struktura archívu jogl-1.1.0-rc1-windows-i586.zip .................................. 9 : Adresářová struktura................................................................................ 10 : Výsledný trojúhelník ............................................................................... 13 : Náhledy možností kreslení ...................................................................... 15 : Pohledová pyramida ................................................................................ 17 : Rotující jehlan.......................................................................................... 18 : Body na jehlanu ....................................................................................... 19 : Krychle s texturou.................................................................................... 20 : Pořadí bodů, texturovací souřadnice a mapování textury........................ 21 : Body na krychli........................................................................................ 22 : Osvětlená krychle .................................................................................... 26 : Srovnání GL_SMOOTH a GL_FLAT stínování ..................................... 28 : Drátěný model ......................................................................................... 28 : Text a otexturovaný čtverec..................................................................... 29 : Pohled do výsledného bludiště ................................................................ 32 : Mapa a pole pravdivostních hodnot......................................................... 34 : Rozdělení čtverce..................................................................................... 35 : Animovaná textura................................................................................... 38 : Předmět ke sběru...................................................................................... 39 : Teleport.................................................................................................... 39 : Světlo ....................................................................................................... 39 : Konzole.................................................................................................... 40 : Souřadné systémy .................................................................................... 45 : Porovnání aplikací v DirectX (vlevo) a OpenGL (vpravo) ..................... 49 : Identická bludiště v DirectX (vlevo) a OpenGL (vpravo)....................... 50
vi
Seznam tabulek Tabulka 1 Tabulka 2 Tabulka 3 Tabulka 4
: Popis možností kreslení .............................................................................. 15 : Tabulka řezů písma..................................................................................... 31 : Parametry bludiště ...................................................................................... 33 : Tabulka znaků............................................................................................. 34
vii
Prohlášení Prohlašuji, že jsem bakalářskou práci vypracoval samostatně a výhradně s použitím citovaných pramenů.
V Plzni dne 17. května 2007
Jan Tichava
viii
Poděkování Touto cestou bych rád poděkoval všem, kteří mi pomáhali s přípravou práce nebo mě jakkoli podporovali během jejího vytváření. Zejména pak chci poděkovat vedoucí mé bakalářské práce Ing. Janě Hájkové za podnětné rady, čas strávený konzultacemi a její trpělivost. V neposlední řadě bych rád poděkoval všem svým přátelům a kamarádům za jejich připomínky a náměty.
ix
Kapitola 1 Úvod V dřívějších dobách byla 3D grafika výsadou bohatých grafických studií, která měla finance na nákup drahého hardwarového a softwarového vybavení svých kanceláří a vytvářela nejrůznější efekty pro filmová studia. Postupem času se výkon „obyčejných“ počítačů zvyšoval a 3D grafika se začala pomalu protlačovat i do domácností, hlavně v oblasti počítačových her. Legendou se stala hra Doom, kterou v roce 1993 uvedla firma id Software. Hra byla naprogramovaná v jazyce C. V té době ještě nebyla Java ani na světě, natož, aby se v ní programovaly 3D hry. První verze Javy[13], JDK verze 1.0 byla uvedena v lednu 1996. Java byla v té době úplně nový programovací jazyk, který měl mnoho nedostatků. Tyto nedostatky se začaly projevovat až při jejím používání. Před 11 lety byly také mnohem méně výkonné počítače a vzhledem k tomu, že Java je interpretovaný jazyk, byly aplikace v Javě velice pomalé. První verze Javy byly dvacetkrát až čtyřicetkrát pomalejší než stejný algoritmus naprogramovaný v C/C++. Java se samozřejmě vyvíjela až do dnešní verze 1.6, která je plnohodnotným soupeřem C/C++. Některé algoritmy jsou v Javě dokonce i rychlejší než v těchto jazycích. Tohoto zrychlení bylo docíleno zdokonalením překladače. Od verze 1.3 byla implementována technologie HotSpot, která umožňuje překladači nalézt takové části kódu, které jsou náročné na výpočetní výkon procesoru a pak je přeložit se silným důrazem na výkon. HotSpot má také negativní vedlejší efekt, po spuštění je program pomalejší, protože detekce náročných míst v programu vyžaduje také výpočetní výkon od procesoru. Grafické karty u běžných domácích počítačů disponují velkým výkonem, který vyžadují převážně nové počítačové hry. Při běžné práci není grafická karta plně využita, protože pracuje pouze ve 2D režimu. Výrobci softwaru vytvářejí i obyčejné programy s 3D prostředím, aby využily celý potenciál grafické karty. Někdy je takový program prakticky nepoužitelný, jako například souborový manažer, který přiřadí diskům patra budovy a dveře jsou jednotlivé adresáře. Rychlá práce se soubory na disku není v tomto programu skutečně možná. Jiným případem je přímo prostředí operačního systému, které je postaveno na 3D – ať jde o Aero od Microsoftu v nových Windows Vista nebo XGL na Linuxu. Otázkou zůstává, zda je toto nové prostředí k něčemu praktickému užitečné nebo je to pouze nové lákadlo na zákazníky.
1
1.1 Cíl bakalářské práce Jedním z cílů bakalářské práce bylo seznámit se s různými možnostmi propojení Javy a OpenGL, vybrat si jednu z metod, nastudovat její možnosti a vytvořit jednoduchý návod k použití základních prvků, které se používají ve 3D grafice. Dalším cílem bylo naprogramovat, s použitím vybrané metody mapování OpenGL do Javy, podobné 3D Bludiště, které jsme programovali v předmětu KIV/ZPG jako semestrální práci. V ZPG se využívá prostředí .NET, jazyk C# a DirectX pro 3D svět. Úkolem bylo popsat a porovnat obě konkurenční technologie.
1.2 Struktura dokumentu Celý dokument je rozdělen následovně: 1. Úvod Začíná obecným úvodem do celé problematiky a struktury celé bakalářské práce. 2. Teoretická část Zde jsou rozebrány možnosti použití 3D grafiky v Javě, převážně se jedná o OpenGL. Popisují se rozšiřující knihovny a do detailu se zachází u vybrané technologie na propojení Javy a OpenGL. 3. Realizační část Obsahuje manuál k použití základních technik OpenGL v Javě s pomocí JOGL. Následuje popis řešení 3D Bludiště a končí vzájemným srovnáním DirectX v C# a OpenGL v Javě s využitím JOGL. 4. Závěr Ve stručnosti hodnotí jednotlivé metody propojení Javy a OpenGL. Srovnává 3D Bludiště v Javě a DirectX z jiné perspektivy a končí malým zamyšlením nad vývojem komerčních her v Javě.
2
Část I Teoretická část
3
Kapitola 2 Možnosti OpenGL v Javě
2.1 Úvod Existuje více možností spojení Javy a OpenGL. Některá řešení jsou skutečně pouze na propojení Javy s OpenGL. Jiná jsou komplexní balíky, které umožňují práci se zvukem, herním hardwarem a usnadňují práci s texturami, modely a podobně. V první části kapitoly ve stručnosti představím čtyři vybrané vazby Javy na OpenGL, kde Java 3D je komplexní balík různých pomocných tříd a ostatní tři jsou „jen“ více či méně obsáhlá propojení. S rozšiřujícími knihovnami pro OpenGL se seznámíme ve druhé části kapitoly. Knihovny slouží k tomu, aby programátor nemusel vyvíjet a testovat algoritmy, které jsou často používané; jako je například načítání modelů, textur, řešení kolizí mezi objekty a podobně. Andrew Davison se ve svých několika knihách[1][2][3] zmiňuje i o existujících vazbách na konkrétní herní systémy. Zaujal mě projekt Jake2[12], jehož autoři přepsali celý herní engine Quake 2 do Javy. Na grafiku používá JOGL nebo LWJGL, na 3D zvuk JOAL. Webové stránky projektu prezentují srovnání původního kódu v C s novým kódem v Javě. Zajímavé je, že výkon v počtu FPS je přibližně stejný. Podobných vazeb na herní systémy je mnohem více, namátkou Auriga3D[4] vychází z Quake 3, ale uvádím je pouze pro doplnění, dále se o nich již nebudu zmiňovat.
2.2 Propojení Javy a OpenGL 2.2.1 GL4Java GL4Java[10] je jedna ze starších vazeb Javy a OpenGL. Poslední verze byla vydána v prosinci 2001. Ve své době patřila k nejpopulárnějším, ale byla vytlačena modernějším JOGL (viz níže v kapitole 2.2.3).
4
Podporuje OpenGL verze 1.3 a GLU verze 1.2. Je možné ji použít ve spojení s knihovnami AWT a Swing. OpenGL funkce jsou volány přes Java Native Interface, proto je výkon aplikace limitován rychlostí hostitelského systému. Vychází z původního OpenGL, které známe z C. V rámci Javy musí být samozřejmě objektový, ale stavba GL4Java je strukturální. Pro programátory OpenGL v C nebude velkým problémem naučit se v GL4Java. GL4Java je open source projekt, který je distribuován pod všeobecnou veřejnou licencí GNU[11].
2.2.2 Lightweight Java Game Library (LWJGL) Lightweight Java Game Library[27] je řešení, které je určené pro profesionální i amatérské programátory. Umožňuje programovat kvalitní komerční hry v Javě. LWJGL poskytuje vývojářům přístup k výkonným multiplatformním knihovnám pro OpenGL a OpenAL, které umožňují vytvářet 3D hry spolu s 3D zvukem. LWJGL navíc podporuje game pady, volanty, joysticky a další herní zařízení. Používání LWJGL automaticky neznamená snadné psaní 3D her v Javě. Jeho hlavním účelem je zpřístupnit vývojářům všechny potřebné prostředky pro vývoj. Začátkem ledna 2007 vyšla po několika letech finální stabilní verze 1.0. Byla vytvořena s důrazem na výkon, jednoduchost, přenositelnost, bezpečnost a robustnost. Autoři LWJGL předpokládají použití na rozmanitých platformách – od telefonů, přes běžné počítače až po velké renderovací servery. LWJGL se drží osvědčeného návrhu. OpenGL funkce z C jsou mapovány do Javy stejným způsobem jako v JOGL. LWJGL je velice podobný JOGL, ale na rozdíl od něj neumísťuje canvas na swing komponentu, ale vytváří vlastní okno. Na internetu je možné najít NeHe tutoriály, které byly portovány také do LWJGL a ke stažení je několik her, které jsou napsány v Javě a LWJGL. Některé z nich jsou pouze trial verze a prodávají se za poměrně vysoké ceny.
2.2.3 Java OpenGL (JOGL) Java OpenGL[15] je jedna z nejnovějších vazeb Javy na OpenGL, kterou propaguje skupina Game Technologies Group od firmy Sun. Nabízí podobné možnosti jako LWJGL, ale liší se v tom, že JOGL je integrován do knihoven AWT a Swing. Aplikační rozhraní JOGL se stane referenční vazbou Javy na OpenGL vyvíjené jako součást specifikačního procesu JSR 231[18] společností Sun. Z JSR 231 se tak stane oficiální vazba Javy na OpenGL. JOGL přistupuje na funkce OpenGL z jazyka C pomocí volání Java Native Interface. Autoři se nesnažili přepracovat celé rozhraní do objektově orientovaného. Ve skutečnosti je velká část zdrojového kódu JOGL automaticky vygenerována z hlavičkových souborů OpenGL jazyka C pomocí nástroje Gluegen[9].
5
Tento návrh má své výhody i nevýhody. Nevýhodou je, že struktura metod, které souvisejí s JOGL je jiná, než všech ostatních metod v aplikaci. Na druhou stranu, je jednodušší na naučení pro toho, kdo zná OpenGL z jazyka C. Také je jednodušší pro autory JOGL, protože není nutné vymýšlet novou strukturu a využívají již zaběhnutý a léty ověřený soubor metod.
2.2.4 Java 3D Java 3D[14] není jen obyčejná vazba mezi Javou a OpenGL, ale celá sada různých podpůrných tříd, které by si programátor ve výše uvedených způsobech použití OpenGL v Javě musel sám naprogramovat. Java 3D má vlastně velice podobnou myšlenku jako DirectX. Obsahuje metody pro načítání obrázků, práci se zvukem a sprity. Při vývoji složitějších aplikací je možné využít integrovaných metod pro načítání a práci s modely nebo metody pro různé způsoby komunikace po síti. Při využití knihovny Java 3D si programátor na Windows dokonce může vybrat, jestli chce použít OpenGL nebo DirectX.
2.3 Rozšiřující knihovny pro OpenGL v Javě 2.3.1 jMonkey Engine jMonkey Engine[17] je výkonný systém, jehož autoři se inspirovali knihou 3D Game Engine Design od Davida Eberlyho. Pro renderování scén využívá LWJGL, ale v budoucnu autoři plánují i JOGL. Kromě základních věcí obsahuje podporu pro multitexturing, bumpmapping a třeba i detekce kolizí. Jednoduše lze používat látku (oblečení), částicové systémy, stíny nebo efekt vody. Umožňuje načítat modely v následujících formátech: ASE, 3DS, MD2, Milkshape, OBJ a COLLADA. jME je plně open source projekt, který je distribuován pod BSD[26] licencí. Je volně k použití pro zábavu i pro komerční aplikace.
2.3.2 Xith3D Aplikační rozhraní Xith3D[29] je velice podobné Java 3D. Ovšem Xith3D je koncipován tak, aby mohl pracovat nad libovolným rozhraním, podle výběru programátora. Nyní je možné volit mezi JOGL a LWJGL.
6
Xith3D umí přímo volat funkce rozhraní OpenGL, proto je možné implementovat vlastní shadery. Jeho další vlastnosti jsou podobné s jME. Namátkou například podporuje ASE, 3DS, OBJ, MD3, MD2, AC3D, COLLADA jako formáty modelů nebo také obsahuje systém řešení kolizí. Xith3D je také šířen pod BSD[26] licencí.
2.3.3 Java is Doomed Java is Doomed[16] je malý open source 3D engine implementovaný na JOGL. Umožňuje načítat modely ve formátu MD2 a 3DS. Využití nalezne v případě, když programátor nechce nebo nemůže použít jeden z výše uvedených balíků. V archívu s knihovnou je přiložena i FPS(2) hra Escape, která se inspirovala v legendární hře Doom.
7
Kapitola 3 JOGL – Java OpenGL
3.1 Úvod JOGL jsem si vybral jako hlavní vazbu mezi Javou a OpenGL, ve které budu vytvářet ukázky řešení základních problémů v grafice a pak 3D Bludiště pro srovnávání OpenGL v Javě a DirectX v C#. Základní vlastnosti a popis JOGL byl zmíněn již v kapitole 2.2.3, kde jsem rozebíral jednotlivé možnosti propojení Javy a OpenGL. JOGL jsem si vybral jako hlavní prostředek 3D, protože mě zaujala blízká podobnost s klasickým OpenGL. Přístup musí být samozřejmě objektový, ale autoři funkce z OpenGL pouze přemapovali na metody v jedné třídě. Pro OpenGL je na internetu k nalezení obrovské množství různých návodů, tutoriálů a rad. Oblíbené NeHe tutoriály[5][20] jsou vytvořené pro jazyk C, ale i pro JOGL jsou velice užitečné. Ne všechno lze ovšem bez problémů použít v Javě. Dokonce i návody přímo pro JOGL není možné vždy použít, protože JOGL prošel bouřlivým vývojem a co platilo například v roce 2003, již není aktuální. Principy však zůstávají shodné. Podstatné je také dlouhodobější existence stabilní verze a plánované začlenění JOGL do Javy, jako oficiální vazby OpenGL v Javě, viz JSR 231.
3.2 Požadavky na systém JOGL pro svůj běh vyžaduje operační systémem Linux, MacOS, Solaris nebo Windows. Počítač by měl být dostatečně výkonný pro provoz Javy verze 1.4.2 a vyšší. Další nároky na software a hardware jsou pak závislé na konkrétní aplikaci. U jednoduchých 3D scén bude stačit obyčejná grafická karta, která hardwarově podporuje pouze OpenGL 1.2. Náročné aplikace mohou vyžadovat hardwarovou podporu OpenGL verze 2.
8
V ideálním případě by měl být aktualizovaný operační systém, nainstalovány nejnovější ovladače pro grafickou kartu. Totéž platí o Javě, JOGL a případně i o dalších používaných rozšiřujících třídách, jakou může být například OpenAL.
3.3 Instalace Nejprve je potřeba nainstalovat JDK[13], které je zdarma ke stažení z webových stránek firmy Sun Microsystems. K dispozici jsou 32 a 64 bitové verze Javy 1.6 pro Windows, Linux a Solaris a Java verze 1.5 pro MacOS. V následujícím textu předpokládám instalaci JDK a JRE verze 1.6 do standardních adresářů, které nabízí instalátor jako výchozí. Po instalaci je vhodné provést restart počítače nebo alespoň odhlásit a opět přihlásit uživatele, aby se projevily změny, které provedl instalátor v systémových proměnných. Pokud je Java správně nainstalovaná, můžeme pokračovat v instalaci JOGL[15]. Nejnovější verze je k dispozici ke stažení na domovských stránkách JOGL v části „Documents & files“, aktuální verzi naleznete po rozbalení nabídky „Release Builds 2007 (0)“. Pro provoz na vlastním počítači je potřeba stáhnout knihovny pouze pro vlastní operační systém, pro distribuci je výhodné přibalit knihovny alespoň pro Linux a Windows.
Obrázek 1: Struktura archívu jogl-1.1.0-rc1-windows-i586.zip
Archív pro operační systém Windows bude mít podobnou strukturu, jakou je možno vidět na obrázku 1. Důležitý je adresář lib, který obsahuje všechny potřebné knihovny pro provoz aplikací. Tyto knihovny je nutno rozbalit do následujících adresářů, případně do obdobných na jiných operačních systémech. C:\Program Files\Java\jre1.6.0\lib\ext\ C:\Program Files\Java\jdk1.6.0\lib\ext\ C:\Program Files\Java\jdk1.6.0\jre\lib\ext\
9
Další možností je rozbalit JOGL do libovolného adresáře na disku a přidat do systémové proměnné CLASSPATH cestu ke zvolenému umístění. Po editaci je nutné odhlásit a přihlásit uživatele, aby se změny projevily. Po provedení výše uvedených kroků bude možné používat JOGL jako součást Javy a nebude nutné složitě specifikovat cesty ke knihovnám. Knihovny budou k dispozici v Eclipse, který bude třídy a metody z JOGL knihoven zobrazovat v rozbalovacích nabídkách.
3.4 Provoz aplikace bez nainstalovaného JOGL Ne vždy je možné použít postup, který je uvedený v kapitole 3.3. Na počítači, ke kterému nemá uživatel administrátorské oprávnění, pravděpodobně nebude možné zapisovat do adresáře, kde je nainstalovaná Java. I na takových počítačích je možné provozovat aplikace, které využívají JOGL. Program spustíme níže uvedeným příkazem java -Djava.library.path=./win_lib/ -jar Aplikace.jar Knihovny musí být v tomto případě v adresáři win_lib. Na stejné úrovni jako podadresář win_lib je i soubor Aplikace.jar, ve kterém je rozbalený obsah jogl.jar. Adresářová struktura je znázorněná na obrázku 2.
Obrázek 2: Adresářová struktura
Potřebné DLL knihovny je také možné umístit přímo do adresáře, kde je Aplikace.jar, pak není nutné používat parametr –D a definovat cestu ke knihovnám, protože si aplikace najde soubory sama. Z důvodu přehlednosti je však lepší umístit knihovny do vlastního adresáře.
10
Část II Realizační část
11
Kapitola 4 Základní techniky v JOGL 4.1 Úvod Následujících pět kapitol je lehkým úvodem do OpenGL v Javě s využitím JOGL. Začneme ukázkou, jak se vytvoří OpenGL okno a do něj se nakreslí trojúhelník, který má každý vrchol jiné barvy. Na tento jednoduchý úvod navážeme rotujícím jehlanem. Další kapitola je o trochu více složitá, obsahuje načítání obrázku z disku jako textury pro krychli. Přidáním světla do scény se zabývá další kapitola. V předposlední kapitole se čtenář dozví, jak napsat na obrazovku text a zobrazit 2D obrázek. Myšlenka následujících lekcí je stejná jako v NeHe[5][20] tutoriálech. Ty jsou určeny hlavně pro jazyk C, pro který jsou dokonale zdokumentovány. Existují i porty do mnoha různých jiných jazyků, včetně Javy a JOGL, ale ne všechny jsou aktuální. Některé využívají ještě GLDrawable, který byl nahrazen vylepšeným GLAutoDrawable a zdrojové kódy je potřeba upravit, aby je bylo možné přeložit a spustit. Obecně lze napsat, že všechny porty NeHe tutoriálů do JOGL mají špatnou dokumentaci, pokud vůbec nějakou mají. OpenGL v podání JOGL se od OpenGL, které známe z jazyka C, příliš neliší, ale některé metody, byly upraveny a v porovnání s funkcemi v C, mají například jiný počet parametrů.
4.2 Vykreslení trojúhelníku pomocí OpenGL V této kapitole vykreslíme barevný trojúhelník pomocí OpenGL v Javě s využitím JOGL. Budeme potřebovat Javu ve verzi 1.5 a vyšší a JOGL ve verzi 1.1 a vyšší. Programovat je možné v libovolném textovém editoru, ale s ohledem na budoucí ukázky je výhodnější použít Eclipse[4] nebo podobný IDE, protože doplní automaticky potřebné importy apod. Pro bezproblémovou přenositelnost mezi platformami je výhodné používat UTF-8 pro kódování všech souborů, pokud chceme používat české popisky.
12
Program se skládá ze dvou tříd. Klientská třída Lesson je společná pro všechny kapitoly. Mění se pouze titulek okna. Pomocí této třídy se spouští celý program, obsahuje metodu main(). Druhou třídou je Renderer, která definuje výslednou vyrenderovanou scénu a v tomto příkladu navíc ještě obsluhuje stisky kláves. Po spuštění níže uvedeného kódu uvidíte okno, jako je na obrázku 3.
Obrázek 3: Výsledný trojúhelník
4.2.1 Třída Lesson Obsahuje statickou metodu main(), vytváří swingový JFrame, na který je umístěn canvas (kreslící plátno pro OpenGL renderování) a spouští Animator, aby se automaticky překreslovala scéna. public class Lesson extends JFrame { GLCanvas canvas = new GLCanvas(); Animator animator = new Animator(); public static void main(String[] args) { new Lesson(); } public Lesson() { canvas.addGLEventListener(new Renderer()); animator.add(canvas); this.getContentPane().add(canvas); this.setTitle("Lekce 1: Vytvoření OpenGL okna"); this.setSize(640, 480); this.setLocationRelativeTo(null);
13
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); animator.start(); canvas.requestFocus(); } }
4.2.2 Třída Renderer Implementuje GLEventListener pro řešení událostí OpenGL a KeyListener pro obsluhu stisků kláves. V této třídě je definována celá scéna, která se renderuje. Metoda display() definuje co, je bude vykreslovat a je automaticky volána třídou Animator1, ostatní metody slouží k nastavení scény. Importujeme GL, což je základní rozhraní pro zpřístupnění funkcí z OpenGL verze 2.0. GLAutoDrawable vychází z GLDrawable, který slouží k renderování scén, ale podporuje vykreslování pomocí událostí, což přispívá k vyššímu výkonu. GLU se využívá k nastavení pohledu. public class Renderer implements GLEventListener, KeyListener { private GLU glu = new GLU(); private GL gl;
Metodu display() volá Animator pro zobrazení každého framu, definuje se tu celá scéna, která se má vykreslovat. V této kapitole se smaže obrazovka s hloubkovým bufferem, resetuje matice a posune se scéna o –2,75 ve směru osy Z (do hloubky). Posunutí je nutné, protože rovina znear je ve vzdálenosti 1 a trojúhelník by nebyl zobrazen, viz níže. public void display(GLAutoDrawable gLDrawable) { gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); gl.glTranslatef(0f, 0.0f, -2.75f);
Na začátku vykreslování si volíme, jaké útvary chceme kreslit. Na výběr máme z několika základních geometrických útvarů, které jsou zobrazeny na obrázku 4 a popsány v tabulce 1. Na první pohled jde pouze o 2D útvary, ale souřadnice každého vrcholu obsahují i složku Z.
1
Viz třída Lesson
14
GL_POINTS
GL_LINES
GL_LINE_STRIP
GL_LINE_LOOP
GL_TRIANGLES
GL_TRAINGLE_STRIP
GL_TRAINGLE_FAN
GL_QUADS
GL_QUAD_STRIP
GL_POLYGON Obrázek 4: Náhledy možností kreslení
GL_POINTS GL_LINES GL_LINE_STRIP GL_LINE_LOOP
Každý vertex je reprezentovaný jako samostatný bod. Každý pár po sobě jdoucích vertexů definuje úsečku. Spojí po sobě jdoucí vertexy v lomenou čáru. Stejně jako GL_LINE_STRIP spojuje po sobě jdoucí vertexy, ale navíc ještě spojí první a poslední bod. GL_TRIANGLES Každá trojice po sobě jdoucích vertexů definuje trojúhelník. GL_TRIANGLE_STRIP První tři vertexy definují jeden trojúhelník, každý další bod definuje nový trojúhelník s využitím předchozích dvou vertexů jako vrcholy. GL_TRIANGLE_FAN Podobně jako GL_TRIANGLE_STRIP, všechny trojúhelníky využívají první vertex jako jeden svůj vrchol, druhý vrchol je předchozí vrchol. GL_QUADS Každá čtveřice vertexů definuje čtyřúhelník. GL_QUAD_STRIP První čtyři vertexy definují jeden čtyřúhelník a každé další dva vertexy definují nový čtyřúhelník, který využívá předchozí dva vertexy. GL_POLYGON Jako GL_LINE_LOOP, ale s vyplněnou plochou. Tabulka 1: Popis možností kreslení
Na začátku vykreslování nastavíme kreslení trojúhelníků pomocí GL_TRIANGLES. Pak pro každý bod specifikujeme barvu vrcholu a jeho souřadnici v prostoru. Barva je reprezentována jako třísložkový vektor, kde jednotlivé složky odpovídají červené,
15
zelené a modré barvě. Hodnoty jsou v intervalu <0; 1>. Souřadnice bodu v prostoru jsou reprezentovány obvyklým způsobem (X, Y, Z). Kreslení se nesmí zapomenout ukončit. gl.glBegin(GL.GL_TRIANGLES); gl.glColor3d(1.0, 0.0, 0.0); gl.glVertex3f(0.0f, 1.0f, 0.0f); gl.glColor3d(0.0, 1.0, 0.0); gl.glVertex3f(-1.0f, -1.0f, 0.0f); gl.glColor3d(0.0, 0.0, 1.0); gl.glVertex3f(1.0f, -1.0f, 0.0f); gl.glEnd(); }
Metoda displayChanged() není nyní v JOGL implementována. V budoucnu se bude volat při změně barevné hloubky nebo připojení dalšího monitoru, atd. Metodu je nutné implementovat, protože je definována v rozhraní GLEventListener. public void displayChanged(GLAutoDrawable gLDrawable, boolean modeChanged, boolean deviceChanged) { }
Metoda init() se volá bezprostředně po vytvoření OpenGL okna, je vhodná pro nastavení základních parametrů vykreslování apod. V této kapitole se vytváří přístup k OpenGL, nastavuje barva pozadí (černá) a přidává třída, která bude obsluhovat stisky kláves. Barva pozadí je reprezentována jako čtyřsložkový vektor, kde první tři hodnoty určují barvu a čtvrtá hodnota určuje průhlednost, u barvy pozadí na nastavení průhlednosti nezáleží. public void init(GLAutoDrawable gLDrawable) { this.gl = gLDrawable.getGL(); gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); gLDrawable.addKeyListener(this); }
Metoda reshape() je zavolána při změně velikosti okna a při prvním vykreslením, protože je nutné, aby se nastavil perspektivní pohled podle aktuální velikosti okna. public void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height) { if (height <= 0) height = 1; final float h = (float)width / (float)height; gl.glViewport(0, 0, width, height);
Matice GL_PROJECTION ovlivňuje jak výrazná bude perspektiva, tj. jak moc se budou vzdálenější objekty zmenšovat. Metodou gluPerspective se nastavuje pohledová pyramida (viz obrázek 5), která v tomto případě svírá úhel 45°, závisí na výšce a šířce okna, ořezávací rovina znear je ve vzdálenosti 1 a zfar 20 na ose Z. Hodnota znear by
16
neměla nabývat 0, protože pak se mohou vyskytnout z důvodu zaokrouhlovacích chyb problémy s viditelností. Přepnutí na matici GL_MODELVIEW oznamuje, že forma pohledu bude změněna, glLoadIdentity opět resetuje matici. gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(45.0f, h, 1.0, 20.0); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); }
Plocha okna, do kterého se vykresluje zfar znear
Výška v pixelech α
Šířka v pixelech Obrázek 5: Pohledová pyramida
Metoda keyPressed() je zavolána, když uživatel stiskne klávesu. Pokud stiskne Escape, aplikace se ukončí. Metody keyReleased() a keyTyped() jsou prázdné, ale musí být implementovány, aby byla implementace korektní. public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) System.exit(0); } public void keyReleased(KeyEvent e) {} public void keyTyped(KeyEvent e) {} }
17
4.3 Rotující jehlan V této kapitole vytvoříme prostorový útvar, který bude rotovat okolo své svislé osy. Využijeme kód z kapitoly 4.2, kde jsme vytvořili trojúhelník. Klientská třída Lesson se nemění. Po spuštění níže uvedeného kódu uvidíte okno, jako je na obrázku 6.
Obrázek 6: Rotující jehlan
4.3.1 Třída Renderer Všechny metody, kromě níže uvedených, zůstávají shodné s metodami z kapitoly 4.2. Části kódu, které se nezměnily, jsou napsány šedou barvou. Z metody display() odstraníme část kódu, která zobrazovala trojúhelník a nahradíme ho novým kódem, který vykresluje jehlan. Navíc přidáme jednoduchou rotaci okolo osy Y. Aby bylo možné rotovat okolo osy, přibyl jeden nový atribut třídy, který ukládá ve stupních celkový úhel, o který byl jehlan otočen. private float rotate = 0;
Scénou otáčíme pomocí metody glRotatef(úhel, x, y, z), kde souřadnice x, y, z udávají směr osy, okolo které se otáčí. Souřadnice tří vrcholů byly nahrazeny dvanácti vrcholy jehlanu. Chceme-li každému vrcholu přiřadit jinou barvu, je nutné ji uvést. Na závěr inkrementujeme hodnotu proměnné rotate, ve které je uložen úhel,
18
o který je jehlan otočený. Pro zjednodušení je rychlost otáčení závislá na výkonu grafické karty. Ve zdrojovém kódu v textu je uvedena pouze jedna stěna jehlanu, která je znázorněna na obrázku 7, zbylé tři stěny mají pouze jiné souřadnice vrcholů, viz zdrojový kód na přiloženém CD. public void display(GLAutoDrawable gLDrawable) { gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); gl.glTranslatef(0f, 0.0f, -2.75f); gl.glRotatef(rotate, 0.0f, 1.0f, 0.0f); gl.glBegin(GL.GL_TRIANGLES); gl.glColor3f(1.0f, 0.0f, 0.0f); gl.glVertex3f(0.0f, 1.0f, 0.0f); gl.glColor3f(0.0f, 1.0f, 0.0f);
bod A
gl.glVertex3f(-1.0f, -1.0f, 1.0f); gl.glColor3f(0.0f, 0.0f, 1.0f);
bod B
gl.glVertex3f(1.0f, -1.0f, 1.0f);
bod C
A
. . . gl.glEnd(); rotate += 0.2; }
Obrázek 7: Body na jehlanu
B
C Obrázek 7: Body na jehlanu
Protože vykreslujeme prostorové útvary, je potřeba zapnout testování na hloubku, aby bylo zajištěno, že bližší objekty překryjí vzdálenější. Pak se nastaví typ hloubkového vykreslování. Pro běžné vykreslování se používá GL_LESS nebo GL_LEQUAL, bližší objekty jsou překryty vzdálenějšími. Nakonec nastavíme korekci perspektivy. Při zanedbatelném snížení výkonu dosáhneme lepšího vzhledu celé scény. public void init(GLAutoDrawable gLDrawable) { this.gl = gLDrawable.getGL(); gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(GL.GL_LEQUAL); gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); gLDrawable.addKeyListener(this); }
19
4.4 Textury na krychli, použití kláves S využitím kódu z předchozí kapitoly si ukážeme, jak načítat a používat textury. Výsledná krychle bude mít na všech šesti stěnách stejnou texturu. Otexturovat každou stěnu je obdobné a dosažitelné jednoduchou modifikací. Klientská třída Lesson, kterou naleznete v kapitole 4.2, je stále stejná. Jako bonus je implementováno jednoduché řízení rychlostí otáčení kolem všech os, pomocí kláves ←, →, ↓, ↑, PageDown, PageUp. Po spuštění níže uvedeného kódu uvidíte okno, jako je na obrázku 8.
Obrázek 8: Krychle s texturou
4.4.1 Třída Renderer Všechny metody, kromě níže uvedených, zůstávají shodné s metodami z kapitoly 4.3. Části kódu, které se nezměnily jsou napsány šedou barvou. V metodě display() nahradíme téměř celý kód. Místo jehlanu budeme vykreslovat krychli a naučíme se používat texturovací souřadnice. Do metody init() doplníme kód pro zapnutí textur. Nakonec vytvoříme úplně nové metody a jednu privátní třídu pro načítání textur. Do třídy keyPressed() doplníme reakce na stisky potřebných kláves. Je nutné upozornit, že z důvodu kompatibility musí být rozměry textur mocniny 2 a nejméně 64 a nejvíce 256 pixelů. V případě použití textury o jiných rozměrech, může program příliš vytěžovat systém a počet FPS klesne až na 0 nebo nepůjde vůbec spustit.
20
Celkově nyní potřebujeme již importovat 14 tříd, pro načítání obrázků, obsluhu OpenGL a podobně. Při programování v Eclipse se doplní automaticky, popřípadě v menu Source je příkaz Organize Imports, který doplní vše potřebné. Kromě standardních atributů pro GL a GLU vytvoříme dvě konstanty, kde uložíme název souboru s texturou a počet textur, které budeme načítat. Důležité je celočíselné pole textur, ve kterém bude textura uložena. Zbylé atributy jsou pouze pro rotaci krychle v prostoru. Hodnota rotateX je celkový úhel otočení okolo osy X, deltaX je krok, o který se krychle otočí v každém framu, pro osy Y a Z jsou zbylé čtyři proměnné. private final String textureFile = "lesson03/textures/texture.png"; private final int texturesCount = 1; private float rotateX = 0; private float rotateY = 0; private float rotateZ = 0; private float deltaX = 0.05f; private float deltaY = 0.1f; private float deltaZ = 0.2f; private int[] texture = new int[texturesCount]; private GLU glu = new GLU(); private GL gl;
Krychli je možné vykreslit pomocí dvanácti trojúhelníků podle předchozí kapitoly, ale je jednodušší na začátku vykreslování definovat, že chceme kreslit čtverce. Proto tentokrát použijeme GL_QUADS. Vrcholy se definují stejně jako u trojúhelníku. Ke každému vrcholu se ještě musí uvést texturovací souřadnice. Ty určují, jakým způsobem bude na čtverec textura namapována. Pořadí zadávání bodů a texturovací souřadnice ukazuje obrázek 9. Před zavoláním glBegin() je nutné nastavit aktuální texturu, se kterou chceme pracovat pomocí metody glBindTexture().
4 (0, 0)
(1, 0)
3
1 (0, 1)
(1, 1)
2
Obrázek 9: Pořadí bodů, texturovací souřadnice a mapování textury
public void display(GLAutoDrawable gLDrawable) { gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); gl.glTranslatef(0f, 0.0f, -5f);
21
gl.glRotatef(rotateX, 1.0f, 0.0f, 0.0f); gl.glRotatef(rotateY, 0.0f, 1.0f, 0.0f); gl.glRotatef(rotateZ, 0.0f, 0.0f, 1.0f); gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0]); gl.glBegin(GL.GL_QUADS); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 0.0f);
bod A
gl.glVertex3f(1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 1.0f);
bod B
gl.glVertex3f(1.0f, 1.0f, 1.0f); gl.glTexCoord2f(0.0f, 1.0f);
bod C
gl.glVertex3f(-1.0f, 1.0f, 1.0f);
bod D
. . . gl.glEnd();
D
C
A
B
rotateX += deltaX; rotateY += deltaY; rotateZ += deltaZ; }
Obrázek 10: Body na krychli Obrázek 10: Body na krychli
Do metody init() přidáme volání vlastní metody pro vygenerování textur a pomocí metody glEnable s parametrem GL_TEXTURE_2D je nutné zapnout použití textur. Bez toho by se zobrazila pouze bílá krychle. public void init(GLAutoDrawable gLDrawable) { this.gl = gLDrawable.getGL(); gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f); gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(GL.GL_LEQUAL); gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); gl.glEnable(GL.GL_TEXTURE_2D); generateTextures(); gLDrawable.addKeyListener(this); }
22
V metodě generateTextures() nejprve zavoláme metodu glGenTextures(), které předáme jako parametr, kolik textur chceme generovat, proměnnou, do které se budou ukládat textury a offset textury. Pomocí GL_TEXTURE_2D definujeme, že jde o 2D texturu a pomocí glBindTexture() řekneme, se kterou texturou chceme pracovat. Pak načteme a vytvoříme texturu (viz níže). Poslední dva řádky definují, jaké filtrování se má použít na texturu, pokud je menší (MIN), respektive větší (MAG) než skutečný obrázek, který načítáme ze souboru. Filtr nemusíme použít žádný (GL_NONE), ale textura není na pohled hezká z blízka, protože přes celou obrazovku se zobrazí jen několik málo velkých pixelů z původního obrázku. Další možné filtry jsou GL_NEAREST, GL_LINEAR. Chceme-li použít mipmapping, využíváme kombinací předchozích dvou filtrů, například GL_NEAREST_MIPMAP_NEAREST nebo GL_LINEAR_MIPMAP_NEAREST a podobně. Filtr GL_LINEAR je náročnější na výkon hardware, ale výsledná textura vypadá hezky z blízka i z dálky. Při zvětšení jsou pixely rozmazány, takže nejsou vidět ostré hrany mezi pixely. private void generateTextures() { gl.glGenTextures(texturesCount, texture, 0); gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0]); Texture newTexture = null; try { newTexture = readTexture(textureFile); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } makeRGBTexture(gl, glu, newTexture, GL.GL_TEXTURE_2D); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); }
Metody readTexture(), readImage() a getResourceAsStream() obstarávají správné nalezení souboru s texturou buď v JAR archívu nebo na disku a načtený obrázek předají metodě readPixels(), která zprostředkuje načtení obrázku po jednotlivých pixelech. private Texture readTexture(String filename) throws IOException { BufferedImage bufferedImage = readImage(filename); return readPixels(bufferedImage); } private BufferedImage readImage(String resourceName) throws IOException { return ImageIO.read(getResourceAsStream(resourceName)); }
23
public InputStream getResourceAsStream(final String filename) throws IOException { InputStream stream = ClassLoader.getSystemResourceAsStream(filename); if (stream == null) { return new FileInputStream(filename); } else { return stream; } }
Metoda readPixels() není z pohledu OpenGL zajímavá. Slouží ke čtení jednotlivých pixelů z obrázku, který je uložen jako BufferedImage. Obrázek postupně prochází po jednotlivých pixelech a do ByteBuffer ukládá hodnoty jednotlivých složek RGB pro každou barvu. Vrací objekt Texture. private Texture readPixels(BufferedImage img) { int bytesPerPixel = 3; int[] packedPixels = new int[img.getWidth() * img.getHeight()]; PixelGrabber pixelgrabber = new PixelGrabber(img, 0, 0, img.getWidth(), img.getHeight(), packedPixels, 0, img.getWidth()); try { pixelgrabber.grabPixels(); } catch (InterruptedException e) { throw new RuntimeException(); } ByteBuffer unpackedPixels = BufferUtil.newByteBuffer(packedPixels.length * bytesPerPixel);
for (int row = img.getHeight() - 1; row >= 0; row--) { for (int col = 0; col < img.getWidth(); col++) { int packedPixel = packedPixels[row * img.getWidth() + col]; unpackedPixels.put((byte) ((packedPixel >> 16) & 0xFF)); unpackedPixels.put((byte) ((packedPixel >> 8) & 0xFF)); unpackedPixels.put((byte) ((packedPixel >> 0) & 0xFF)); } }
unpackedPixels.flip(); return new Texture(unpackedPixels, img.getWidth(), img.getHeight()); }
24
Metoda makeRGBTexture() vytváří texturu ve formátu, který se používá při přiřazení textury na objekt. private void makeRGBTexture(GL gl, GLU glu, Texture img, int target) { gl.glTexImage2D(target, 0, GL.GL_RGB, img.getWidth(), img.getHeight(), 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, img.getPixels()); }
Privátní třída Texture, která uchovává informace o vygenerované textuře do doby, než se textura skutečně vytvoří pomocí glTexImage2D() v metodě makeRGBTexture(). Obsahuje výšku, šířku a jednotlivé pixely obrázku. private class Texture { private ByteBuffer pixels; private int width; private int height; public Texture(ByteBuffer pixels, int width, int height) { this.height = height; this.pixels = pixels; this.width = width; } public int getHeight() { return height; } public ByteBuffer getPixels() { return pixels; } public int getWidth() { return width; } }
Po doplnění reakcí na stisky kláves bude možné regulovat rychlost otáčení krychle podle libovolné osy. public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) System.exit(0); if (e.getKeyCode() == KeyEvent.VK_LEFT) deltaX -= 0.05; if (e.getKeyCode() == KeyEvent.VK_RIGHT) deltaX += 0.05;
25
if (e.getKeyCode() == KeyEvent.VK_DOWN) deltaY -= 0.05; if (e.getKeyCode() == KeyEvent.VK_UP) deltaY += 0.05; if (e.getKeyCode() == KeyEvent.VK_PAGE_DOWN) deltaZ -= 0.05; if (e.getKeyCode() == KeyEvent.VK_PAGE_UP) deltaZ += 0.05; }
4.5 Světla Nyní je krychle osvětlována zpředu bílým světlem. Klientská třída Lesson se opět nemění, rozdíly jsou pouze ve třídě Renderer. Klávesou L se zapíná a vypíná světlo. Po spuštění níže uvedeného kódu uvidíte okno, jako je na obrázku 11.
Obrázek 11: Osvětlená krychle
4.5.1 Třída Renderer Všechny metody, kromě níže uvedených, zůstávají shodné s metodami z kapitoly 4.4. Části kódu, které se nezměnily jsou napsány šedou barvou. Při práci se světly je nutné nastavit ambientní světlo, které je všude a zdroj difúzního světla, u kterého je potřeba definovat i jeho polohu. Při inicializaci navíc zapneme
26
jemné stínování, aby byla vyrenderovaná scéna opticky hezká. Nesmí se zapomenout dodefinovat ke každé ploše normálové vektory, aby OpenGL vědělo, jestli je daná plocha osvětlená a pokud ano, tak jakou intenzitou Přidáme čtyři nové atributy, kde nastavíme barvu ambientního světla, barvu a polohu difúzního světla. Proměnná lightingEnabled slouží pro možnost zapínání a vypínání světla. private private private private
float[] float[] float[] boolean
lightAmbient = {0.5f, 0.5f, 0.5f, 1.0f}; lightDiffuse = {1.0f, 1.0f, 1.0f, 1.0f}; lightPosition = {0.0f, 0.0f, 5.0f, 1.0f}; lightingEnabled = true;
Důležité je správně nastavit normálové vektory ke všem plochám pomocí metody glNormal3f(), protože jinak bude světlo počítáno špatně. Normála je kolmý vektor na plochu, která má být osvícena. Kolmice vychází z té strany plochy, která má být osvětlena. public void display(GLAutoDrawable gLDrawable) { gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); gl.glTranslatef(0f, 0.0f, -5f); gl.glRotatef(rotateX, 1.0f, 0.0f, 0.0f); gl.glRotatef(rotateY, 0.0f, 1.0f, 0.0f); gl.glRotatef(rotateZ, 0.0f, 0.0f, 1.0f); if (lightingEnabled) gl.glEnable(GL.GL_LIGHTING); else gl.glDisable(GL.GL_LIGHTING); gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0]); gl.glBegin(GL.GL_QUADS); gl.glNormal3f(0.0f, 0.0f, 1.0f); gl.glTexCoord2f(0.0f, 0.0f); gl.glVertex3f(-1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 0.0f); gl.glVertex3f(1.0f, -1.0f, 1.0f); gl.glTexCoord2f(1.0f, 1.0f); gl.glVertex3f(1.0f, 1.0f, 1.0f); gl.glTexCoord2f(0.0f, 1.0f); gl.glVertex3f(-1.0f, 1.0f, 1.0f); . . . gl.glEnd(); rotateX += deltaX; rotateY += deltaY; rotateZ += deltaZ; }
27
Metoda init() je téměř identická, pouze se nastavuje jemné stínování (GL_SMOOTH) metodou glShadeModel(), další možností stínování je GL_FLAT, které ovšem neinterpoluje hodnoty jasu z jednotlivých vrcholů; viz obrázek 12. Pak je nutné zavolat metodu setLights(), ve které se nastavují světla. Pokud je vyžadován drátěný model, doporučuji vypnout světla a textury. Pak použijeme v této metodě konstrukci gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE). Výsledek je vidět na obrázku 13. public void init(GLAutoDrawable gLDrawable) { this.gl = gLDrawable.getGL(); gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl.glShadeModel(GL.GL_SMOOTH); gl.glEnable(GL.GL_DEPTH_TEST); gl.glDepthFunc(GL.GL_LEQUAL); gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST); gl.glEnable(GL.GL_TEXTURE_2D); generateTextures(); setLights(); gLDrawable.addKeyListener(this); }
Obrázek 12: Srovnání GL_SMOOTH a GL_FLAT stínování
Obrázek 13: Drátěný model
Metoda nastavuje ambientní a difúzní světla, která pak zapne. private void setLights() { gl.glLightfv(GL.GL_LIGHT1, GL.GL_AMBIENT, this.lightAmbient, 0); gl.glLightfv(GL.GL_LIGHT1, GL.GL_DIFFUSE, this.lightDiffuse, 0); gl.glLightfv(GL.GL_LIGHT1, GL.GL_POSITION, this.lightPosition, 0); gl.glEnable(GL.GL_LIGHT1); gl.glEnable(GL.GL_LIGHTING); this.lightingEnabled = true; }
28
Do metody keypressed() byla doplněna obsluha klávesy L. public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) System.exit(0); if (e.getKeyCode() == KeyEvent.VK_LEFT) deltaX -= 0.05; if (e.getKeyCode() == KeyEvent.VK_RIGHT) deltaX += 0.05; if (e.getKeyCode() == KeyEvent.VK_DOWN) deltaY -= 0.05; if (e.getKeyCode() == KeyEvent.VK_UP) deltaY += 0.05; if (e.getKeyCode() == KeyEvent.VK_PAGE_DOWN) deltaZ -= 0.05; if (e.getKeyCode() == KeyEvent.VK_PAGE_UP) deltaZ += 0.05; if (e.getKeyCode() == KeyEvent.VK_L) lightingEnabled = !lightingEnabled; }
4.6 Text a 2D grafika Tutoriál nerozšiřuje předchozí. Ukazuje, jakým způsobem je možné umístit libovolný nápis do OpenGL okna a vytvoření otexturovaného čtverce. Dvourozměrná grafika se často nazývá sprite[24]. Uvedený postup je možné použít na vytvoření nápovědy a podobně. Klientská třída Lesson je stále stejná, pouze dojde k několika úpravám ve třídě Renderer. Po spuštění níže uvedeného kódu uvidíte okno, jako je na obrázku 14.
Obrázek 14: Text a otexturovaný čtverec
29
4.6.1 Třída Renderer Oproti předchozí kapitole byly některé metody odstraněny, protože nejsou na správnou funkci textu a 2D grafiky potřeba. Kompletní zdrojový kód je k dispozici na přiloženém CD. Počet atributů třídy se snížil, ale používáme novou třídu GLUT, která obsahuje potřebné metody pro práci s textem. Všimněte si, že se změnil název souboru s texturou. private final String textureFile = "lesson05/textures/picture.jpg"; private final int texturesCount = 1; private int[] texture = new int[texturesCount]; private GLU glu = new GLU(); private GLUT glut = new GLUT(); private GL gl;
Pro obyčejné psaní textu do okna nejsou některé řádky nezbytně nutné. Vzhledem k tomu, že v budoucnu se bude pravděpodobně text psát přes vyrenderovanou scénu, je vhodné tyto postupy uvést. Na začátku přepneme na matici MODELVIEW a uložíme její stávající podobu, to samé uděláme s maticí PROJECTION. Obě matice nastavíme na jednotkové. Pak nastavíme aktuální pohled a uložíme všechny potřebné OpenGL vlastnosti, které budeme později potřebovat. Vypneme světla a testováni hloubky při vykreslování. public void display(GLAutoDrawable gLDrawable) { gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glPushMatrix(); gl.glLoadIdentity(); gl.glMatrixMode(GL.GL_PROJECTION); gl.glPushMatrix(); gl.glLoadIdentity(); gl.glViewport(0, 0, gLDrawable.getWidth(), gLDrawable.getHeight()); gl.glPushAttrib(GL.GL_ENABLE_BIT); gl.glDisable(GL.GL_LIGHTING); gl.glDisable(GL.GL_DEPTH_TEST);
Uložíme aktuální pohledovou matici (VIEWPORT) a nastavíme pravoúhlou projekci. Následuje zapnutí textur, nastavení textury kterou chceme používat, nastavení barvy čtverce a vykreslení čtverce obdobným způsobem jako v kapitole 4.4. Pouze s tím rozdílem, že není udána souřadnice Z a používáme dvousložkové vektory. IntBuffer viewPort = BufferUtil.newIntBuffer(4); gl.glGetIntegerv(GL.GL_VIEWPORT, viewPort); glu.gluOrtho2D(0, viewPort.get(2), viewPort.get(3), 0); gl.glEnable(GL.GL_TEXTURE_2D);
30
gl.glBindTexture(GL.GL_TEXTURE_2D, texture[0]); gl.glColor3f(1, 1, 1); gl.glBegin(GL.GL_QUADS); gl.glTexCoord2f(0, 0); gl.glVertex2f(10, 250); gl.glTexCoord2f(1, 0); gl.glVertex2f(250, 250); gl.glTexCoord2f(1, 1); gl.glVertex2f(250, 50); gl.glTexCoord2f(0, 1); gl.glVertex2f(10,50); gl.glEnd();
Vypneme textury, nastavíme barvu na žlutou. Pak nastavíme pozici, kam chceme, aby se text zobrazoval a text vypíšeme fontem Helvetica. Žádný z fontů nepodporuje plně češtinu s diakritikou. Řezy fontů a jejich velikosti jsou omezeny, viz tabulka 2. Nakonec obnovíme původní nastavení všech matic. gl.glDisable(GL.GL_TEXTURE_2D); gl.glColor3f(1, 1, 0); gl.glRasterPos2i(20, 40); glut.glutBitmapString(GLUT.BITMAP_HELVETICA_18, "Lekce 5"); gl.glPopAttrib(); gl.glPopMatrix(); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glPopMatrix(); }
Řez písma
Skutečný vzhled
BITMAP_8_BY_13 BITMAP_9_BY_15 BITMAP_HELVETICA_10 BITMAP_HELVETICA_12 BITMAP_HELVETICA_18 BITMAP_TIMES_ROMAN_10 BITMAP_TIMES_ROMAN_24 Tabulka 2: Tabulka řezů písma
31
Kapitola 5 3D Bludiště
Obrázek 15: Pohled do výsledného bludiště
5.1 Zadání Vytvořte jednopatrové bludiště s pravoúhlou sítí kostek. Bludiště by mělo přibližně vypadat jako hra Wolfenstein 3D. Rozložení stěn v bludišti bude dáno mapou načítanou ze souboru. Formát souboru je popsaný v kapitole 5.1.1. Bludištěm bude možné se volně pohybovat. Kolize se stěnou nesmí způsobovat zaseknutí či poskočení. Nesmí být možné opustit mapu i v případě, že na okraji bludiště chybí zeď, která by opuštění bránila. Není možné vstoupit či nahlédnout do zdi.
32
Pozorovatel se pohybuje rovnoměrnou rychlostí vzhledem ke skutečnému času, rychlost tedy není závislá na počtu FPS. Rychlost otáčení pohledu myší je závislá pouze na rychlosti pohybu myší. Pozorovatel se nemůže přetočit, tj. natáčení ve vertikálním směru lze pouze v rozsahu (−90°; +90°), kde 0° je pohled přímo vpřed. Veškeré animace a pohyb pozorovatele jsou závislé na reálném čase, nikoliv na snímkovém kmitočtu, tj. změna doby nutné na zobrazení jednoho snímku nesmí způsobit změnu rychlosti pohybu či animace v zobrazovaném světě. Scéna osvětlena reflektorem ze svítilny držené pozorovatelem ve výšce 2,05 m a směrovém vektoru o depresi 2°. Úhel u kořene kuželu je menší, než je úhel pohledu pozorovatele. Výpočet počtu snímků za předchozí sekundu počínaje aktuálním snímkem, tj. počet předchozích snímků, které se vejdou do okénka o velikosti jedné sekundy. Bludiště je charakterizováno parametry v tabulce 3, kde 1 jednotka = 1 metr.
šířka: hloubka: výška:
2m 2m 3m
výška očí: hmotnost: průměrná rychlost:
1,85 m 95 kg 2,5 m/s
Tabulka 3: Parametry bludiště
Jako rozšíření implementujte načítání a aplikaci textur. Na textury aplikujte různé filtry pro lepší vizuální dojem z výsledné vyrenderované scény. Můžete použít i animované textury. Animace musí být tvořena změnou obrazu, nikoliv například jen posunutím texturovacích souřadnic. Do mapy umístěte předměty. Hráč předměty sbírá a počítá se počet sebraných předmětů, který je zobrazen na obrazovce. Předměty poskakují, točí se na místě, popř. provádějí nějaký jiný zajímavý pohyb. Rychlost pohybu předmětů je nezávislá na snímkovém kmitočtu. Předmětem bude model, který se bude načítat z disku v textovém formátu. Bludiště opatřete zvoleným množstvím teleportů, které slouží k přenesení hráče v mapě z jednoho místa do jiného. Během teleportace bude hráči znemožněno se pohybovat a obraz přejde plynule do celé bílé obrazovky a zpět. Teleporty v bludišti vhodně označte, aby byly snadno rozpoznatelné. Do scény přidejte osvětlení směrovým světlem (slunce, globální osvětlení) produkující phongovo stínování, tj. bez využití vertex/pixel shaderů. Světla v mapě opět vhodně vyznačte. Implementujte jednoduchou dynamiku hráče. Postava se bude při chůzi vpřed a vzad pohupovat a tím bude simulovat kroky. Vytvořte poloprůhlednou konzoli, která bude podobná konzoli ze hry Quake 3. Musí obsahovat minimálně 3 příkazy s dopadem na scénu.
33
5.1.1 Formát vstupního souboru s mapou Formát vstupního souboru s mapou je textový, kde první řádka definuje šířku a výšku bludiště: W×H (např.: 32x40 = 32 sloupců široká a 40 řádků vysoká). Jeden znak je jedna kostka na mapě. Mapa je uložena po řádcích a má W sloupců a H řádek. Význam jednotlivých znaků je pevně stanoven, viz tabulka 4. Není-li v aplikaci daný znak využit, pak je dekódován dle významu skupiny znaků do níž náleží nebo jako volný prostor. Je-li například nalezen znak 'f' (druh zdi) a aplikace nerozlišuje druhy zdí, pak je tento znak považován za zeď podobně jako znaky 'a', 'b', …, 'n'. V případě, že je nalezen znak 'O' (cizí postava) a není řešena úloha Protivník, pak je tento znak interpretován jako volný prostor dle znaku 'o'. Je-li nalezen znak '|' (volné užití), pak je tento interpretován jako volný prostor. znak mezera, 'o' až 'z' '*', 'a' až 'n' 'S' '@' 'A' až 'G' 'H' až 'N' 'O' až 'R' 'T' až 'Z' ASCII 32 až 127
význam volný prostor zeď (obecně neprůchodné pole) startovní pozice pozorovatele, vždy právě jedna světla dveře a vstupy tajných chodeb pevné objekty cizí postavy (protivníci) předměty určené ke sběru volné použití Tabulka 4: Tabulka znaků
5.2 Popis řešení 5.2.1 Detekce kolizí Při řešení kolizí využívám vlastnosti toho, že všechny stěny jsou pravoúhlé a zabírají jeden celý čtverec na mapě. Při načítání mapy se vytvoří pole pravdivostních hodnot, které říká, je-li na daném místě zeď nebo není, viz obrázek 16. Mapa ************** * * P * * *CBAS * * * * * D * * * **************
Zeď 11111111111111 10000100000001 10000100000001 10000100000001 10000000000001 10000000000001 11111111111111
Obrázek 16: Mapa a pole pravdivostních hodnot
34
5.2.1.1 Detekce kolize na „volném prostranství“ Při každém pokusu o pohyb se ještě před přesunem na novou pozici vypočítá cílová souřadnice, kde by se měl hráč objevit. Tato souřadnice v prostoru se přepočítá na souřadnice vzhledem k velikosti čtverců. Pokud na cílové pozici není stěna, hráč je přesunut na novou pozici. Jestliže tam stěna je, bude nová souřadnice upravena tak, aby hráč nevstoupil do stěny. Pohyb ve směru, kde je stěna, bude vynulován a zachován bude pouze pohyb v kolmém směru – v tomto případě bude hráč po stěně klouzat a nedojde k jeho zaseknutí na místě.
5.2.1.2 Popis funkce algoritmu detekce kolize v rozích Každý čtverec je rozdělen na čtyři sub-čtverce, jak je zobrazeno na obrázku 17. V každém sub-čtverci se kontroluje přítomnost stěny pouze v tom čtverci, který přísluší vrcholu sub-čtverce, na němž se hráč nachází. Řešení samotných kolizí funguje stejně jako v kapitole 5.2.1.1. Podle matice pravdivostních hodnot se rozhodne, jestli tam je, či není stěna a jestli bude hráč vpuštěn na novou pozici.
1
2
3
4
Obrázek 17: Rozdělení čtverce
5.2.2 Popis tříd a metod package bludiste Bludiste.java Hlavní třída s metodou main(), přečte parametr příkazové řádky, pokud je –f, spustí se v celoobrazovkovém režimu. Volá třídy, které načítají mapu ze souboru a pak generují souřadnice bodů pro vykreslování čtverců. Ctverec.java Objekt, který reprezentuje jeden čtverec bludiště. Obsahuje vše, co je potřeba později při vykreslování při použití GL_QUADS, konkrétně souřadnice všech čtyř vrcholů, normálu a souřadnice pro textury.
35
GenerovaniBodu.java Generuje souřadnice a z nich skládá čtverce, počítá příslušné normálové vektory. Vygenerované čtverce ukládá do kolekcí, které přísluší logickému celku (podlaha, strop, stěny). KeyboardHandler.java Handler pro zjišťování stisknutých kláves. Informace předává instanci třídy Renderer. Konstanty.java Konstanty ovlivňující vlastnosti výsledného vzhledu bludiště. Nastavuje se velikost políček bludiště, výška „očí“ nad zemí a minimální odstup od stěny. MouseMotionHandler.java Zjišťuje, zda bylo pohnuto myší. Pokud ano, zjistí o kolik a opět předá informaci instanci třídy Renderer. NactiMapu.java Čte mapu z textového souboru a ukládá výsledek do char pole. Renderer.java Hlavní třída pro zobrazení celé scény. Provádí se zde také vyhodnocení, o kolik se má hráč posunout každý frame z důvodu konstantní rychlosti pohybu bez ohledu na počet FPS. Důležité metody třídy Renderer: void update() V případě, ze je stisknuta některá klávesa, posune hráče v daném směru. void zakladniDetekceKolizi() Řeší jednoduché kolize v ose X a Z. void hledejObjekty() Při pohybu v bludišti zjišťuje, zda se na aktuální pozici hráče nachází objekt k sebrání. void hledejTeleporty(GL gl, GLAutoDrawable glDrawable) Podobně jako hledejObjekty(), ale hledá teleporty. void detekceRohu() Vyhodnocuje kolize v rozích. void vykresliObjekty(GL gl, ArrayList
entita, int polohaTextury) Vykresluje podlahu, strop a stěny pomocí GL_QUADS. Čtverce jsou uloženy v kolekci jako objekt Ctverec. void display(GLAutoDrawable gLDrawable) Provádí příslušné transformace, zapíná a vypíná světla a vykresluje nový frame.
36
void svetla(GL gl, GLAutoDrawable glDrawable) Správné nastavení polohy světel při pohybu hráče. void zobrazObjekty(GL gl, GLAutoDrawable glDrawable) Vykresluje do bludiště objekty, které jsou určené ke sběru. void zobrazTeleporty(GL gl, GLAutoDrawable glDrawable) Vykresluje do mapy modely pro označení teleportů. void nactiTextury(GL gl) Načítá obrázky z disku, od každého obrázku se vytvoří tři stejné textury s různým filtrem – bez filtru, lineární filtrování a mipmapping. Textura je uložena jako ByteBuffer, načítat je možné textury v běžných formátech. void init(GLAutoDrawable gLDrawable) Inicializace a nastavení OpenGL zobrazení – způsob stínování, perspektivu, nastavení výchozí pozice hráče. void reshape(GLAutoDrawable gLDrawable, int x, int y, int width, int height) Metoda je zavolána při změně velikosti okna a nastavuje perspektivu.
RozliseniObrazkovky.java Informace o výchozí šířce a výšce okna, případně rozlišení při zobrazení na celou obrazovku. RozmerBludiste.java Uchovává informace o výchozích rozměrech bludiště. package bludiste.ctverec Bod.java, Normala.java, Vektor.java Slouží k uchovávání souřadnic bodů v prostoru. Třídy jsou stejné, jiné názvy mají jen kvůli přehlednosti kódu. SouradniceTextury.java Uchovává u a v souřadnice pro textury. package bludiste.utils Třídy vycházejí z NeHe tutoriálů o OpenGL. BitmapLoader.java Načítání bitmapových obrázků z disku.
37
GLDisplay.java Vytváří vlastní zobrazovací plochu, do které se renderuje, nastavuje režimy zobrazení a obsahuje metody na přidávání handlerů na myš a klávesnici. HelpOverlay.java Vytváří výchozí nastavení pro renderování. Některé je později překryto nastavením, které je uvedeno v Renderer.java. Využívá se pro vypisování nápovědy na obrazovku. ResourceRetriever.java Otevírá soubory z JAR, aktuálního adresáře nebo z ClassPath, tuto třídu využívají BitmapLoader a TextureReader. TextureReader.java Načítání textur pro snadnější zpracování v OpenGL. Výška a šířka textur musí být mocnina 2, nejméně 64 pixelů. Z důvodu kompatibility se nedoporučuje používat větší textury než 256 pixelů.
5.3 Implementované vlastnosti 5.3.1 Textury Podlaha, strop a stěny mají vlastní texturu, dále je použita textura na pozadí v konzoli. Při zobrazení konzole se v pravém dolním rohu objeví malá animovaná textura, která je zachycena na obrázku 18. Obrázek 18: Animovaná textura
5.3.2 Modely Modely jsou načítány z textových souborů s následujícím formátem. 4 -1.0 1.0 1.0 -1.0 2 1 4 3 1 3 2
1.0 -1.0 1.0 -1.0 1.0 1.0 1.0 1.0
38
Soubor se skládá ze dvou hlavních částí. Jedna část definuje souřadnice vertexů v prostoru a druhá část udává, které vertexy se použijí při vytváření trojúhelníků. Číslice 4 nám říká, že následují souřadnice čtyř vertexů v prostoru, pak jsou na samostatných řádcích vypsány X, Y a Z souřadnice všech čtyř vertexů. Číslice 2 udává počet trojúhelníků, které budou definovány. Na dalších řádcích jsou popsány jednotlivé trojúhelníky tím způsobem, že odkazují na indexy vertexů, které byly definovány v první části souboru.
5.3.3 Sběr předmětů Sbíraným předmětem je načtený model prostorového kříže. V souboru s mapou je označen znakem T až Z. Model je vyobrazen na obrázku 19. Sbírá se pouze jeden druh objektů. Pokud je objekt sebrán – zmizí a zvýší se počet sebraných předmětů o 1. Předmět je považovaný za sebraný v okamžiku vstupu hráče na pole, nad kterým se vznáší. Předměty rotují kolem všech svých os. Obrázek 19: Předmět ke sběru
5.3.4 Teleport V bludišti se vyskytují políčka, která jsou speciálně označená modelem (viz obrázek 20). Po vstupu na toto pole dojde k přenosu na náhodně vybraný teleport v bludišti (tedy i na teleport na kterém hráč stojí). Po teleportování není možné 10s používat teleport (protože by jinak hrozilo, že v případě teleportování na jiné místo by se znovu aktivoval teleport a došlo k novému přenosu). Na počátku teleportace se přes celou obrazovku vykreslí obdélník, který má bílou barvu a mění se jeho průhlednost z plně průhledného na neprůhledný. V tomto okamžiku je hráč přenesen na jiné místo a průhlednost se opět zvětšuje. Během tohoto procesu je zablokováno veškeré ovládání, včetně rozhlížení myší. Obrázek 20: Teleport
5.3.4 Osvětlení Osvětlení světly, která jsou v mapě označeny @ je řešeno jen na úplně základní úrovni. Světla jsou načtena ze souboru a umístěna na scénu. V místě světel je na stropě model kvádru, viz obrázek 21. Maximální počet uživatelských světel je 6, ostatní jsou programem ignorována.
39
Obrázek 21: Světlo
5.3.5 Dynamika hráče Aby byla zajištěna větší reálnost chůze, hráč se pohupuje po funkci sinus ve svislém směru při chůzi dopředu nebo dozadu.
5.3.6 Konzole Po stisknutí ~ se rozbalí konzole, do které je možné zadávat pouze příkazy, které se zobrazí po napsání příkazu help, viz obrázek 22. Konzole je ve skutečnosti 2D obdélník, který je pokryt texturou a má nastavenou průhlednost. Konzole si pamatuje poslední potvrzený příkaz, který je možné znovu zobrazit pomocí klávesy ↑ (a případně editovat pomocí klávesy backspace). Pokud je uživatel v konzoli, je vypnuto ovládání hráče s výjimkou rozhlížení myší po okolí.
Obrázek 22: Konzole
40
5.4 Uživatelská dokumentace 5.4.1 Systémové požadavky a spuštění K běhu 3D Bludiště je vyžadováno JRE 1.5 a JOGL 1.1. Program se spouští souborem 3dmaze.jar. Pokud je na počítači nainstalovaný JOGL, aplikace se spustí a uživatel může procházet bludištěm. V případě, že JOGL nainstalovaný není nebo je nainstalována nekompatibilní verze, je nutné při spuštění specifikovat cestu ke knihovnám, které jsou přidány k programu. Bludiště se pak spouští následujícím příkazem: java -Djava.library.path=./lib/windows -jar 3dmaze.jar kde ./lib/windows je cesta ke knihovnám, které přísluší vašemu operačnímu systému. Pro zjednodušení spouštění jsou na CD vytvořeny spouštěcí skripty pro Windows a Linux. Uživatel si tedy nemusí pamatovat výše uvedený příkaz. V Linuxu bude pravděpodobně nutné přiřadit souboru práva na spouštění příkazem: chmod +x linux_start.sh
5.4.2 Ovládání Program nabízí velice jednoduché ovládání. Hráč se po bludišti pohybuje pomocí níže uvedených kláves a pomocí myši se může rozhlížet po okolí. Pohyb po bludišti W dopředu A doleva S dozadu D doprava rozhlížení po okolí je uskutečněno pomocí myši Další klávesy L zapne/vypne světla F přepne filtr textur ~ konzole Esc konec
5.5 Shrnutí 3D Bludiště jsem primárně vyvíjel a testoval na notebooku s Pentium M 750, Mobility Radeon X700, Windows XP SP2 a Java 1.6.0-b105. Testování probíhalo na odlišných verzích Windows a různých distribucí Linuxu. Zkoušel jsem odlišné Javy od verze 1.5 až po 1.6. Java starší než 1.5 není podporována, protože využívám typované kolekce. V následující kapitole uvádím porovnání téměř totožného 3D Bludiště, které je naprogramované v Javě za pomoci OpenGL a v C# s DirectX.
41
Kapitola 6 Porovnání OpenGL a DirectX OpenGL a DirectX – dvě různé, odlišné technologie, které jsou určené pro tvorbu 3D aplikací. OpenGL je starší než DirectX a je nezávislé na platformě, funguje například na operačních systémech Windows, Linux a Mac OS. DirectX je naopak určený pouze pro Windows. Pomocí D3DUT[6] je možné namapovat DirectX příkazy na OpenGL a následně pak provozovat DirectX aplikace i pod Linuxem. Je to ale poměrně komplikovaná záležitost. OpenGL v podání JOGL je plně přenositelné na výše uvedené platformy. Microsoft původně chtěl odstranit z Windows Vista hardwarovou podporu OpenGL, plánoval naopak mapování OpenGL příkazů na DirectX. Později z tohoto záměru ustoupil a existuje ovladač, který zpřístupní potřebné systémové prostředky pro OpenGL.
6.1 OpenGL OpenGL samo o sobě slouží pouze k renderování 3D scén. V dnešní době se používá převážně v poloprofesionálních a profesionálních programech jako je Blender, 3D Studio Max nebo Maya. Rozhraní OpenGL je založeno na architektuře klient server, kde klient je aplikace a server grafická karta. Díky této architektuře je možné spustit program na jiném počítači, než se bude renderovat výsledná scéna. OpenGL má strukturální přístup (ne objektový), proto je z počátku jednodušší na naučení. OpenGL v podání JOGL je téměř identické s klasickým OpenGL, všechno si musí programátor napsat sám.
6.2 DirectX Vývojový balík DirectX SDK obsahuje knihovny nejen pro renderování 3D scén, ale i pro podporu zvuků, hudby nebo propojení přes síť. V současnosti využívá DirectX téměř naprostá většina her, právě kvůli integrovaným knihovnám. DirectX využívá objektově orientovaný přístup, což může způsobit potíže při počátečním učení, ale později to již potíže nepůsobí. Výhodou DirectX je, že nově přidané funkce nemusí grafická karta podporovat a automaticky se počítají softwarově. Ne vždy bude ale výsledek použitelný kvůli velké výpočetní náročnosti.
42
Nově navržené DirectX 10 obsahují řadu vylepšení, například nové unifikované shadery. Dříve měla grafická karta určitý počet vertex a pixel shaderů, které plnily pouze jednu specifickou funkci. Nyní bude každý shader počítat nejen pixely a vertexy, ale navíc i pracovat s texturami, což bude mít pozitivní vliv na celkový výkon.
6.3 OpenGL vs. DirectX Jak bylo řečeno v úvodu v kapitole 1.1, programoval jsem v předmětu KIV/ZPG jako semestrální práci 3D Bludiště v prostředí .NET, jazyku C# s využitím DirectX. Pro porovnání jsem v bakalářské práci vytvořil v rámci možností srovnatelné 3D Bludiště s využitím JOGL v Javě. Některé následující kapitoly jsou rozděleny na dvě části, kde jedna se bude věnovat OpenGL a druhá DirectX. Snažil jsem se vyzdvihnout jejich zajímavé vlastnosti. Vzhledem k tomu, že jsem pracoval v naprosté většině případů pod Windows XP, nebudou jiné operační systémy zmíněny.
6.3.1 Instalace vývojového prostředí Nejprve je nutné stáhnout z internetu aktuální verzi JDK, JOGL a v mém případě oblíbený Eclipse. Instalace JDK je jednoduchá, bezproblémová a realizovaná přes instalačního průvodce. Eclipse se neinstaluje, stačí pouze rozbalit stažený archív do požadovaného adresáře na disku. Instalovat JOGL je komplikovanější a instalace je popsána v kapitole 3.3. Všechny potřebné nástroje jsou zdarma a celá instalace zabere na disku přibližně 460MB; kromě upravení několika systémových proměnných se žádný z programů do Windows neintegruje. Instalaci Visual Studio 2005 Professional od Microsoftu jsem prováděl z instalačního DVD, které si mohou půjčit všichni studenti KIV. Pro provoz všech aplikací v prostředí .NET je nutné nainstalovat .NET Framework verze 2.0 a zároveň i 1.1, protože verze 2 není zpětně kompatibilní. Pro vývoje DirectX aplikací se používá DirectX SDK. Nejlepší je, pokud se stáhne aktuální verze z webových stránek Microsoftu, protože každý měsíc vychází pravidelně nová verze. Jako poslední krok je vhodné nainstalovat všechny aktuální patche a service packy na Visual Studio a .NET Framework. Všechno dohromady zabírá na disku přes 1.1GB místa. Visual Studio se silně integruje do Windows, hlavně svým Just-in-time debuggerem, který v mém případě silně narušil stabilitu některých aplikací. Instalace se provádí jednou za čas, proto nejde jednoznačně rozhodnout, jestli je lepší Java nebo C#. Ale z negativní zkušenosti s Just-in-time debuggerem bych si raději vybral Javu a Eclipse, který nemá na operační systém žádný vliv.
43
6.3.2 Práce s IDE Každé moderní IDE pomáhá programátorům v psaní zdrojového kódu pomocí automatického doplňování názvů tříd, metod a proměnných. Obsahují nástroje na automatické generování bloků kódu (ošetření výjimek, cykly, importy a podobně). Další neméně důležitou funkcí je možnost refactoringu, například přejmenování proměnné včetně úpravy případných getterů, setterů a opravení komentářů. Eclipse používám na vývoj programu v Javě přibližně 2 roky, jsem na něj zvyklý a vyhovuje mi. Podporuje všechny výše uvedené vlastnosti, práce s ním je rychlá a pohodlná. Visual Studio jsem vlastně používal poprvé v životě a velice mě zklamalo. Sice také obsahuje spoustu užitečných funkcí, ale ve výchozím nastavení fungují jinak než v Eclipse. Snažil jsem se o takové nastavení, aby se chovalo podobně jako Eclipse, ale neuspěl jsem.
6.3.3 Java a C# Dva podobné, objektově orientované, programovací jazyky. Java je oficiálně multiplatformní jazyk, který funguje na všech běžných operačních systémech. Microsoft v jazyce C# pro prostředí .NET podporuje pouze Windows. Existuje open source projekt Mono[19], který sponzoruje společnost Novell. Mono umožňuje provozovat .NET aplikace nejen na Windows, ale i na operačních systémech Linux, Unix a Mac OS. Oba jazyky mají sice mírně odlišnou syntaxi a konvence, není ale velký problém, pokud známe jeden, naučit se druhý. Při vývoji 3D Bludiště v Javě bylo dokonce možné použít části kódu z C# pouze s minimálními úpravami.
6.3.4 Implementační rozdíly OpenGL a DirectX Přestože v rozsahu 3D Bludiště nebylo možné porovnat tyto dvě technologie do detailů, i v tomto ne příliš rozsáhlém projektu se projevila spousta odlišností. 6.3.4.1 Inicializace grafického hardware V OpenGL je metoda init(), která se zavolá ihned po spuštění, všechny parametry jsou v ní celkem přehledně popsány. Dalo by se říci, že na každé řádce je jeden příkaz, který nastaví jeden parametr. V DirectX je podobná metoda, ovšem při nastavování se volají třídy, jejichž konstruktory mají na první pohled spoustu složitých parametrů. Na druhý pohled, ale ani inicializace DirectX není tak složitá.
44
6.3.4.2 Směr osy Z Jednou z odlišností OpenGL a DirectX je orientace souřadného systému[23]. OpenGL používá pravotočivý souřadný systém a DirectX levotočivý. Výsledkem je obrácený směr osy Z, viz obrázek 23. Pokud vytvoříme v OpenGL 3D scénu a „beze změny“ jí přeneseme do DirectX, dostaneme zrcadlově obrácený obraz. Z tohoto důvodu jsem musel v DirectX otočit mapu, kterou jsem načítal z disku, aby výsledná scéna odpovídala zadané mapě. levotočivý systém
pravotočivý systém
Obrázek 23: Souřadné systémy
6.3.4.3 Řádkový a sloupcový zápis vektorů OpenGL používá sloupcovou reprezentaci vektoru a DirectX řádkovou. Ani jeden způsob zápisu nemá žádnou výhodu. Tato drobná změna má za následek opačné pořadí aplikování transformací v technologiích. Příklad: Chceme-li libovolný objekt ve scéně otočit o úhel α okolo bodu A, budou transformační matice vypadat následovně: OpenGL: DirectX:
Transformační matice = Translace(–A) · Rotace(α) · Translace(A) Transformační matice = Translace(A) · Rotace(α) · Translace(–A)
6.3.4.4 Geometrické entity Chceme-li vykreslit jakýkoliv prostorový objekt, musíme jeho povrch rozložit na síť trojúhelníků. Pokud bychom každý trojúhelník chtěli vykreslit samostatně, docházelo by ke zbytečnému definování bodů, které jsou společné pro více trojúhelníků a vedlo by to ke snížení výkonu. K tomuto účelu se používá tzv. fan a strip, viz kapitola 4.2.2. DirectX umí vykreslovat pouze trojúhelníky. OpenGL to umí také, ale navíc ještě dokáže pracovat s čtyřúhelníky. Možnost práce se čtyřúhelníkem byla v 3D Bludišti velice výhodná, protože podlaha a strop se skládají ze čtverců, stěny jsou obdélníky. Čtyřúhelník je při renderování automaticky rozložen na dva trojúhelníky.
45
6.3.4.5 Textury, modely, sprity a text Textura je obrázek, který se většinou načítá z disku a umísťuje se na příslušný objekt ve scéně. Model je zpravidla prostorový objekt, který může mít definované barvy, textury a materiály. Je uložený v souboru a používá se pro vkládání předmětů do scény, které by bylo příliš složité definovat ve zdrojovém kódu. Sprite je 2D obrázek, který je vhodný pro zobrazeni informačních sdělení na obrazovce v případě, že není možné použít běžný text. V DirectX jsou na všechny výše uvedené problémy připravené potřebné třídy a metody v SDK od Microsoftu. Například načtení textury z disku do formátu, který se pak používá při renderování, stačí pouze jedna řádka kódu. V klasickém OpenGL si musí programátor všechno sám napsat a odladit. 6.3.4.6 Světla Světla se ve 3D světě používají pro zvýšení realističnosti scén. Bez světel není možné zobrazovat stíny a například pohled do krajiny plné různého porostu by vypadal velice uměle. Používají se různé druhy světel[22]. Ambientní světlo je ve všech místech celé scény a má všude stejnou intenzitu. Bodové světlo si můžeme představit jako žárovku v prostoru, svítí do všech směrů a intenzita světla klesá se vzdáleností od zdroje světla. Směrové světlo je definováno pouze vektorem směru, kterým se šíří. Za směrové světlo považujeme Slunce, protože vzhledem k velké vzdálenosti jsou jeho paprsky téměř rovnoběžné. Posledním implementovaným světlem v OpenGL a DirectX je reflektorové světlo. Je definováno polohou v prostoru, směrem kterým svítí a úhlem světelného kuželu. Představit si ho můžeme jako baterku nebo reflektor. Výpočtově nejnáročnějším světlem je plošné světlo, které není v těchto dvou technologiích implementováno. V reálném světě se však vyskytuje velice často, například zářivka nebo okno v místnosti. V DirectX se na světla neaplikují žádné transformace a maximální počet světel je omezen na 16. V OpenGL si programátor vhodným nastavením matic sám zvolí, jestli se mají nebo nemají aplikovat transformace na světla. Maximum je 8 světel. Pouze 8 světel se na první pohled může zdát málo, ale výpočet světel je náročný na výkon hardware. Omezení je možné samozřejmě obejít, viz [25].
6.3.5 Výkon Srovnání výkonu JOGL v Javě a DirectX v C# není až tak jednoduché. Před několika lety platilo, že Java je pomalá. Dnes je Java výkonná a mnohdy i rychlejší, než stejný algoritmus napsaný v C++. Výkonnost aplikace závisí z velké části na optimalitě algoritmu, který programátor zvolil. Podle srovnání, které bylo provedeno v roce 2006, vychází Java a C# jako přibližně stejně výkonné vývojové platformy a C++ je v průměru asi 2× výkonnější. Zajímavé je, že Java na Windows je cca o 10% výkonnější, než stejný algoritmus v Linuxu. Podrobnější popis, grafy a výsledky jsou k dispozici na webových stránkách autora srovnávacího testu[28].
46
6.3.6 Zatížení procesoru, využití paměti RAM a grafické paměti Jestliže chceme od aplikace maximální výkon v řádu stovek až tisíců FPS, pak je procesor zatížen na 100%. Pokud výkon omezíme použitím FPSAnimator v případě programování v JOGL, pak zátěž klesne téměř k nule. 3D Bludiště v Javě potřebuje ke svému běhu 40 MB. Verze v C# o 5 MB méně, tedy 35MB. Využití paměti RAM není příliš závislé na velikosti a složitosti načtené mapy. Vzhledem ke kapacitě paměti dnešních počítačů je tento rozdíl téměř zanedbatelný. V případě využití paměti na grafické kartě vychází lépe Java s obsazenými 13 MB oproti C#, který zaplní 24 MB. Java totiž využívá jednodušší modely, proto také zabírá méně paměti. Složitost nebo velikost bludiště nezvyšuje nároky na paměť grafické karty, protože každý objekt je načítán pouze jednou, ale vykreslován několikanásobně.
6.3.7 Rychlost vývoje aplikací Pokud bych porovnal vývoj síťové 3D hry včetně doprovodných zvuků a hudby v OpenGL v Javě s DirectX v C#, bude vývoj v C# rychlejší. DirectX obsahuje ve svém SDK soubor všech potřebných nástrojů, které v OpenGL nejsou. Při programovaní s využitím JOGL bude nutné navrhnout a napsat všechny potřebné třídy vlastní silou nebo použít vhodnou rozšiřující knihovnu. Programovat vše sám je velice pracné a zdlouhavé, protože se musí každá třída odladit a otestovat. Rozšiřující knihovny jsou sice otestované, ale vzhledem k tomu, že JOGL a rozšiřující knihovny jsou vyvíjeny odděleně, může nastat problém s kompatibilitou. DirectX je vyvíjen pod záštitou Microsoftu, který by měl zaručit bezproblémový vývoj. Výhoda multiplatformnosti Javy může být zároveň i jejím problémem. U her se často používá nestandardní hardware, jako je volant, joystick a podobně. Výrobci takového hardware zpravidla dodávají ovladače pouze pro Windows. Je jen na vývojářích hry, jak se k tomuto problému postaví. Zda nějakým způsobem naprogramovat přímou podporu pro herní hardware nebo uměle omezit funkčnost pouze na Windows. Pak je ale možná zbytečné programovat v Javě.
47
Kapitola 7 Závěr 7.1 Shrnutí možností propojení Javy a OpenGL V první části bakalářské práce jsem porovnal vybrané možnosti propojení Javy a OpenGL. Myslím si, že by bylo velice zajímavé zkusit vytvořit 3D Bludiště pomocí jiné vazby než JOGL nebo s využitím rozšiřujících knihoven. Zajisté by byl rozdíl v rychlosti vývoje aplikace, když bych nemusel pracně programovat načítání textur a modelů, ale použil pouze připravené metody. Nelze jednoznačně říci, která z možností propojení je lepší a která horší. U každé se zajisté najde řada výhod i nevýhod. Pokud bych chtěl vyvíjet 3D aplikace pro systém, který má nedostatek systémových prostředků, použil bych LWJGL, který je pro (nejen) taková zařízení navržený. Na druhou stranu vyvstává otázka, proč na takových systémech používat Javu, která je sama o sobě náročnější než nativní aplikace. Pro běžné počítače je možné použít prakticky libovolnou z možností. Podle mne záleží jen na vkusu programátora. Nenašel jsem u žádné z vazeb zásadní nedostatky, které by mohly nějak bránit ve vývoji.
7.2 Zhodnocení ukázkové aplikace 3D bludiště jsem se snažil naprogramovat stejně jako v DirectX. Ne vždy to bylo možné a občas jsem i záměrně zvolil odlišný způsob řešení. Na začátku vyvstala otázka, jestli vykreslovat jednotlivé čtverce pomocí dvou trojúhelníků, jako v DirectX, abych zachoval co možná největší podobnost nebo používat GL_QUADS na vykreslování čtverců. Nakonec jsem se rozhodl pro vykreslování čtverců, protože je to vlastnost OpenGL a bylo by to jako v DirectX psát svoje vlastní metody na načítání textur. Výsledek snažení o vytvoření dvou srovnatelných aplikací s použitím různých vývojových prostředků je na obrázku 24. Na obrázcích je jasně patrné použití jiných
48
Obrázek 24: Porovnání aplikací v DirectX (vlevo) a OpenGL (vpravo)
49
Obrázek 25: Identická bludiště v DirectX (vlevo) a OpenGL (vpravo)
modelů. V DirectX jsem používal modely přímo pro DirectX v binárním formátu, které není možné pomocí JOGL bez přídavných knihoven načítat a používat. Zajímavé je porovnání FPS, které je vidět na obrázku 24. U prvních dvou screenshotů jsem použil malou mapu s málo objekty ve scéně, u druhé dvojice velkou mapu s velkým počtem pohybujících se stejných objektů. Na obrázku 25 je malá mapa o rozměrech 3×3, která obsahuje pouze to, co je v bludišti v DirectX a OpenGL na pohled naprosto identické (tj. ohraničení scény, textury a baterka). Podle počtu FPS na obrázku 24 bychom mohli usuzovat, že OpenGL v Javě je mnohem výkonnější, než DirectX v C#. Tento výsledek může být zkreslen větší složitostí modelů v DirectX, proto jsem vytvořil jednoduchou mapu, která je zachycena na obrázku 25. Ovšem i na identickém zobrazení vychází Java jako výkonnější. Rozhodně si myslím, že Java v podání JOGL vyšla ze srovnání velice dobře. Očekával jsem mnohem horší výsledek. Ačkoliv si Java nevede špatně, předpokládám, že se na poli profesionálních komerčních her s největší pravděpodobností neprosadí. Dnes jsou hry vyvíjeny převážně v C++ a DirectX. Pro firmy by byl přechod na jiný jazyk velice finančně nákladný a podstupovaly by obrovské riziko, že se vyskytnou nové neočekávané problémy. Do vývoje multiplatformních her je také netlačí fakt, že téměř naprostá většina domácích herních počítačů má operační systém Windows – bohužel, nebo bohudík?
50
Použité zkratky API – Application Programming Interface Sada tříd nebo funkcí, které je možné využít ve vlastních programech. Tyto třídy či funkce poskytuje cílová platforma pro kterou je aplikace určena a podstatně tak usnadňuje celkový vývoj. FPS – Frames Per Second Počet vykreslených snímků za jednu sekundu. FPS(2) – First Person Shooter 3D hra, kde se hráč dívá na svět očima virtuální postavy. GLU – OpenGL Utility Library Knihovna se snaží doplnit chybějící funkce, které nejsou přímo v OpenGL implementovány z důvodu složitosti, ale přesto se často používají. Usnadňuje programátorům práci v tom, že nemusejí programovat a ladit běžně používané algoritmy. GLUT – OpenGL Utility Toolkit Je doplněk pro OpenGL. Základem této nadstavbové knihovny je podpora pro práci s okny a písmem. Tyto funkce nejsou totiž v OpenGL implementovány z důvodu co největší platformové nezávislosti. IDE – Integrated Development Environment Vývojové prostředí, kde software usnadňuje práci programátorů. Obsahuje editor zdrojového kódu, kompilátor, případně interpret a většinou také debugger. JDK – Java Development Kit Soubor základních nástrojů pro vývoj aplikací v Javě. JiD – Java is Doomed Jedna z rozšiřujících knihoven OpenGL, viz kapitola 2.3.3. jME – jMonkeyEngine Jedna z rozšiřujících knihoven OpenGL, viz kapitola 2.3.1.
51
LWJGL – Lightweight Java Game Library Jedna z možných vazeb mezi Javou a OpenGL, viz kapitola 2.2.2. JOAL – Java OpenAL Jedna z možných vazeb mezi Javou a OpenAL. JOGL – Java OpenGL Jedna z možných vazeb mezi Javou a OpenGL, viz kapitola 2.2.3. JRE – Java Runtime Enviroment Prostředí, které je potřeba pro běh aplikací v Javě OpenAL – Open Audio Library Standard specifikující multiplatformní rozhraní pro tvorbu aplikací využívající zvuk. Je navržen pro efektivní renderování vícekanálového prostorového zvuku. OpenGL – Open Graphics Library Standard specifikující multiplatformní rozhraní pro tvorbu aplikací počítačové grafiky. Používá se při tvorbě počítačových her, CAD programů, aplikací virtuální reality či vědeckotechnické vizualizace a podobně. SDK – Software development kit Soubor nástrojů, které jsou potřebné pro vývoj. V této práci se vyskytuje ve spojení s DirectX SDK.
52
Literatura [1]
Davison Andrew, Killer Game Programming in Java 1. vydání, O’Reilly Media, 2005, ISBN 0-596-00730-2
[2]
Davison Andrew, Pro Java 6 3D Game Development 1. vydání, O’Reilly Media, 2007, ISBN 1-590-59817-7
[3]
Davison Andrew, Programování dokonalých her v Javě 1. vydání, Computer Press, 2006, ISBN 80-7226-944-5
[4]
Auriga 3D URL: [citováno 21. dubna 2007]
[5]
CZ NeHe OpenGL URL: [citováno 20. srpna 2006]
[6]
D3DUT URL: [citováno 11. května 2007]
[7]
Eclipse URL: [citováno 24. dubna 2007]
[8]
Geometric Primitives URL: [citováno 7. dubna 2007]
[9]
Gluegen URL: [citováno 21. dubna 2007]
[10]
GL4Java URL: [citováno 21. dubna 2007]
[11]
GNU General Public License URL: [citováno 21. dubna 2007]
53
[12]
Jake2 URL: [citováno 21. dubna 2007]
[13]
Java URL: [citováno 24. dubna 2007]
[14]
Java 3D URL: [citováno 24. dubna 2007]
[15]
Java OpenGL URL: [citováno 21. dubna 2007]
[16]
Java is Doomed URL: [citováno 21. dubna 2007]
[17]
jMonkeyEngine URL: [citováno 21. dubna 2007]
[18]
JSR 231: Java Binding for the OpenGL API URL: [citováno 21. dubna 2007]
[19]
Mono URL: [citováno 5. května 2007]
[20]
NeHe Productions URL: [citováno 20. srpna 2006]
[21]
OpenGL Utility Library URL: [citováno 24. dubna 2007]
[22]
Popis světel v OpenGL URL: [citováno 5. května 2007]
[23]
Souřadné systémy URL: [citováno 26. dubna 2007]
54
[24]
Sprite URL: [citováno 26. dubna 2007]
[25]
Světla OpenGL URL: [citováno 26. dubna 2007]
[26]
The BSD License URL: [citováno 21. dubna 2007]
[27]
The Lightweight Java Game Library URL: [citováno 21. dubna 2007]
[28]
Výkon Java, C# a C++ URL: [citováno 5. května 2007]
[29]
Xith3D URL: [citováno 21. dubna 2007]
55