10.06.2015 Views

Zadán´ı bakalárské práce - ExtBrain

Zadán´ı bakalárské práce - ExtBrain

Zadán´ı bakalárské práce - ExtBrain

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Zadání bakalářské <strong>práce</strong>


České vysoké učení technické v Praze<br />

Fakulta elektrotechnická<br />

Katedra počítačové grafiky a interakce<br />

Bakalářská <strong>práce</strong><br />

Webová platforma pro interakci uživatelů v 3D<br />

prostoru<br />

Ondřej Psota<br />

Vedoucí <strong>práce</strong>: Ing. Tomáš Novotný<br />

Studijní program: (BN2)Softwarové technologie a management,<br />

Bakalářský<br />

Obor: (2612R062)Web a multimedia<br />

28. května 2012


Poděkování<br />

Rád bych poděkoval svému konzultantovi a vedoucímu <strong>práce</strong> panu Ing. Tomášovi Novotnému<br />

za jeho cenné rady a vstřícný přístup při řešení problémů. Dále bych chtěl rovněž poděkovat<br />

všem, kteří mi byli nápomocni a vytvořili podmínky pro to, abych se své práci mohl plně<br />

věnovat.<br />

iii


Prohlášení<br />

Prohlašuji, že jsem práci vypracoval samostatně a použil jsem pouze podklady uvedené v přiloženém<br />

seznamu.<br />

Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000<br />

Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některých<br />

zákonů (autorský zákon).<br />

V Praze dne 28. května 2012 ...............................................................................................<br />

v


Abstract<br />

This work deals with creating a web platform using the WebGl technology. The web platform<br />

should be designed with regard to its future development. Objectives and requirements of<br />

the web platform are determined. There is a description of selected technologies enabling<br />

to display 3D graphics in a web browser and the current solution in the form of WebGl<br />

frameworks is evaluated. The procedure is that the solution is analyzed and proposed with<br />

regard to the requirements based on the needs of the resulting application where the user is<br />

located in the space environment with asteroids and compete with other users.<br />

The test did not reveal any significant shortcomings of the application. The application<br />

mostly appeared to be stable. Problems have been resolved with the recording of objects in<br />

the scene. Basic collisions, physics, network communication and many more features were<br />

implemented. A good basis was created on which it could be built in the future. Some gaps<br />

could be found in the scene lighting and some other imperfections.<br />

Abstrakt<br />

Tato <strong>práce</strong> se zabývá tvorbou webové platformy v technologii WebGl, která by měla být<br />

navržena s ohledem na její budoucí vývoj. Jsou stanoveny cíle a požadavky na webovou<br />

platformu. Dochází k popisu vybraných technologií umožňujících zobrazení 3D grafiky ve<br />

webovém prohlížeči a hodnotí se stávající řešení v podobě WebGl frameworků. Postup je<br />

takový, že se analyzuje a navrhuje řešení s ohledem na požadavky, které vycházejí z potřeb<br />

výsledné aplikace, kde se uživatel nachází v prostředí vesmíru s asteroidy a závodí s jinými<br />

uživateli.<br />

Test neobjevil významné nedostatky aplikace, která se vesměs jevila jako stabilní. Byly<br />

vyřešeny problémy s nahráváním objektů do scény, naimplementovány základní kolize, fyzika,<br />

sít’ová komunikace a mnoho dalších. Podařilo se vytvořit dobrý základ, na kterém lze v<br />

budoucnosti stavět. Určité mezery lze najít v osvětlení scény a některých nedokonalostech.<br />

vii


viii


Obsah<br />

1 Úvod 1<br />

2 Popis problému 2<br />

2.1 Cíl <strong>práce</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

2.2 Požadavky na ukázkovou aplikaci . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

2.3 Požadavky na webovou platformu . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

3 Popis vybraných technologií 4<br />

3.1 Technologie pro zobrazení 3D grafiky ve webovém prohlížeči . . . . . . . . . . 4<br />

3.1.1 VRML a X3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4<br />

3.1.2 Flash (Stage 3D) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4<br />

3.1.3 Unity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

3.2 Technologie WebGL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

3.2.1 Specifikace API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

3.2.2 Názorná ukázka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

3.2.3 Výsledek názorné ukázky . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

3.3 Technologie WebSockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

3.3.1 WebSocket protokol . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

3.3.2 Použití API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

ix


4 Analýza a návrh řešení 10<br />

4.1 Stručný přehled WebGl frameworků . . . . . . . . . . . . . . . . . . . . . . . 10<br />

4.2 Architektura platformy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

4.2.1 Inspirace pro návrh . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

4.2.2 Privátní proměnné . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

4.2.3 Přehledový diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

4.2.4 Objekt GameObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />

4.2.5 Komponenty objektu GameObject . . . . . . . . . . . . . . . . . . . . 13<br />

4.2.6 Nahrání dat do scény . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />

4.2.7 VirtualWorld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

4.2.8 Shadery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />

4.2.9 Vstup z klávesnice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

4.3 Obalová tělesa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

4.3.1 Obalová koule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

4.3.2 OBB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

4.3.3 AABB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

4.3.4 Testy kolizí mezi tělesy . . . . . . . . . . . . . . . . . . . . . . . . . . 25<br />

4.3.5 Objekt Contact . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

4.4 Základní fyzikální systém . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

4.4.1 Integrační metoda rigidního tělesa . . . . . . . . . . . . . . . . . . . . 27<br />

4.4.2 Pružina . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />

4.4.3 Registr působících sil . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />

4.5 Rozdělení prostoru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29<br />

4.5.1 Mřížky . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

4.5.2 Stromy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

4.5.3 Řadící mechanismy . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

5 Realizace 34<br />

5.1 Herní smyčka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />

5.1.1 RequestAnimationFrame API . . . . . . . . . . . . . . . . . . . . . . . 34<br />

5.1.2 Použití RequestAnimationFrame API v aplikaci . . . . . . . . . . . . . 36<br />

5.2 Průhlednost objektů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

5.2.1 Z-buffer a jeho nevýhody . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

x


5.2.2 Vykreslení průhledných objektů . . . . . . . . . . . . . . . . . . . . . . 37<br />

5.3 Viditelnost objektů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

5.3.1 View frustum culling . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

5.3.2 Backface culling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />

5.4 Multiplayer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />

5.4.1 Známé architektury . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39<br />

5.4.2 Implementace multiplayeru v ukázkové aplikaci . . . . . . . . . . . . . 40<br />

5.5 Generátor asteroidů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42<br />

5.5.1 Algoritmus pro generování asteroidů . . . . . . . . . . . . . . . . . . . 42<br />

5.5.2 Problém s generováním více asteroidů . . . . . . . . . . . . . . . . . . 43<br />

5.6 Laser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />

5.6.1 Billboarding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44<br />

5.6.2 Nejpoužívanější typy billboardů . . . . . . . . . . . . . . . . . . . . . . 45<br />

5.6.3 Tvorba laseru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45<br />

6 Testování 47<br />

6.1 Uživatelský test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />

6.2 Test aplikace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />

7 Závěr 49<br />

A Balíky platformy 54<br />

B Celkový UML diagram 56<br />

C Uživatelská příručka 58<br />

C.0.1 Ovládání . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61<br />

C.0.2 Hra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62<br />

D Obsah přiloženého CD 64<br />

xi


xii


Seznam obrázků<br />

3.1 Výsledný čtverec na černém pozadí . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

4.1 GameObject a možné komponenty . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

4.2 Obrázek znázorňuje objekty, které mezi sebou komunikují, pokud nastane<br />

změna v komponentě Transform a nebo v objektu GameObject. . . . . . . . 14<br />

4.3 Komponenta NetworkView a všechny důležité třídy se kterými spolupracuje. 16<br />

4.4 Obrázek znázorňuje načtení geometrických objektů do scény včetně materiálů<br />

a textur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

4.5 Mesh renderer, přiřazený mesh, buffery a materiály . . . . . . . . . . . . . . 19<br />

4.6 Objekt VirtualWorld se všemi objekty, na které si drží referenci. . . . . . . . 20<br />

4.7 Všechny objekty a konstruktory, které v platformě mají na starosti shadery. . 21<br />

4.8 Objekt Input s přidruženými objekty . . . . . . . . . . . . . . . . . . . . . . . 22<br />

4.9 Nejpoužívanější obalová tělesa. Převzato z [13] . . . . . . . . . . . . . . . . . 23<br />

4.10 Nalezený OBB ve 2D. Převzato z [15] . . . . . . . . . . . . . . . . . . . . . . 25<br />

4.11 Ukázka kolize OBB s koulí. Převzato z [12] . . . . . . . . . . . . . . . . . . . 26<br />

4.12 (a) Buňky jsou moc malé. (b) Buňky jsou zbytečně velké. (c) Buňky jsou velké<br />

s ohledem na velikost objektu. (d) Buňky jsou moc velké a zároveň moc malé.<br />

Převzato z [13] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30<br />

4.13<br />

Číslování jednotlivých potomků stromu. Převzato z [13] . . . . . . . . . . . . 31<br />

4.14 Minimální a maximální body jednotlivých AABB v dané ose jsou seřazeny dle<br />

velikosti. Převzato z [13] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />

4.15 Na obrázku vidíme objekty, které se nacházejí kousek od sebe v jedné ose.<br />

Pouze malý pohyb objektu může způsobit, že se hodnota uložená v seznamu<br />

posune o mnoho pozic. Převzato z [13] . . . . . . . . . . . . . . . . . . . . . . 32<br />

5.1 Rozdíl ve výkonu mezi setTimeout a RequestAnimationFrame API. Převzato<br />

z [18] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />

5.2 Některé verze prohlížečů implementují API již nějakou dobu, jiné prohlížeče<br />

naopak API zatím ignorují a nebo ho připravují v budoucích verzích. Převzato<br />

z [19] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />

5.3 a) Obrázek znázorňuje chyby ve vykreslení, pokud nejsou průhledné objekty<br />

seřazeny. b) Průhledné objekty jsou seřazeny. . . . . . . . . . . . . . . . . . . 38<br />

5.4 a) Počáteční koule rozpůlená rovinou. b) Koule je rozpůlena jinou rovinou.<br />

Vertexy před rovinou se posunuly směrem ke středu a vertexy za rovinou<br />

směrem od středu. c) Výsledek po několika iteracích. . . . . . . . . . . . . . . 43<br />

5.5 Billboardy orientované směrem k pozorovacímu bodu . . . . . . . . . . . . . 45<br />

5.6 Laser z ukázkové aplikace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />

xiii


A.1 Balíčky, které strukturují zdrojový kód . . . . . . . . . . . . . . . . . . . . . . 54<br />

B.1 Celkový uml diagram, který obsahuje všechny důležité třídy (konstruktory) . 56<br />

C.1<br />

Úvodní obrazovka . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

C.2 a) Okno, které se objeví po stisknutí klávesy S v úvodním okně. b) Okno<br />

informující o stavu scény po jejím spuštění. Pomocí tlačítka Uložit scénu lze<br />

uložit aktuální stav scény. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

C.3 a) Okno, kde se uživatel může připojit jako nový hráč. b) Okno, kde si uživatel<br />

může vybrat ze seznamu odpojených hráčů a přebrat jeho vesmírnou lod’. . . 60<br />

C.4 Okno se scénou. Vlevo nahoře je vidět vzdálenost uživatele od středu, rychlost<br />

a uplynulý čas od průletu první brány. Vpravo nahoře se objevují informace<br />

o nově připojených nebo odpojených hráčích. . . . . . . . . . . . . . . . . . . 61<br />

D.1 Výpis souboru readme.txt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64<br />

xiv


1 Úvod<br />

Současný technologický vývoj umožňuje vytvářet aplikace spustitelné ve webovém prostředí,<br />

které se svým vzhledem a chováním blíží desktopovým aplikacím. Přesně takovou technologii<br />

představuje WebGl[6], pomocí které lze docílit velice zajímavých výsledků v oblasti počítačové<br />

grafiky. Velkou výhodou technologie WebGl je možnost vytváření vlastních shaderů, s<br />

jejichž pomocí lze docílit efektů, které jsme si dříve ve webovém prohlížeči nedokázali ani<br />

představit. I přesto, že se objevují konkurenční technologie, které jsou schopné dosáhnout<br />

obdobných výsledků, má WebGl tu výhodu, že případnou aplikaci lze spustit, aniž by bylo<br />

nutné instalovat doplněk do webových prohlížečů. Jedná se o novější technologii, a proto není<br />

podporována jejich staršími verzemi. Bohužel podpora Internetu Exploreru zatím chybí.<br />

Cílem této bakalářské <strong>práce</strong> je navrhnout a naimplementovat webovou platformu umožňující<br />

interakci uživatelů v 3D prostoru pomocí WebGl, které vychází z OpenGl ES 2.0[5].<br />

Implementované vlastnosti dané platformy budou demonstrovány na ukázkové aplikaci. Koncový<br />

uživatel bude moci ovládat vesmírné plavidlo a pohybovat se mezi asteroidy či jinými<br />

objekty. Serverová komponenta umožní vzájemnou interakci uživatelů a sdílení jejich scény.<br />

Aby si uživatelé mohli vyzkoušet ovládání plavidla a celkově si vychutnat možnosti vytvořeného<br />

virtuálního prostředí, bude pro ně připraven jednoduchý závod. Kontrolní body ve<br />

formě hvězdných bran zajistí hladký průběh závodu. Plavidla budou moci kolidovat s okolními<br />

předměty a reagovat na kolizi. Vývoj platformy se bude odvíjet s ohledem na požadavky<br />

ukázkové aplikace.<br />

V kapitole 2 se definují požadavky na výslednou platformu včetně ukázkové aplikace.<br />

Kapitola 3 se zabývá popisem technologií, které se používají k zobrazování 3D grafiky ve<br />

webovém prohlížeči. Především jde o VRML, Stage3D a Unity. Dále se zaměřuje na základní<br />

stavební prvky WebGl a přibližuje technologii WebSockets[8]. V kapitole 4 se provádí analýza<br />

možností řešení a dochází k návrhu jednotlivých prvků platformy. Kapitola 5 popisuje<br />

detailněji zajímavá či neobvyklá řešení, která se týkají vývoje ukázkové aplikace na navržené<br />

platformě. V kapitole 6 jsou shrnuty poznatky, které vyplynuly z testování aplikace.<br />

1


2 Popis problému<br />

V podkapitole 2.1 je obecně popsán cíl <strong>práce</strong> a možnosti využití vytvořené platformy. V<br />

podkapitolách 2.2 a 2.3 se kladou požadavky, které by měly výsledná platforma a ukázková<br />

aplikace splňovat.<br />

2.1 Cíl <strong>práce</strong><br />

Cílem <strong>práce</strong> je navrhnout a naimplementovat základ webové platformy pro interakci uživatelů<br />

v 3D prostoru pomocí technologie WebGl. Očekává se, že tato platforma bude nadále<br />

rozvíjena a postupně rozšiřována. Ve výsledku by mohla například sloužit jako součást či<br />

doplněk výuky, jejíž pomocí by studentům byla názorně předváděna funkce určitých zařízení.<br />

Pohyb pístů motoru by si dokázali ihned lépe představit. Samozřejmě se najde širší<br />

oblast působnosti. Jak již bylo zmíněno v úvodu 1, vlastnosti platformy budou demonstrovány<br />

na ukázkové aplikaci v podobě hry z prostředí vesmíru. Platforma bude založena na<br />

rozšířené specifikaci jazyka HTML, čímž je jazyk HTML5[1]. Technologie WebGl využívá<br />

pro vykreslování plátno canvas, které je součástí zmíněného jazyka . Z této skutečnosti vyplývá,<br />

že zvolená technologie nebude dostupná v prohlížečích, které nepodporují HTML5.<br />

Aktuální verze nejrozšířenějších prohlížečů již tuto specifikaci podporují. Všechny prohlížeče<br />

jako je Firefox, Chrome, Opera, či Safari podporují ve standardním nebo editačním módu<br />

také technologii WebGl. Bohužel jeden významný hráč na trhu v seznamu zatím chybí a tím<br />

je Internet Explorer. Ani jeho verze číslo 9 si s touto technologií neporadí, a to v momentě,<br />

kdy Khronos Group standardizovalo grafické rozhraní WebGl 1.0.<br />

2.2 Požadavky na ukázkovou aplikaci<br />

Závod bude individuální časovka, která se pro jedince spustí průletem první brány. Závodit<br />

bude moci i více závodníků najednou, ale každému se čas měří od prvního průletu. Každý<br />

závodník vidí zvýrazněnou příští bránu a méně zvýrazněné příští brány ostatních připojených<br />

účastníků. Pokud nemá bránu v zorném poli, vidí po straně obrazovky šipku ukazující<br />

nejbližší vzdálenost. Mapu bude možné stavět z lodi, čímž se otevře prostor ke stavbě zajímavých<br />

map. Hráč bude moci po stisku klávesy nechat vygenerovat asteroid nebo bránu.<br />

Z důvodu zpětné vazby bude vygenerovaný asteroid poloprůhledný a nebude kolidovat. Po<br />

opuštění prostoru všemi hráči se zhmotní. Asteroidy půjde odstřelovat laserem, který když<br />

zasáhne asteroid, tak dojde k jeho zmizení. Obdobným způsobem půjde přidávat a odebírat<br />

brány. Laser ostatním hráčům nebude vadit. Pokud během závodu někdo zruší aktuální<br />

bránu, najde se další brána s vyšším číslem. Vytvořený svět i s pozicemi hráčů půjde uložit<br />

do souboru, odkud bude moci být znovu načten. Poslední pozice hráče bude uložená na<br />

serveru. Pokud se hráč odpojí, jeho lod’ se zastaví a zůstane pro ostatní lodě viditelná ve<br />

vesmíru. Při připojení se hráči zobrazí seznam odpojených hráčů a hráč si vybere, za koho<br />

se připojí, nebo zadá nové jméno do editu a vytvoří se tím nový hráč.<br />

2


2.3 Požadavky na webovou platformu<br />

Požadavky na webovou platformu byly již částečně zmíněny v úvodu 1 <strong>práce</strong>. Ve své podstatě<br />

se jedná o základní návrh a implementaci herního enginu. Samotné téma herních enginů je<br />

natolik rozsáhlé a složité, že bude nutné si vymezit určitý okruh vlastností, které by výsledná<br />

platforma nebo ukázková aplikace měli splňovat:<br />

ˆ Platforma by měla mít určitou strukturu s důrazem na její snadnou rozšiřitelnost.<br />

ˆ Základem každého enginu jsou 3D modely, bude tedy nutné vyřešit jejich nahrávání<br />

do scény.<br />

ˆ Na jednotlivé objekty by měly být aplikovatelné různé shadery podle potřeby.<br />

ˆ Objekty ve scéně budou uspořádány ve stromové struktuře.<br />

ˆ Na jednotlivé uzly stromu bude možné aplikovat známé transformace rotace, posunutí<br />

a zvětšení, popřípadě jiné vlastnosti.<br />

ˆ Jelikož by měly objekty ve scéně mezi sebou interagovat, tak je zapotřebí vytvořit<br />

základ fyzikálního systému a s tím související detektor kolizí.<br />

ˆ S předešlým bodem přímo souvisí různá obalová tělesa objektů ve scéně, například<br />

koule, orientovaný kvádr atd.<br />

ˆ Pohyb kamery by měl být dynamický, kamera by se neměla nacházet pouze na jednom<br />

místě za objektem.<br />

ˆ Scéna by měla být rozdělena do určitých sekcí. Objekty, které se nenachází ve viditelném<br />

prostoru, by neměly být předány grafické kartě k renderování.<br />

ˆ Ve scéně se budou nacházet průhledné objekty, je tedy nutné vyřešit problémy týkající<br />

se blendingu a z - bufferu.<br />

ˆ Pro asteroidy je třeba vytvořit generátor, aby se docílilo různého vzhledu asteroidů.<br />

ˆ Je třeba vyřešit problémy týkající se multiplayeru a vybrat konkrétní architekturu jako<br />

je klient - server nebo například peer - to - peer.<br />

Serverová komponenta je tvořena javovským Jetty serverem. Bohužel to má tu nevýhodu, že<br />

nebude moci být použit na aplikační logiku výsledného programu. Kód pro WebGl je totiž<br />

psán v javascriptu. Jetty server byl původně vybrán, protože je malý a podporuje technologii<br />

WebSockets, která bude použita pro vzájemnou komunikaci uživatelů. API WebGl je<br />

oproti původnímu OpenGl hodně redukované. Základ tvoří primitiva, buffery a programovatelná<br />

grafická část. Chybí zcela objekty Begin, End, v API se nenachází žádné metody<br />

pro výpočet matic, kvaternionů, není zde žádná metoda lookAt. Ve WebGl není třeba hledat<br />

žádnou podporu pro světla, materiály, žádná tam totiž není, vše je nutné udělat pomocí<br />

shaderů. Z toho vyplývá tedy to, že určité vlastnosti musejí být doplněny různými externími<br />

javascriptovskými knihovnami a nebo vlastní implementací.<br />

3


3 Popis vybraných technologií<br />

V následující podkapitole 3.1 jsou stručně popsány známé technologie pro zobrazování 3D<br />

grafiky ve webovém prohlížeči. Další podkapitola 3.2 se zaměřuje na WebGl a nastiňuje<br />

princip tvorby pomocí této technologie. Poslední podkapitola 3.3 přibližuje technologii Web-<br />

Sockets pro sít’ovou komunikaci.<br />

3.1 Technologie pro zobrazení 3D grafiky ve webovém prohlížeči<br />

WebGl není jediná technologie, která umožňuje zobrazení 3D grafiky pomocí webového prohlížeče.<br />

Podkapitola 3.1.1 se zaměřuje spíše na starší technologii VRML. V podkapitole 3.1.2<br />

je stručně popsána poměrné nová technologie Stage3D. Podkapitola 3.1.3 se zaměřuje na<br />

kompletní vývojový nástroj Unity.<br />

3.1.1 VRML a X3D<br />

Již v roce 1997 byla publikována norma pro popis virtuálního prostředí pod jménem VRML[2].<br />

Jedná se o jazyk, který je zaměřen na prezentaci virtuální reality ve webovém prohlížeči a<br />

zároveň jde o formát souborů. Scéna je organizována do stromové struktury. Tělesa a další<br />

objekty jsou popsány pomocí hraniční reprezentace. Na jejich plošky je možné mapovat textury.<br />

Scéna v sobě zahrnuje běžně používané prvky jako jsou světelné zdroje, předdefinované<br />

polohy, charakteristiky kamer atd. VRML není žádný programovací jazyk, neobsahuje žádné<br />

programovací konstrukce. Funkční vlastnosti nových objektů lze popsat jazyky Java a JavaScript.<br />

Pomocí různých prostředků lze definovat animace objektů a interakci s uživatelem.<br />

Klíčové hodnoty založené na lineární interpolaci definují výslednou animaci. Pro interakci<br />

slouží různé senzory, které reagují na různé aktivity avatara. Může se jednat o kliknutí myši,<br />

o průchod určitým místem atd. Pro interakci se využívá principu událostí. VRML postupně<br />

přestalo dostačovat současným požadavkům, což se snaží napravit formát X3D, který doplňuje<br />

nové vlastnosti.<br />

3.1.2 Flash (Stage 3D)<br />

S vydáním Flashové přehrávače číslo 11 se otevřely nové možnosti použití, které dřívější<br />

verze neposkytovaly. Nový Flash již podporuje rendering pomocí 3D hardwarové akcelerace.<br />

Dřívější verze Flash se spoléhaly pouze CPU. Adobe s touto verzí vydalo API Stage3D[3],<br />

které využívá všech schopností GPU přímo z Flashe, což rozšiřuje oblast působnosti tohoto<br />

velice rozšířeného přehrávače. Již bude možné vytvářet různé efekty pomocí shaderů. Scéna<br />

se pouze připraví(vertexy, transformační matice, atd ) a všechna potřebná data se pošlou do<br />

GPU, které data postupně zpracuje v několika fázích. Mimo jiné se jedná o velice podobný<br />

princip, který využívá právě WebGl.<br />

4


3.1.3 Unity<br />

Unity 3D[4] je herní vývojový nástroj, který poskytuje spoustu možností pro vývoj interaktivních<br />

3D aplikací. Nejedná se pouze o grafické API, ale o kompletní vývojové prostředí.<br />

Výsledné výtvory mohou být spuštěny na mnoha známých platformách. Od Windows, Mac,<br />

XBox360 až po mobilní Android. Navíc existuje doplněk, pomocí kterého je možné výsledný<br />

projekt spustit ve webovém prohlížeči. Aktuální verze 3.5 podporuje export do SWF formátu,<br />

který je doménou Adobe Flash. Hlavním stavebním prvkem je GameObject, který se může<br />

skládat z mnoha komponent od fyziky po různá světla a zvuky. Objektům je možné přiřadit<br />

komponentu script pomocí, které se tvoří hlavní logika a ovládání hry. Unity podporuje tři<br />

skriptovací jazyky. Javascript, C# a Boo, který vychází z Pythonu. Nahrávaní vytvořených<br />

modelů ze známých modelovacích nástrojů je otázkou několika málo kliknutí. Jedná se celkově<br />

o propracovanou platformu s vývojovým prostředím, pomocí kterého je možné vytvářet<br />

opravdu pohledné scény a využít tím možnosti dnešních grafických karet. Unity například<br />

podporuje Nvidia PhysX.<br />

3.2 Technologie WebGL<br />

Několik následujících řádků se bude týkat pouze technologie WebGl. První podkapitola 3.2.1<br />

pouze nastiňuje konkrétní specifikaci. V podkapitolách 3.2.2 a 3.2.3 je ukázán základní princip<br />

tvorby aplikací pomocí webGl.<br />

3.2.1 Specifikace API<br />

Technologie WebGl byla již částečně popsána v kapitole 1 a 2.1. Kompletní specifikace<br />

OpenGl ES 2.0 [5] lépe popisuje všechny možnosti tohoto API, které je určeno pro vestavěné<br />

systémy, mobilní telefony, konzole, spotřebiče či auta. Specifikace WebGl 1.0[6] vychází z<br />

OpengGl ES 2.0, na kterou se velmi často odvolává a případně popisuje rozdíly mezi těmito<br />

API.<br />

3.2.2 Názorná ukázka<br />

Na WebGl bude postavena výsledná platforma, a proto následuje velice jednoduchá ukázka,<br />

která se snaží nastínit princip tvorby aplikací pomocí WebGl.[7]<br />

Vertex shader a Fragment shader - Bloky vertex shaderů a pixel shaderů jsou napsány<br />

v jazyku GLSL, který vychází ze syntaxe jazyka C. Vertex shader v tomto případě<br />

pouze vynásobí každý vertex projekční a modelovou maticí. V ukázce jsou 2 typy proměnných.<br />

Uniform proměnné se v průběhu provádění nemění, matice mají tedy stále stejnou<br />

hodnotu. Naproti tomu proměnné Attribute se neustále mění. Vertex shader je totiž spuštěn<br />

pro každý vertex zvlášt’. Fragment shader nepřijímá žádnou proměnnou z vertex shaderu a<br />

pouze nastaví vykreslenému objektu konkrétní barvu.<br />

var vertexSh = ” a t t r i b u t e vec3 poziceVertexu ;”+<br />

5


”\ } ”;<br />

”uniform mat4 p r o j e k c n i M a t i c e ;”+<br />

”uniform mat4 MMatice ;”+<br />

”void main ( void ) \{”+<br />

” g l P o s i t i o n = p r o j e k c n i M a t i c e * MMatice<br />

* vec4 ( poziceVertexu , 1 . 0 ) ; ”+<br />

var fragmentSh = ” p r e c i s i o n mediump f l o a t ;”+<br />

”void main ( void ) {”+<br />

”gl FragColor = vec4 ( 0 . 5 , 0 . 5 , 0 . 5 , 1 . 0 ) ; ”+<br />

”} ”;<br />

Kompilace programu - Následující kód získá WebGl kontext, pomocí kterého je možné<br />

přistupovat k funkcím jádra WebGl. Dále se provede kompilace shaderů a vlastního programu.<br />

var canvas = document . getElementById ( ” platno ”) ;<br />

var g l = canvas . getContext ( ”moz−webgl ”) ;<br />

var vertexShader = g l . createShader ( g l .VERTEX SHADER) ;<br />

g l . shaderSource ( vertexShader , vertexSh ) ;<br />

g l . compileShader ( vertexShader ) ;<br />

var fragmentShader = g l . createShader ( g l .FRAGMENT SHADER) ;<br />

g l . shaderSource ( fragmentShader , fragmentSh ) ;<br />

g l . compileShader ( fragmentShader ) ;<br />

var program = g l . createProgram ( ) ;<br />

g l . attachShader ( program , vertexShader ) ;<br />

g l . attachShader ( program , fragmentShader ) ;<br />

g l . linkProgram ( program ) ;<br />

g l . useProgram ( program ) ;<br />

6


Tvorba a plnění bufferů - Proto, aby bylo možné vykreslit daný objekt, musí mít grafická<br />

karta k dispozici potřebná data. K těmto účelům slouží buffery, které jsou po vytvoření<br />

uloženy v paměti grafické karty. Buffery jsou pro 3D modely ideální volbou. Array buffer<br />

slouží v tomto případě k uložení pozic vertexů a Element array buffer uchovává indexy, které<br />

odkazují na konkrétní vertexy. Metoda gl.createBuffer() vytvoří nový buffer a gl.bindBuffer()<br />

určuje aktuálně používaný buffer. \<br />

v e r t e x B u f f e r = g l . c r e a t e B u f f e r ( ) ;<br />

g l . bindBuffer ( g l .ARRAY BUFFER, v e r t e x B u f f e r ) ;<br />

vertexy = [ 1 . 0 , 1 . 0 , 0 . 0 , −1.0 , 1 . 0 , 0 . 0 , 1 . 0 ,<br />

−1.0 , 0 . 0 , −1.0 , −1.0 , 0 . 0 ] ;<br />

g l . bufferData ( g l .ARRAY BUFFER,<br />

new Float32Array ( vertexy ) , g l .STATIC DRAW) ;<br />

v e r t e x B u f f e r . v e l i k o s t P o l o z k y = 3 ;<br />

v e r t e x B u f f e r . pocetPolozek = 4 ;<br />

i n d e x B u f f e r = g l . c r e a t e B u f f e r ( ) ;<br />

g l . bindBuffer ( g l .ELEMENT ARRAY BUFFER, i n d e x B u f f e r ) ;<br />

var indexy = [ 0 , 1 , 2 , 1 , 3 , 2 ] ;<br />

g l . bufferData ( g l .ELEMENT ARRAY BUFFER,<br />

new Uint16Array ( indexy ) , g l .STATIC DRAW) ;<br />

i n d e x B u f f e r . pocetPolozek = 6 ;<br />

program . v e r t e x A t t r i b u t e = g l . g e t A t t r i b L o c a t i o n (<br />

program , ”poziceVertexu ”) ;<br />

g l . enableVertexAttribArray ( program . v e r t e x A t t r i b u t e ) ;<br />

Nastavení Uniform proměnných<br />

- Na následujících několika řádcích se nejprve nastaví<br />

hodnoty matic a následně se přiřadí k Uniform proměnným použitých v shaderech.<br />

var p r o j e k c n i M a t i c e = mat4 . c r e a t e ( ) ;<br />

var MMatice = mat4 . i d e n t i t y ( ) ;<br />

mat4 . t r a n s l a t e ( MMatice , [ 0 , 0 . 0 , − 7 . 0 ] ) ;<br />

g l . viewport ( 0 , 0 , 400 , 4 0 0 ) ;<br />

mat4 . p e r s p e c t i v e (45 , 400 / 400 , 0 . 1 , 1 0 0 . 0 , p r o j e k c n i M a t i c e ) ;<br />

program . l o k a c e P r o j e k c n i M a t i c e = g l . getUniformLocation (<br />

program , ”p r o j e k c n i M a t i c e ”) ;<br />

g l . uniformMatrix4fv ( program . lokaceProjekcniMatice ,<br />

f a l s e , p r o j e k c n i M a t i c e ) ;<br />

program . lokaceMMatice = g l . getUniformLocation (<br />

program , ”MMatice ”) ;<br />

g l . uniformMatrix4fv ( program . lokaceMMatice , f a l s e , MMatice ) ;<br />

7


Vykreslení objektu<br />

- V posledním kroku se určí buffery, se kterými má grafická karta aktuálně<br />

pracovat. Zavoláním metody drawElements dojde k vykreslení objektu na obrazovku.<br />

g l . c l e a r C o l o r ( 0 . 0 , 0 . 0 , 0 . 0 , 1 . 0 ) ;<br />

g l . c l e a r ( g l .COLOR BUFFER BIT ) ;<br />

g l . bindBuffer ( g l .ARRAY BUFFER, v e r t e x B u f f e r ) ;<br />

g l . v e r t e x A t t r i b P o i n t e r ( program . vertexAttribute ,<br />

v e r t e x B u f f e r . v e l i k o s t P o l o z k y , g l .FLOAT, f a l s e , 0 0 ) ;<br />

g l . bindBuffer ( g l .ELEMENT ARRAY BUFFER, i n d e x B u f f e r ) ;<br />

g l . drawElements ( g l .TRIANGLES, i n d e x B u f f e r . pocetPolozek ,<br />

g l .UNSIGNED SHORT, 0 ) ;<br />

3.2.3 Výsledek názorné ukázky<br />

V minulé podkapitole 3.2.2 byl popsán postup, jak na obrazovku vykreslit čtverec. Zde je<br />

výsledek snažení:<br />

Obrázek 3.1: Výsledný čtverec na černém pozadí<br />

3.3 Technologie WebSockets<br />

Specifikace technologie WebSocket[8] definuje API, které dovoluje webovým stránkám používat<br />

obousměrnou komunikaci se vzdáleným hostem. Uvádí WebSocket rozhraní a definuje<br />

full duplexní komunikační kanál přes TCP spojení. HTML5 WebSockets výrazně redukuje<br />

objem přenesených dat a zkracuje zpoždění až na 50ms ve srovnání s jinými technologiemi.<br />

Existují sice technologie polling a long-polling, ale ty nemohou websockets konkurovat co<br />

se týče rychlosti. Není již třeba se neustále dotazovat serveru, zda nejsou k dispozici nová<br />

data k přenesení. Na technologii Websockets je unikátní, že dokáže posílat data bez větších<br />

omezení skrz různé firewally a proxy servery.<br />

8


Podkapitola 3.3.1 přibližuje samotný WebSocket protokol. V podkapitole 3.3.2 se rozebírá<br />

základní API této technologie.<br />

3.3.1 WebSocket protokol<br />

WebSocket protokol byl navržen s ohledem na stávající webovou infrastrukturu. Specifikace<br />

protokolu definuje, že je spojení nejprve navázáno pomocí HTTP, což garantuje zpětnou<br />

kompatibilitu se systémy z dob, kdy WebSocket vůbec neexistovalo. Navázání spojení se<br />

provádí v několika krocích:<br />

ˆ Webový prohlížeč odešle na server žádost o přepnutí HTTP protokolu na protokol<br />

WebSocket. Žádost je odeslána v podobě aktualizovací hlavičky.<br />

ˆ Server okamžitě přepne na nový protokol, pokud podporuje technologii WebSocket.<br />

ˆ V tomto bodě dojde k nahrazení protokolu HTTP spojením WebSocket přes vrstvu<br />

TCP/IP. WebSocket spojení používá stejný port jako HTTP(80) a zabezpečené HTTPS(443).<br />

ˆ Je-li spojení úspěšně navázáno, je možné přijímat a odesílat jednotlivé framy mezi<br />

klientem a serverem ve full-duplexním módu. Jak binární, tak textové framy mohou<br />

být přijímány a odesílány najednou v jeden okamžik.<br />

3.3.2 Použití API<br />

Pro navázání spojení stačí vytvořit novou instanci WebSocket a vložit do konstruktoru URL<br />

s předponou ws nebo wss, chceme-li zabazpečené spojení:<br />

var myWebSocket = new WebSocket ( ”ws : / /www. adresa . cz ”) ;<br />

Rozhraní WebSocket definuje několik posluchačů, které jsou zavolány, pokud nastane konkrétní<br />

událost :<br />

myWebSocket . onopen = f u n c t i o n ( evt ) {<br />

a l e r t ( ” S p o j ení navázáno ”) ;<br />

} ;<br />

myWebSocket . onmessage = f u n c t i o n ( evt ) {<br />

a l e r t ( ” P ř i j a t a zpráva : ” + evt . data ) ;<br />

} ;<br />

myWebSocket . o n c l o s e = f u n c t i o n ( evt ) {<br />

a l e r t ( ” S p o j ení ukončeno ”) ;<br />

} ;<br />

Zprávy jsou odesílány pomocí metody send :<br />

myWebSocket . send ( ” Hello ! ”) ;<br />

Ukončení spojení:<br />

myWebSocket . c l o s e ( ) ;<br />

9


4 Analýza a návrh řešení<br />

V následující podkapitole 4.1 jsou rozebrány různé frameworky, které jsou pro WebGl k<br />

dispozici. Podkapitola 4.2 se zaměřuje na architekturu a je zde snaha najít ideální návrh<br />

výsledné platformy. Následující podkapitoly jsou úzce svázány s architekturou platformy.<br />

Konkrétně se v podkapitole 4.3 rozebírají nejpoužívanější obalová tělesa a vybírají se ta,<br />

která následně budou implementována. V podkapitole 4.4 je přiblížen základní fyzikální<br />

systém, který bude použit. Podkapitola 4.5 je sice poslední, ale určitě není méně důležitá.<br />

Zaměřuje se na metody rozdělující scénu a vybírá se ta ideální pro ukázkovou aplikaci.<br />

4.1 Stručný přehled WebGl frameworků<br />

HTML5,CSS3 a WebGl jsou technologie, které mění podobu dnešních webových stránek.[9]<br />

Očekává se, že se tyto technologie budou navzájem doplňovat a vzniknou velice zajímavé<br />

projekty. Takto velké rozsáhlé aplikace není možné tvořit jen pomocí API, které WebGl nabízí.<br />

Je potřeba přidat určité vrstvy, které budou mít na starosti například světla, rendering,<br />

nahrávání objektů, fyziku, dělení scény, stromovou strukturu, atd. Za tímto účelem vznikají<br />

různé frameworky, které implementují tyto vlastnosti a mnoho dalších. Ačkoliv počet<br />

WebGl frameworků neustále roste, tak některé jsou již na konci svého vývoje. V době, kdy<br />

se začala tvořit výsledná platforma nebyly frameworky dobře zdokumentované. Například<br />

framework Three.js vypadal jako dobrý kandidát, ve kterém by se dala platforma naimplementovat,<br />

ale existoval pouze jednoduchý příklad, a to je velice málo. Navíc chyběla podpora<br />

fyziky, částicového systému a pokročilejších funkcí. X3DOM framework vychází z X3D, o<br />

kterém bylo zmíněno v kapitole (3.1.1). Podporuje stromovou strukturu, rozmanité efekty,<br />

shadery, světla, interpolaci, atd. Obecně je nedodělaný a zatím nepoužitelný pro větší projekt,<br />

ale určitou perspektivu před sebou má, protože vychází z X3D. GLGE jako jeden z mála<br />

frameworků disponuje rozsáhlejší dokumentací a zajímavými příklady. Podporuje základní<br />

vlastnosti OpenGl ES. Explicitně chybí fyzikální systém. Třídy nejsou vždy ideálně navrženy<br />

a neuškodilo by rozdělení na více modulů. CubicVR 3D má slibné příklady, velice působivou<br />

dokumentaci a obsahuje základní matematiku (vektory, matice). Používá OPP přístup kombinovaný<br />

s objektovými poli, které se předávají jako parametr. Gettery a settery nejsou díky<br />

tomu potřeba, což udělalo kód přehlednějším. Toto API plně nepodporuje animace, fyziku,<br />

křivky, vlastní renderery. Je naimplementována většina známých světel. Obecně se jedná<br />

o velice zdařile navrženou architekturu od matematických možností po shadery. Podporuje<br />

formát COLADA.<br />

Obecně mají frameworky problém s horší dokumentací, nejsou dodělané a není vždy<br />

jisté, zda jejich vývoj bude dále pokračovat. Zatímco většina frameworků podporuje meshe,<br />

modely, kamery, osvětlení, jeden renderer. Pokročilejší funkce jako animace, fyzika, octrees,<br />

zvuky, video textury, sít’ování chybí. Také toto byly hlavní důvody, proč se výsledná platforma<br />

začala tvořit od začátku, nebylo by vždy jisté, zda budou naimplementovány potřebné<br />

vlastnosti. Kdyby existovalo opravdu dokonalé API, nebylo by celkem co řešit, ale WebGl je<br />

tu jen krátce a frameworky mají určité porodní bolesti. Proto bylo rozhodnuto, že platforma<br />

nebude vycházet z žádného existujícího frameworku a vytvoří se nová.<br />

10


4.2 Architektura platformy<br />

Návrh celé plaformy je stěžejní částí této <strong>práce</strong>. Špatný návrh by mohl způsobit velké komplikace<br />

v průběhu budoucího vývoje.<br />

V podkapitole 4.2.1 se hledají různé techniky, které by mohly být použity ve výsledné<br />

platformě. V podkapitole 4.2.2 je přiblížen problém javascriptu s veřejnými a privátními proměnnými<br />

či metodami. V podkapitole 4.2.3, respektivě v příloze B na straně 56 se nachází<br />

přehledový diagram platformy. V podkapitolách 4.2.4 a 4.1 jsou popsány vlastnosti konstruktoru<br />

GameObject a možné komponenty, které lze přiřadit případnému objektu. Další<br />

podkapitola 4.2.6 popisuje, jakým způsobem jsou do scény nahrávána data ze souboru json.<br />

Hlavní uzel scény je detailněji přiblížen v podkapitole 4.2.7. Jak jsou v platformě uspořádány<br />

shadery, je možné nalézt v podkapitole 4.2.8. Poslední podkapitola 4.2.9 se zaměřuje na vstup<br />

z klávesnice.<br />

4.2.1 Inspirace pro návrh<br />

Inspirace pro návrh byla hledána u jiných frameworků. Svým poměrně jednoduchým návrhem<br />

zaujal framework GLGE[10]. Ten využívá při tvorbě vlastností javascriptu, který umožňuje<br />

řetězení prototypů a také dynamicky přidávat a nebo odebírat metody či proměnné určitého<br />

objektu. Zde je malý příklad konstruktoru Group:<br />

GLGE. Group=f u n c t i o n ( uid ){<br />

t h i s . c h i l d r e n = [ ] ;<br />

var that=t h i s ;<br />

t h i s . downloadComplete=f u n c t i o n ( ) {<br />

i f ( that . isComplete ( ) )<br />

that . f i r e E v e n t ( ”downloadComplete ”) ;<br />

}<br />

GLGE. Assets . r e g i s t e r A s s e t ( t h i s , uid ) ;<br />

}<br />

GLGE. augment (GLGE. Placeable ,GLGE. Group ) ;<br />

GLGE. augment (GLGE. Animatable ,GLGE. Group ) ;<br />

GLGE. augment (GLGE. QuickNotation ,GLGE. Group ) ;<br />

GLGE. augment (GLGE. JSONLoader ,GLGE. Group ) ;<br />

Z výše uvedeného kódu je možné vyčíst několik věcí :<br />

ˆ Každá metoda, či konstruktor začíná slovem GLGE, které nejen informuje, o tom,<br />

že se jedná o konkrétní framework, ale také omezuje kolize mezi jinými použitými<br />

javascriptovskými aplikacemi, které by náhodou obsahovaly stejnou metodu se stejným<br />

názvem. Pro výslednou platformu byla zvolena proměnná WGLP(WebGl Platform),<br />

která bude v budoucnu nejspíš nahrazena jiným slovem.<br />

ˆ Dále zaujme metoda augment. Prvním parametrem je konstruktor, jehož vlastnosti přiřazené<br />

prototypu budou přidány do prototypu konstruktoru, který se metodě předává<br />

11


pomocí druhého parametru. Prototyp konstruktoru Group bude ve výše uvedeném<br />

případě rozšířen o vlastnosti prototypů konstruktorů Placeable a Animatable. Group<br />

tím tyto vlastnosti přijme za své. Jedná se konkrétně o uzel libovolného stromu, který<br />

bude moci být umístěn a nebo animován. Tato metoda je velice užitečná a bude zajisté<br />

naimplementována do nové platformy. Takový postup přidávání vlastností má ale tu<br />

nevýhodu, že by se programátor mohl za chvíli ztrácet v tom, jakou vlastnost daný<br />

objekt má.<br />

Trochu jinou filozofii využívá vývojová platforma Unity z kapitoly (3.1.3), která se stala<br />

hlavním zdrojem inspirací pro výslednou platformu. Každý objekt ve scéně je typu Game-<br />

Object, který má určité Id. Dále se podle potřeby přidávají různé komponenty, které jsou<br />

nutné k dosažení potřebného efektu. Mezi komponenty patří například Transform, Renderer,<br />

RigidBody, Světlo, Kamera, Animace, atd. Chceme-li například animovaný objekt, je<br />

nezbytné vytvořit GameObject, poté přiřadit komponenty Renderer, která má na starosti<br />

rendering, Transform, pomocí které je objekt pozicován a nakonec Animace, která zařídí<br />

výslednou animaci. Velice zajímavá je komponenta Script, pomocí které je možné přiřadit<br />

logiku danému objektu.<br />

Všechny výše zmíněné vlastnosti platformy Unity přebírá výsledně vytvořená platforma.<br />

4.2.2 Privátní proměnné<br />

Javascript ve své implementaci nezná pojem veřejná a privátní proměnná. Pro potřeby platformy<br />

by bylo vhodné proměnné či metody takovým způsobem odlišit. Pomocí určitých<br />

programových struktur lze dosáhnout podobných vlastností, které privátní a veřejné metody(proměnné)<br />

mají, ale kód by se stal složitějším a méně přehledným. Proto bylo přistoupeno<br />

k velice jednoduchému až primitivnímu řešení. Před každou privátní metodou nebo<br />

proměnou se bude nacházet dolní podtržítko. Takto vývojář ihned na první pohled pozná,<br />

s jakou metodou aktuálně pracuje. Příkladem privátní proměnné může být position” z<br />

”<br />

komponenty Transform.<br />

4.2.3 Přehledový diagram<br />

Přehledový diagram se nachází v příloze B na straně 56. Vybrané části jsou popsány v<br />

následujících podkapitolách.<br />

4.2.4 Objekt GameObject<br />

Každý objekt, který bude umístěn do scény by měl být vytvořen konstruktorem GameObject(id)<br />

se zvoleným Id, které musí být unikátní. Dále do vytvořeného objektu GameObject<br />

mohou být přidávány různé komponenty, což přibližuje následující obrázek (4.1)<br />

12


Obrázek 4.1: GameObject a možné komponenty<br />

Z výše uvedeného obrázku 4.1 je patrné, že objektu mohou být nastaveny proměnné,<br />

které určují:<br />

ˆ Zda objekt může kolidovat s ostatními objekty ve scéně.<br />

ˆ Jestli se objekt pohybuje a nebo je statický.<br />

ˆ Zda je objekt ve scéně viditelný.<br />

ˆ Jestli je objekt průhledný či nikoliv.<br />

ˆ V neposlední řadě lze objekt přiřadit ke konkrétní skupině. Například se může jednat o<br />

asteroid, vesmírnou lod’, a podobně. Konkrétní příklad použití lze nalézt u kolizí, kdy<br />

je někdy potřeba vyřadit jeden pár objektů, který mezi sebou nemá nikdy kolidovat.<br />

Může se jednat například o laser, který není schopen zasáhnout vesmírnou lod’.<br />

ˆ Poslední, ale důležitá vlastnost se týká vlastníka objektu. Vždy při zavolání konstruktoru<br />

GameObject je této proměnné přiřazena hodnota self”, která říká, že objekt patří<br />

”<br />

uživateli, který sedí aktuálně u PC. Vlastníkem ale může být například server nebo jiný<br />

vzdálený uživatel. Takto lze určit, kdo má daný objekt pod kontrolou a může s ním<br />

popřípadě hýbat.<br />

4.2.5 Komponenty objektu GameObject<br />

Transform je velice důležitá komponenta, pomocí které je možné objekt pozicovat, rotovat,<br />

a to bud’ relativně ke svému předkovi a nebo absolutně ve světových souřadnicích.<br />

Ostatní hodnoty se vždy dopočítají automaticky. Pomocí tohoto uzlu je dále možné vytvářet<br />

hierarchii objektů. Každý uzel Transform může mít neomezeně mnoho potomků. V<br />

13


neposlední řadě existují možnosti zvětšování / zmenšování, přepočítání lokálního bodu do<br />

světových souřadnic, to samé platí i v opačném směru, atd. Všechny změny provedené v uzlu<br />

Transform jsou postupně propagovány stromovou strukturou až k listům.<br />

Obrázek 4.2: Obrázek znázorňuje objekty, které mezi sebou komunikují, pokud nastane<br />

změna v komponentě Transform a nebo v objektu GameObject.<br />

Výše uvedený obrázek 4.2 znázorňuje objekty, které mezi sebou komunikují, pokud nastane<br />

důležitá změna v komponentě Transform, a nebo v objektu GameObject. Například,<br />

pokud dojde k pohybu objektu, tak uzel Transform neprodleně informuje všechny své zaregistrované<br />

pozorovatele o dané změně. Při vytváření nového objektu pomocí konstruktoru<br />

Transform se mezi pozorovatele automaticky přidá objekt Hierarchy, který má za úkol informovat<br />

o změně všechny přímé i nepřímé potomky, které na základě nových dat změní<br />

také svůj stav. Mezi pozorovateli se dále může nacházet například obalové těleso přiřazené<br />

přímo objektu GameObject, a nebo jeho rendereru, pokud samozřejmě nějaký vůbec má.<br />

Obalové těleso je automaticky přidáno mezi pozorovatele, pokud je přiřazeno objektu game-<br />

Object, a nebo případnému rendereru. Všechna tělesa by také měla mít naimplementovanou<br />

metodu update(), která je volána v případě , že nastane změna a je potřeba změnit pozici<br />

či orientaci obalového tělesa. Objekt Hierarchy nemá na starosti pouze aktualizaci všech potomků,<br />

které jsou instance Transform, ale také informuje kořenový uzel scény VirtualWorld<br />

o požadovaných změnách. Konkrétně se jedná především o informace, zda objekt instance<br />

GameObject přiřazený uzlu Tranform nezměnil některou ze svých proměnných. Například<br />

jestli se z dynamického objektu nestal statický. Na základě těchto dat by následně došlo k<br />

aktualizaci kolekcí, ve kterých si uchovává VirtualWorld ukazatele na různé typy objektů.<br />

Více o VirtualWorld je v kapitole 4.2.7.<br />

Pro uložení pozice v uzlu Transform je použit třísložkový vektor. Rotace jsou uloženy<br />

ve formě matic o velikosti 4x4. Jedná se o redundanci, protože pro rotační matici dostačuje<br />

velikost 3x3. Použitá knihovna gl-matrix[11] pro výpočet matic pracuje primárně s maticemi o<br />

velikosti 4x4, proto byla zvolena tato velikost. Matice nejsou jedinou volbou pro uložení rotace<br />

objektu, velice často se používají Kvaterniony. Jejich výhoda spočívá především ve snadnější<br />

a lepší interpolaci. Další výhodou je menší pamět’ová náročnost, protože jsou uloženy ve<br />

formě čtyř reálných čísel. Grafické karty pracují pouze s maticemi, proto je vždy potřeba<br />

každý kvaternion převést před renderováním do maticové formy. Výhody kvaternionů nejsou<br />

pro výslednou platformu až tak zásadní, proto jsou rotace uloženy ve formě matic, z kterých<br />

14


je možné ihned extrahovat jednotlivé osové vektory(up, right, forward), což se v některých<br />

případech hodí.<br />

RigidBody je komponenta, která zaručí, že bude mít objekt určité fyzikální vlastnosti.<br />

Více o rigidních tělesech je napsáno v podkapitole 4.4 na straně 27, kde jsou informace<br />

týkající se použitého fyzikálního systému. K použití komponenty dojde v případě, kdy je<br />

potřeba, aby byl objekt ovlivňován různými fyzikálními vlivy.<br />

Camera je hluboce svázána s komponentou Transform, protože upravuje její pozici a rotaci.<br />

Kamera se ve skutečnosti nikam nepohybuje, stále se nachází v počátku světového<br />

souřadnicového systému a je natočena směrem k ose Z v negativním směru. Musí být tedy<br />

hýbáno s okolním světem přesně v opačném směru. Takzavaná View matice, kterou si kamera<br />

uchovává je vypočítána jako inverze z modelové matice, která je dodána pravě komponentou<br />

Transform. Velice důležitou maticí pro rendering je projekční matice, která se také nachází<br />

v již zmíněné komponentě. Kameře je možné přiřadit avatara a případně používaný skybox.<br />

Její součástí je také takzvané ViewFrustum, které definuje viditelnou oblast pomocí šesti<br />

rovin, které musejí být při každém pohybu kamery přepočítány.<br />

BoundingVolume je komponenta, která zaručuje obklopení objektu obalovým tělesem.<br />

Idea je taková, že téměř každý objekt může jím může být obklopen. Těleso by nemělo obklopovat<br />

pouze objekt, ke kterému je přiřazeno, ale také všechny objekty, které se nacházejí v<br />

hierarchii pod ním. Pokud dojde k posunutí nebo k rotaci objektu, je nutné také aktualizovat<br />

polohu obalového tělesa. Více o použitých obalových tělesech je napsáno v podkapitole 4.3.<br />

Script je komponenta, která může být přiřazena každému objektu, a pomocí které může<br />

být objekt obohacen o určitou logiku. Například ve výsledné ukázce je takto uděláno ovládání<br />

a chování vesmírné lodi. Každá komponenta Script musí mít povinně metodu start(),<br />

která provádí počáteční nastavení dle potřeby uživatele. Další povinnou metodou je update(duration),<br />

která je spuštěna v každém snímku a očekává hodnotu intervalu, o kterém<br />

je více napsáno v kapitole 4.4.1.<br />

NetworkView<br />

Každý objekt, který je sdílený mezi uživateli po síti, musí mít přiřazenu<br />

komponentu NetworkView, která obsahuje Id, které jednoznačně identifikuje objekt v síti.<br />

15


Obrázek 4.3: Komponenta NetworkView a všechny důležité třídy se kterými spolupracuje.<br />

Komponenta poskytuje dvě důležité metody sendMessage a onMessage, které slouží pro<br />

příjem a odesílání dat týkajících se daného objektu. Odeslané zprávy se doručí všem uživatelům<br />

v síti, kteří mají ve scéně objekt se stejným Id. Objektům, které jsou řízeny takto na<br />

dálku a nejsou ovládané uživatelem, je potřeba přiřadit komponentu Script, která obstará<br />

příjem příchozích zpráv pomocí metody onNetworkViewMessage, a která změní například<br />

stav objektu či provede jeho odstranění ze stromu. Jedná se o upravený skript, o kterém je<br />

více napsáno zde [25]. Skript by měl být přiřazen komponentě NetworkView, k čemuž slouží<br />

proměnná observer. Tím je docíleno toho, že v případě příchodu nové zprávy je zavolána<br />

výše uvedená metoda skriptu, které se neprodleně předají příchozí data. Skript by měl navíc<br />

obsahovat proměnnou interpolationEnabled, která říká, jestli má dojí k interpolaci mezi posledními<br />

známými stavy objektu. Z toto důvodu si skript pamatuje přibližně posledních 15<br />

stavů objektů. Stavem se většinou myslí pozice, rotace a rychlost. V samotné metodě update<br />

komponenty Script by mělo docházet k již zmíněné interpolaci.<br />

Renderer je komponenta, která si uchovává data potřebná k renderování. Především by<br />

měla obsahovat informace o geometrické reprezentaci, materiálech, texturách a bufferech.<br />

Ve scéně jsou naimplementovány celkem tři renderery. Konkrétně se jedná o MeshRenderer,<br />

BillboardRenderer a SkyboxRenderer. První dva zmíněné jsou detailněji popsány v kapitolách<br />

4.2.6 a 5.6.1. Každý z nich obsahuje název shaderu, jehož pomocí má být vyrenderován<br />

výsledný objekt. Další podmínkou pro správnou funkci komponenty je přítomnost metody<br />

render, která má za úkol zavolat zkompilovaný program, který provede samotný rendering.<br />

Metoda na vstupu očekává projekční a takzvanou view” matici, které jsou dostupné v kameře.<br />

”<br />

Light<br />

je komponenta mající na starosti světla. Ve výsledné platformě zatím světla nejsou<br />

naimplementována.<br />

16


4.2.6 Nahrání dat do scény<br />

Některé stávající frameworky podporují pro nahrávání dat do scény formát COLLADA[16]<br />

založený na XML. Jde o velice komplexní formát, který neobsahuje pouze geometrii objektů,<br />

ale také podporuje animace, efekty, shadery, inverzní kinematiku a podobně. Výhoda formátu<br />

Collada spočívá, že je pod záštitou stejné společnosti, která provedla standardizaci WebGl a<br />

také, že je podporován některými modelovacími nástroji. Z pohledu výsledné platformy jde<br />

o zbytečně komplikovaný formát. Jedná se ale o zajímavou alternativu, která by mohla být<br />

v budoucnu naimplementována, pokud by bylo zapotřebí nahrávat komplikovanější scény z<br />

externího souboru.<br />

Platforma nahrává informace o geometrických objektech z JSON souboru, který může<br />

vypadat takto:<br />

{<br />

”name ”: ”Vesmír ” ,<br />

” d e s c r i p t i o n ”: ” V i r t u a l n i r e a l i t a ve vesmiru ” ,<br />

” e x t e r n a l o b j e c t f i l e s ”: [<br />

{ ”id ”: ” VesmirnaLod ” , ” o b j e c t f i l e ”: ” spaceShip . obj ” ,<br />

” m a t e r i a l f i l e ”: ” spaceShip . mtl ”} ,<br />

{ ”id ”: ” Brana ” , ” o b j e c t f i l e ”: ” gate . obj ” ,<br />

” m a t e r i a l f i l e ”: ” gate . mtl ”}<br />

] ,<br />

”meshes ”: {<br />

”nazevMeshe ”: { ” vertexCoords ”: [ ] , ” normalCoords ”: [ ] ,<br />

”UV”: [ ] , ” f a c e I n d i c e s ”: [ ] , ” nazevTextury : ” ”. . . ”<br />

}<br />

} ,<br />

” m a t e r i a l s ”: {<br />

nazevMaterialu : { ”AmbientColor ”: [ ] , ”specularColor ”: [ ] ,<br />

” d i f f u s e C o l o r ”: [ ] , alpha : 1<br />

}<br />

} ,<br />

” t e x t u r e s ”: {<br />

”brana−vyrazna zare ”: { t e x t u r e S c a l e : [ 1 , 1 ] ,<br />

fileName : ”brana−vyrazna zare . png ” } ,<br />

”brana−zare ”: { t e x t u r e S c a l e : [ 1 , 1 ] ,<br />

fileName : ”brana−zare . png ” }<br />

} ,<br />

” o b j e c t s ”: [ ]<br />

}<br />

JSON soubor obsahuje meshe, materiály, textury. Další důležitou položkou je external<br />

”<br />

object files”, která říká, z jakých externích souborů se mají načíst další data a jaký má<br />

mít načtený objekt název.<br />

17


Ze zmíněných souborů jsou načteny další meshe, textury, materiály a v neposlední řadě<br />

informace o objektech, které mají být z těchto komponent vytvořeny. Informace o objektech<br />

a jejich komponentách jsou následně uloženy do poslední položky objects”. ”<br />

Průběh načítání dat do scény znázorňuje následující obrázek 4.4:<br />

Obrázek 4.4: Obrázek znázorňuje načtení geometrických objektů do scény včetně materiálů<br />

a textur<br />

Uživatel, který si přeje vytvořit novou kopii renderovatelného objektu, zavolá metodu<br />

objektu JsonLoader, do které vloží dvě důležité informace:<br />

ˆ Název objektu, jehož nová kopie se má vytvořit. Ten se musí shodovat s názvem uloženým<br />

v položce ”<br />

objects” ve výše zmíněném JSON souboru.<br />

ˆ Druhým parametrem je id nově vzniklého GameObjectu<br />

Platforma zatím podporuje pouze jeden externí formát obj, což je jednoduchý datový formát,<br />

který uchovává 3D geometrii jednoho nebo více objektů. Z tohto formátu lze vyčíst<br />

pozici každého vertexu, UV pozici pro každý vertex, normály a jednotlivé plošky, které jsou<br />

z vertexů vytvořeny(tzv. faces). Formát poskytuje informace, jaký materiál je přiřazen konkrétním<br />

ploškám. V jednom obj souboru může být najednou více objektů, ale všechny sdílejí<br />

jeden společný lokální souřadnicový systém. Pokud je v jednom souboru více objektů, tak<br />

se v takovém případě vytvoří jeden kořenový objekt, který bude mít potomky odpovídající<br />

objektům v souboru. S každým souborem je většinou svázán mtl formát, který si uchovává<br />

informace o materiálech.[17] Z každého materiálu je potřeba získat vlastnosti ambient, diffuse,<br />

specular a průhlednost. Popřípadě název textury a její velikost.<br />

Při exportu objektů do formátu obj ze známých modelářů je nutné si dát pozor na několik<br />

věcí:<br />

18


ˆ Model před exportem musí být složen z trojúhelníků, čtyřhranné polygony nejsou podporovány.<br />

ˆ Při tvorbě materiálů je nutné vybrat takový, aby obsahoval výše zmíněné složky.<br />

ˆ Geometrická reprezentace objektu musí nést informace jak o vertexech, UV souřadnicích,<br />

tak o normálách. Ani jedna složka nesmí chybět.<br />

Mesh renderer má za úkol uchovávat důležitá data pro rendering objektu. Především<br />

musejí být vytvořeny a naplněny buffery, které používá grafická karta. Bufferů, které<br />

uchovávají indexy, může být více, protože části, které mají své vlastní materiály, musejí<br />

být vyrenderovány odděleně. O bufferech již bylo psáno v 3.2.2 na straně 7. Mesh renderer<br />

přibližuje následující obrázek :<br />

Obrázek 4.5: Mesh renderer, přiřazený mesh, buffery a materiály<br />

Struktura MeshRenderu vlastně kopíruje jeden objekt uložený v obj formátu. Jednotlivé<br />

meshe, materiály, textury se mohou ve scéně opakovat vícekrát, proto jsou uloženy pouze<br />

na jednom místě v objektu Components. Mesh renderery se pouze odkazují na jednotlivé<br />

stavební komponenty, z kterých se objekt skládá.<br />

4.2.7 VirtualWorld<br />

Objekt VirtualWorld tvoří základní uzel celé scény. Pozor, nejedná se o konstruktor, ale již<br />

vytvořený objekt.<br />

19


Obrázek 4.6: Objekt VirtualWorld se všemi objekty, na které si drží referenci.<br />

Jakmile se ve scéně vytvoří prví uzel Transform, měl by být ihned přiřazen objektu VirtualWorld,<br />

aby došlo při následném renderování k vykreslení všech objektů ve stromu. Je<br />

doporčeno vždy vytvořit GameObject s identifikátorem root”, jehož komponenta Transform<br />

”<br />

bude přiřazena objektu VirtualWorld. Tento základní uzel scény si dále drží odkazy na stavební<br />

komponenty objektů, aktuálně používanou kameru, na všechny dynamické,statické a<br />

renderovatelné objekty GameObject” ve stromu. Ke všem objektům GameObject”, které<br />

” ”<br />

se nacházejí v hierarchické struktuře je možné přistupovat pomocí speciální proměnné $”. ”<br />

Například, pokud je potřeba pracovat s objektem GameObject” s id SpaceShip2”, tak se<br />

” ”<br />

použije následující zápis:<br />

var spaceShip = VirtualWorld . $ [ ’ SpaceShip2 ’ ] ;<br />

spaceShip . transform . rotateLocalY ( 9 0 ) ;<br />

V případě, že je ve scéně použit strom Octree, o kterém je napsáno více v kapitole 4.5.2<br />

na straně 30 nebo řadící algoritmus jménem Sort and sweep, měli by být jejich reference<br />

přiřazeny k objektu VirtualWorld, který si zároveň drží ukazatel na celou scénu. Jelikož se<br />

kolekce objektů zobrazené na obrázku 4.6 neustále mění, je potřeba informovat všechny pozorovatele,<br />

kteří se nacházejí v poli Observers. Jako příklad může posloužit strom Octree,<br />

který uchovává pouze statické objekty. Pokud je nějaký statický objekt odstraněn z kolekce,<br />

je nutné také smazat referenci na obalové těleso objektu ve stromu. Octree strom je<br />

automaticky přidán mezi pozorovatele hned v momentě, kdy se na něj VirtualWorld dozví<br />

referenci.<br />

4.2.8 Shadery<br />

Ze začátku vývoje byly shadery uloženy ve zvláštním souboru, který se načítal pomocí Ajaxu.<br />

Nevýhody zmíněného řešení spíše převažovaly nad klady. Javascript nemá právo zapisovat<br />

do souborů na disku, takže editace souboru musela být řešena pomocí serveru. Aktuální<br />

řešení zabudovává zdrojový kód shaderů přímo do zdrojového kódu javascriptu. Sice je psaní<br />

kódu zdlouhavější, ale naopak může být shader dynamicky rozšířen podle potřeby o některé<br />

funkce. Například mohou být někde připravené shaderovské funkce, které mají na starosti<br />

jednotlivé typy světel. V případě, že by byl konkrétní typ světla použit, mohla by být funkce<br />

20


do kódu dynamicky přidána. Pro uchovávání zkompilovaných shaderů slouží již vytvořený<br />

objekt WGLP.ShaderPrograms.<br />

Obrázek 4.7: Všechny objekty a konstruktory, které v platformě mají na starosti shadery.<br />

Každý renderer musí obsahovat název shaderu, který má být použit pro renderování<br />

konkrétního objektu. Při renderingu dojde k přepnutí na potřebný shader pomocí metody<br />

useProgram(jmenoShaderu). V objektu ShaderPrograms může existovat libovolné množství<br />

zkompilovaných shaderů pod různými jmény. Pro renderování normálních geometrických<br />

objektů je připraven defaultní shader. Taktéž je k dispozici program pro renderování skyboxu.<br />

Shadery nejsou v počátečním stavu zkompilovány, proto je potřeba vždy zavolat metodu<br />

initDefaultShaders(). Pod pojmem shader se skrývá dvojice vertex shader, fragment shader.<br />

Na následujících několika řádcích je část ukázky z kapitoly 3.2.2 na straně 5 přepsána do<br />

kódu vytvořené platformy:<br />

var sP = WGLP. ShaderPrograms ;<br />

var vertexShader = new WGLP. Shader ( ) ;<br />

vertexShader . setType ( ” vertex ”) ;<br />

vertexShader . addSCLine ( ” a t t r i b u t e vec3 poziceVertexu ; ”) ;<br />

vertexShader . addSCLine ( ”uniform mat4 p r o j e k c n i M a t i c e ; ”) ;<br />

vertexShader . addSCLine ( ”uniform mat4 MMatice ; ”) ;<br />

vertexShader . addSCLine ( ”{ ”) ;<br />

vertexShader . addSCLine ( ” g l P o s i t i o n = p r o j e k c n i M a t i c e * MMatice *<br />

vec4 ( poziceVertexu , 1 . 0 ) ; ”) ;<br />

vertexShader . addSCLine ( ”} ”) ;<br />

vertexShader . compileShader ( ) ;<br />

Stejným způsobem jako výše je nutné zkompilovat fragment shader. Poté se vytvoří program<br />

pomocí následující metody:<br />

var program = sP . createShaderProgram ( vertexShader ,<br />

fragmentShader , ” nazevShaderu ”) ;<br />

V dalším kroku je zapotřebí získat lokace proměnných attribute a uniform, aby jim mohly<br />

být přiřazeny hodnoty.<br />

sP . assignUniformsLocation ( program , [ ” p r o j e k c n i M a t i c e ” , ”MMatice ”] ) ;<br />

sP . a s s i g n A t t r i b u t e s L o c a t i o n ( program , [ ” poziceVertexu ”] ) ;<br />

21


Výše vytvořená proměnná program” v tuto chvíli obsahuje proměnné uniforms a attributes,<br />

které tvoří asociativní pole, které obsahuje lokace shaderovských proměnných. K lokacím<br />

”<br />

je možné přistupovat takto:<br />

var l o k a c e = program . uniforms [ p r o j e k c n i M a t i c e ] ;<br />

V posledním kroku musí být objektu program přiřazena metoda render, která má na starosti<br />

naplnění shaderovských proměnných potřebnými daty pro vyrenderování konkrétního<br />

objektu, a která nakonec zavolá funkci pro vykreslení.<br />

program . render = f u n c t i o n ( gameObject , , p r o j e c t i o n M a t r i x ){<br />

.<br />

t ě l o metody<br />

.<br />

}<br />

4.2.9 Vstup z klávesnice<br />

Součástí platformy je již vytvořený objekt WGLP.Input, který usnadňuje práci se vstupem.<br />

Pozor, nejedná se o konstruktor.<br />

Obrázek 4.8: Objekt Input s přidruženými objekty<br />

Na začátku je vždy nutné obsloužit události z klávesnice. K tomuto účelu slouží metody<br />

handleKeyDown a handleKeyUp, které musí být volány, kdykoliv nastanou události ”<br />

Key-<br />

Down” a ”<br />

keyUp”. Objekt Input si uchovává asociativní pole currentlyPressedKeys, kde ke<br />

každému kódu klávesy je přiřazena hodnota true nebo false, podle toho, zda je konkrétní<br />

klávesa zmáčknuta.<br />

Existuje několik možností, jak lze objekt Input využít:<br />

1. Použitím metody getKey(nazevKlavesy) lze zjistit, zda je klávesa s požadovaným názvem<br />

aktuálně zmáčknuta. Metodu je možné použít na všechny názvy základních kláves.<br />

Čísla se zadávají ve tvaru NUM0,NUM2,.., NUM9”.<br />

”<br />

22


2. Další možností je objektu Input přiřadit pozorovatele na konkrétní klávesu. Takový<br />

pozorovatel musí mít naimplementovánu metodu update(param1, param2), kde první<br />

parametr říká, zda došlo ke stisknutí nebo uvolnění klávesy. Druhým parametrem je<br />

název klávesy, která vyvolala danou událost. Pozorovatele lze přidat metodou addKey-<br />

Observer(klic, observer). Metoda, která odstraní dvojici klíč - pozorovatel” se jmenuje<br />

”<br />

removeKeyObserver(klic, observer).<br />

3. Zbývá poslední metoda se jménem getAxis(jmenoOsy). V objektu Input je defaultně<br />

uloženo několik os. Každá osa si uchovává svůj název a dva kódy požadovaných kláves.<br />

Pokud je zmáčknuta první klávesa, metoda vrátí hodnotu -1. Pokud je zmáčknuta<br />

druhá klávesa, metoda vrátí hodnotu 1. Pokud ani jedna z těchto kláves není zmáčknuta,<br />

metoda vrátí hodnotu 0. Jedná se o to, že se vlastně definují klávesy pro kladný<br />

a záporný pohyb po dané ose. V případě, že nám stávající osy nevyhovují, je možné<br />

přidat své vlastní, a to tak, že se vytvoří nový objekt, který bude rozšiřovat ten stávající.<br />

K tomuto slouží metoda WGLP.extend, založená na jQuery[26] knihovně, kterou<br />

platforma využívá. Poté stačí do pole Input.Axes přidat osu s novým názvem a přiřadit<br />

jí dva nové kódy kláves. Metody getAxis(jmenoOsy) lze například využít při ovládání<br />

vesmírné lodi. Lze nadefinovat osu pohybu vpředVzad”, přiřadit jí potřebné klávesy<br />

”<br />

a pak už jen stačí sílu motoru vynásobit návratovou hodnotou funkce. Síla bude bud’<br />

kladná nebo záporná, při nulové hodnotě nulová. Pak už stačí sílu předat objektu<br />

RigidBody a ten už se o zbytek postará sám.<br />

4. Objekt Input obsahuje asociativní pole Input.KeyMap, které pod každým názvem klávesy<br />

uchovává její kód. Existuje také pole Input.rKeyMap, které si naopak uchovává<br />

kódy a přiřazuje k nim názvy kláves.<br />

4.3 Obalová tělesa<br />

Ačkoliv je možné koliznímu systému předat celý objekt, tak jak byl vymodelován, je zde<br />

několik důvodů, proč daný objekt aproximovat či obalit jiným geometrickým tělesem. [13]<br />

Takové těleso musí kopírovat pohyb původního objektu. Obrázek 4.9 obsahuje pětici dnes<br />

nejvíce používaných obálek.<br />

Obrázek 4.9: Nejpoužívanější obalová tělesa. Převzato z [13]<br />

23


Dnešní počítače nejsou dostatečně rychlé na to, aby 60x za sekundu zkontrolovaly, zda<br />

nekoliduje mezi sebou 50 různých geometrických objektů, které se navíc skládají například<br />

z 10000 trojúhelníků. V takovém případě by bylo nutné ověřit kolizi jednoho trojúhelníku<br />

se všemi ostatními, a to je nemožné v reálném čase. V následujících podkapitolách se budou<br />

rozebírat a hodnotit jednotlivé naimplementované typy obalových těles. V podkapitole 4.3.4<br />

se přibližují všechny možné naimplementované testy kolizí. Sekci uzavírá podkapitola 4.3.5,<br />

která popisuje případný objekt Contact, který slouží k uchovávání kolizních dat a obsahuje<br />

metody na jejich vyhodnocení.<br />

4.3.1 Obalová koule<br />

Obalová koule může být přiřazena jak celému GameObjectu, tak pouze MeshRendereru,<br />

o kterém bylo více napsáno v kapitole 4.2.6 na straně 19. Existují různé algoritmy, které<br />

dokáží rychle a efektivně vypočítat ze sady vertexů obalovou kouli, která je jednoznačně<br />

definována pozicí středu a poloměrem. Ve výsledné platformě je naimplementován Jackův<br />

Ritterův algoritmus, který pracuje v lineárním čase.[14] Výsledná obalová koule je maximálně<br />

o 5% větší než minimální možný výsledek. Algoritmus se provádí ve dvou fázích:<br />

ˆ V první fázi se ke každé ose naleznou maximální a minimální hodnoty. Z těchto hodnot<br />

je vypočítána prvotní koule.<br />

ˆ Ve druhé fázi se každý bod porovná s aktuální koulí. Pokud se bod nachází mimo kouli,<br />

tak dojde ke zvětšení poloměru a k upravení pozice středu.<br />

4.3.2 OBB<br />

Zkratka OBB znamená v angličtině Oriented bounding box, což je libovolně orientovaný<br />

kvádr. Existuje mnoho reprezentací tohoto kvádru. Jako nejvýhodnější se jeví reprezentace,<br />

kdy se uchovává polovina velikosti kvádru ve všech směrech. Rotace je uložena ve formě matice,<br />

jako je tomu u komponenty Transform. Reprezentace v tomto tvaru umožňuje snadnější<br />

test kolize mezi dvěma kvádry. Nalezení nejmenšího kvádru není triviální záležitost. Existuje<br />

například metoda, kdy se kvádr natáčí postupně v různých směrech a hledá se nejmenší<br />

kvádr. Již podle popisu jde o velice nepraktický a zdlouhavý algoritmus. Původně byl naimplementován<br />

ve výsledné platformě, ale nakonec se od něj upustilo. Pokud se kvádr natáčel<br />

do všech směrů a krok natočení byl 10°, tak i přes to výpočet trval neúměrně dlouho.<br />

24


Obrázek 4.10: Nalezený OBB ve 2D. Převzato z [15]<br />

O mnoho lepší algoritmus[15], který k výpočtu využívá kovarianční matici, dojde k požadovanému<br />

kvádru v několika krocích:<br />

ˆ Vstupem je pole vertexů, ze kterých se vypočítá průměrná pozice, která je použita pro<br />

výpočet kovarianční matice spolu se vstupními vertexy.<br />

ˆ Dalším krokem je nalezení vlastních vektorů kovarianční matice C, které definují natočení<br />

výsledného kvádru. Pro vlastní čísla a vektory platí následující vztah : (C -<br />

lambda*E) * v = 0, na který lze nahlížet jako na homogenní soustavu lineárních rovnic<br />

o n neznámých. Ta má nenulové řešení, pokud je det(C - lambda*E) = 0. Vlastní čísla<br />

jsou kořeny kubického polynomu. Vlastní vektory je možné získat vyřešením již zmíněné<br />

soustavy rovnic. Pozici středu a velikost kvádru je již snadné dopočítat pomocí<br />

skalárních součinů a sčítáním vektorů.<br />

Výše zmíněný algoritmus není vhodný pro objekty, kde se vertexy vyskytují ve shlucích. Z<br />

toho vyplývá, že je vhodný pouze na jednotlivé meshe. Pokud by se používal pro obalení<br />

více meshů najednou, tak by výsledky nemusely být ideální. OBB nebude tedy k dispozici<br />

jako obálka pro GameObject.<br />

4.3.3 AABB<br />

AABB je osově zarovnaný kvádr. Ve výsledné platformě se nejedná vlastně o kvádr, ale o<br />

krychli, protože je vypočítána z obalové koule. Pokud by se jednalo o standardní AABB,<br />

tak by jeho velikost musela být přepočítána vždy, když by došlo k pootočení objektu. Pozice<br />

AABB ve scéně bude uložena ve formě minimálních a maximálních hodnot na každé ose.<br />

Toto obalové těleso bylo do platformy přidáno pouze z důvodu, že jako kolizní algoritmus<br />

byl vybrán Sort and sweep, který pracuje právě s AABB. Více o tomto algoritmu je napsáno<br />

v podkapitole .<br />

4.3.4 Testy kolizí mezi tělesy<br />

Platforma v sobě integruje již vytvořený objekt jménem CollisionDetector, který má na<br />

starosti provádění testů kolizí mezi obalovými tělesy. Navíc obsahuje metodu která umí<br />

25


určit, jestli se koule nachází před rovinou nebo za rovinou. CollisionDetector dokáže také<br />

zjistit, jestli se krychle nachází za konkrétní rovinou. V neposlední řadě detekuje kolizi mezi<br />

jednotlivými uzly stromu Octree a takzvaným ViewFrustum kamery. Výsledná platforma<br />

podporuje tyto typy kolizí :<br />

ˆ Koule vs koule.<br />

ˆ Koule vs OBB.<br />

ˆ OBB vs OBB.<br />

ˆ GameObject vs GameObject s automatickým rozeznáním obalového tělesa.<br />

ˆ GameObject vs strom objektů GameObject tvořený hierarchií uzlů Transform. Opět<br />

dojde k automatickému rozpoznání obalového tělesa.<br />

ˆ AABB vs AABB.<br />

ˆ Octree vs ViewFrustum kamery.<br />

Za zmínku stojí algoritmus, pomocí kterého se testuje kolize mezi OBB a OBB. Překvapivě se<br />

nejedná o tak jednoduchý algoritmus, jak se na první pohled zdá. Anglicky se metoda testu<br />

nazývá jako Separating Axis Theorem. Princip je takový, že se nejprve oba OBB promítnou<br />

na osu. Pokud jsou promítnuté intervaly disjunktní, tak tělesa mezi sebou nekolidují. Celkem<br />

stačí otestovat 15 různých os.<br />

4.3.5 Objekt Contact<br />

V případě, že objekty mezi sebou nekolidují, tak testovací metody vrátí booleovskou hodnotu<br />

false. Jiné je to však v momentě, kdy dojde k detekci kolize. Fyzikální systém si bohužel<br />

nevystačí pouze s informací, že dva objekty do sebe narazily. Příklad kolize je na následujícím<br />

obrázku 4.11<br />

Obrázek 4.11: Ukázka kolize OBB s koulí. Převzato z [12]<br />

Zde přichází na řadu objekt Contact, který v sobě zahrnuje tyto doplňující informace:<br />

26


Kolizní normálu - Kolizní normála určuje směr, ve kterém došlo ke kolizi, a ve kterém by<br />

měla být dvě kolidující tělesa oddělena.<br />

Hloubku zanoření - Kolidující objekty se pouze nedotýkají. Jelikož se kolize testuje po<br />

určitých časových intervalech, tak dojde k zanoření objektů. Hloubka zanoření určuje,<br />

o kolik by se měla tělesa posunout ve směru/protisměru kolizní normály, aby již nedocházelo<br />

ke kolizi.<br />

Kolizní body - Kolizní bod může být jen jeden, například dvě kolidující koule se dotýkají<br />

pouze v jednom bodě. Jiný případ nastane, pokud dva OBB objekty do sebe narazí<br />

hranami, to má za následek, že vnikne více kolidujících bodů. Kontaktní body zatím<br />

nebudou naimplementovány.<br />

Koeficient odrazu - Tato vlastnost se nikterak nevypočítává. Je dána podle toho, jaká<br />

dvě rigidní tělesa kolidují.<br />

Třecí sílu - Třecí síla udává, jestli se tělesa mohou smýkat v bodě odrazu. Taktéž se nejedná<br />

o vypočítanou hodnotu, ale je součástí vlastností rigidních těles. Protože výsledný<br />

fyzikální systém nebude zatím podporovat rotace, nebude tato síla zatím naimplementována.<br />

4.4 Základní fyzikální systém<br />

Fyzikální vlastnosti objektu má ve výsledné platformě na starosti komponenta RigidBody,<br />

o které již bylo zmíněno v podkapitole 4.2.5 na straně 15. Fyzikální simulace poskytuje realističtější<br />

chování objektů, než kdyby docházelo k přímému ovlivňování uzlu Transform.[12]<br />

Hned na začátku je nutné napsat, že ve výsledku bude naimplementována jen část potřebných<br />

vlastností. Rotace budou z důvodu větší složitosti prozatím vynechány a bude je nutné<br />

naimplementovat někdy v budoucnu. Fyzikální systém se tím pádem svým chováním bude<br />

spíše blížit částicovému systému.<br />

První podkapitola 4.4.1 přibližuje integrační metodu komponenty RigidBody a popisuje<br />

samotnou komponentu. Další podkapitola 4.4.2 se zaměřuje na fyziku založenou na pružině.<br />

Poslední podkapitola 4.4.3 se zabývá registrem působících sil.<br />

4.4.1 Integrační metoda rigidního tělesa<br />

V každém snímku je zapotřebí aktualizovat pozici objektu. Integrátor se skládá ze dvou částí:<br />

ˆ První část aktualizuje pozici objektu<br />

ˆ novaP ozice =<br />

pozice ˆ + rychlost ˆ · interval<br />

ˆ Druhá část aktualizuje rychlost objektu<br />

ˆ novaRychlost =<br />

rychlost ˆ + zrychlení ˆ · interval<br />

27


Nová pozice objektu závisí na rychlosti a na zrychlení. Zatímco nová hodnota rychlosti<br />

závisí pouze na zrychlení, podle druhého Newtonova zákona, který říká, jestliže na těleso<br />

působí síla, pak se těleso pohybuje se zrychlením, které je přímo úměrné působící síle a<br />

nepřímo úměrné hmotě tělesa, se vypočte hodnota zrychlení takto :<br />

ˆ zrychlení =<br />

ˆF<br />

hmota<br />

Rigidnímu tělesu je tedy nutné předat informaci o hmotě. Integrátor vždy jako poslední<br />

operaci provede vynulování působící síly. Jednotlivé síly, které jsou předány rigidnímu tělesu<br />

se sčítají a zrychlení je vypočítáno z výsledné síly.<br />

Vstupem do integrátoru je hodnota, která udává čas, který uplynul mezi minulým a aktuálním<br />

snímkem. Frame-rate pro fyzikální systém by měl být v budoucnu vylepšen, protože<br />

každý počítač může mít frame-rate rozdílný. Používá se například stanovení hodnoty pro<br />

další frame, atd. Výsledná implementace používá stejnou smyčku pro provádění fyziky a<br />

pro rendering. Tyto smyčky se někdy oddělují a pro každou se vytvoří vlastní vlákno. V<br />

javascriptu takovou věc bohužel nelze provést, protože neumí pracovat s vlákny. Lze použít<br />

jen určitou techniku časování.<br />

Rigidní těleso obsahuje ve výsledku dvě důležité proměnné:<br />

ˆ Hmotu tělesa v kilogramech, která určuje, jak je těleso těžké a jak dobře je s ním možné<br />

hýbat.<br />

ˆ Výslednou sílu v newtonech, která v sobě obsahuje všechny síly aplikované na objekt.<br />

Jiné proměnné jako je rychlost a zrychlení by neměly být ovlivňovány přímo, ale jsou vypočítány<br />

integrační metodou.<br />

4.4.2 Pružina<br />

Pružina je ve fyzikálních enginech velice často používána. Pomocí pružiny lze naimplementovat<br />

například pohyb kamery za avatarem, pohyb vlajky, vlny na moři, pohyb oblečení,<br />

atd. Hookeův zákon matematicky popisuje chování pružiny. Hook objevil, že síla vyvinutá<br />

pružinou závisí na délce stlačení a nebo roztažení pružiny. Tento jev je určen vzorcem:<br />

ˆF = =tuhostP ružiny · roztažení ˆ<br />

Další silou, která působí proti stlačení nebo roztažení je tlumící síla, která je dána vztahem:<br />

ˆF = =tlumícíKonstanta · rychlost ˆ<br />

Tyto síly se ve výsledku sečtou a vznikne výsledná síla.<br />

Všechny tyto výpočty týkající se pružiny má na starosti konstruktor Spring. Po jeho<br />

zavolání vznikne objekt, u kterého je nutné nastavit vlastnosti vyplývající z výše uvedeného<br />

textu:<br />

ˆ tlumící konstantu<br />

ˆ tuhost pružiny<br />

28


Další dvě důležité proměnné jsou pozice a požadovaná pozice. Pokud jsou tyto hodnoty<br />

stejné, tak pružina nevyvíjí žádnou sílu. Rozdílem těchto vektorů je vektor roztažení. Z výše<br />

napsaných vztahů již zbývá jen pokrýt rychlost a jakému rigidnímu tělesu mát být vzniklá síla<br />

přiřazena. Pro tento účel slouží metoda updateForce(duration, gameObject), která by měla<br />

být volána v každém snímku. GameObject je objekt, který obsahuje komponentu RigidBody<br />

a bude mu do výsledné síly připočítána síla vzniklá pružinou. Tlumící síla se vypočte z<br />

rychlosti daného rigidního tělesa. Duration je opět interval mezi jednotlivými snímky. V<br />

pružině sice není potřeba, ale tato metoda by měla ve všech objektech, které vyvíjejí nějakou<br />

sílu, vypadat stejně. Například takto může být přidán objekt, který vyvíjí gravitační sílu,<br />

atd.<br />

4.4.3 Registr působících sil<br />

Sil působících na konkrétní objekt může být velice mnoho. Jedna síla může navíc ovlivňovat<br />

více objektů, například vítr, gravitační síla, atd. Myšlenka je taková, že se vytvoří generátor<br />

síly, jako příklad může posloužit výše zmíněná pružina. Takový generátor musí mít vždy<br />

metodu updateForce(duration, gameObject), kde GameObject je objekt s rigidním tělesem,<br />

na který bude působit výsledná síla.<br />

Registr sil má tři jednoduché metody:<br />

ˆ add(gameObject,forceGenerator), pomocí které dojde k registraci dvojice GameObject<br />

- ForceGenerator. Síla vyvinutá tímto generátorem bude ovlivňovat rigidní těleso v<br />

gameObjectu. Takto může být přidáno neomezené množství dvojic.<br />

ˆ remove(gameObject,forceGenerator), pomocí které dojde k vymazání dvojice Game-<br />

Object - ForceGenerator.<br />

ˆ updateForces(duration), která v cyklu projde všechny zaregistrované dvojice a pokaždé<br />

spustí metodu updateForce(duration, gameObject) příslušného generátoru síly. Za gameObject<br />

dosadí zaregistrovaný objekt.<br />

Výše popsaný způsob se hodí pro scény, kde se vyskytuje velké množství sil a objektů, na<br />

které síly působí. Ve výsledné ukázce není Registr sil použit. Síla je do rigidního tělesa<br />

přidána z komponenty Script, která je přiřazena vesmírnému plavidlu.<br />

4.5 Rozdělení prostoru<br />

Objektům ve scéně mohou být přiřazena obalová tělesa, která urychlují detekci kolizí mezi<br />

objekty, ačkoliv to má tu nevýhodu, že detekce není tak přesná, jako kdyby kolidovaly přímo<br />

samotné meshe mezi sebou. Tímto ale není vyřešeno to, jak najít dvojice objektů, které<br />

mezi sebou mohou kolidovat. Testování typu každý z každým by bylo v tomto případě velice<br />

neefektivní, protože se ve scéně bude nacházet velké množství objektů.<br />

Existují techniky, které rozdělují prostor na menší části, a které testují, zda dva nebo<br />

více objektů nesdílí stejný prostor. Jelikož objekty mohou vzájemně kolidovat pouze tehdy,<br />

29


sdílí-li stejnou část prostoru jako druhý objekt, tak je tímto způsobem významně redukován<br />

počet možných kolidujících dvojic.<br />

Existují 3 hlavní typy metod pro rozdělení prostorů, které jsou rozebírány v následujících<br />

podkapitolách.<br />

4.5.1 Mřížky<br />

Existují mřížky, které prostor rozdělují na stejné části. Jedná se o tzv. Uniform grids. Objekty<br />

jsou přiřazeny oblastem, ve kterých jsou obsaženy. Jedná se o velice oblíbenou metodu.<br />

Problém, který je s mřížkami spojen, spočívá ve stanovení velikosti buňky, což je znázorněno<br />

na následujícím obrázku 4.12<br />

Obrázek 4.12: (a) Buňky jsou moc malé. (b) Buňky jsou zbytečně velké. (c) Buňky jsou velké<br />

s ohledem na velikost objektu. (d) Buňky jsou moc velké a zároveň moc malé. Převzato z<br />

[13]<br />

Výše zmíněný problém řeší hierarchické mřížky, kde větší objekty jsou umístěny do<br />

mřížky, která má větší rozměr buněk. Malé objekty jsou naopak umístěny do mřížky s menšími<br />

buňkami. Pro výslednou ukázku, která se odehrává ve vesmíru, jsou mřížky dobrou<br />

volbou, ale přednost dostala metoda založená na řazení.<br />

4.5.2 Stromy<br />

Scéna je rozdělena do stromové struktury. Kořen stromu obaluje celou scénu. Potomci pokrývají<br />

části scény, které obaluje jejich rodič. Takto může být vytvořen strom o požadované<br />

hloubce. Na dalších několika řádcích bude popsán strom typu Octree, který byl vybrán k<br />

implementaci do výsledné platformy.<br />

Octree je osově zarovnaný strom, kde každý uzel má přesně osm potomků. Kořen stromu<br />

tvoří co nejmenší krychle, která pokrývá celou scénu.<br />

Tato krychle je rozdělena na osm podkrychlí, které tvoří potomky daného uzlu, což zobrazuje<br />

následující obrázek 4.13. Další potomci jsou dále tvořeny rekurzivně stejným způsobem.<br />

Typické kritérium pro zastavení rekurzivního algoritmu je maximální hloubka stromu.<br />

30


Obrázek 4.13: Číslování jednotlivých potomků stromu. Převzato z [13]<br />

Každý uzel stromu si uchovává tyto hodnoty:<br />

ˆ pozici středu<br />

ˆ poloviční velikost hrany<br />

ˆ reference na osm potomků<br />

ˆ pole obalových koulí, které jsou přiřazeny danému uzlu<br />

Existují dva rozdílné přístupy při vkládání objektu do stromu. Zde bude popsán pouze ten<br />

způsob, který je ve výsledku naimplementován. Při vkládání objektu se nejprve detekuje,<br />

zda se obalová koule nenachází uvnitř některého z osmi potomků. Pokud se rozprostírá přes<br />

více než jednu buňku, tak bude odkaz na obalovou kouli uložen do aktuálního uzlu. Je-li<br />

koule obsažena pouze v jedné buňce, tak se algoritmus bude rekurzivně opakovat, dokud<br />

koule nepřesáhne více jak jednu buňku a hloubka bude menší než maximálně povolená.<br />

Nevýhodou tohoto postupu je, že se obalová koule někdy nebude nacházet tak hluboko, jak<br />

by bylo ve skutečnosti možné. Pro statickou scénu by bylo lepší dělení objektu a ukládání<br />

odkazu na kouli do všech buněk, ve kterých se vyskytuje. Pro pohyblivý objekt je naopak<br />

vhodnější první způsob, protože se nemusí aktualizovat více ukazatelů, ale pouze jenom<br />

jeden. Ve výsledné ukázce se ale i přesto používá tento strom pouze pro statickou scénu,<br />

protože i přes použití první verze algoritmu, není standardní Octree strom vhodný pro mnoho<br />

pohybujících se objektů. Pokud bude problém s výkonem, tak je možné naimplementovat<br />

druhou verzi algoritmu. Strom nemusí být na začátku vytvořen celý. Potomci uzlů se mohou<br />

tvořit dynamicky podle toho, zda je do nich přiřazena některá obalová koule. Za zmínku stojí<br />

informace, že existuje Loose octree, který dovoluje dynamicky měnit velikost buněk, což řeší<br />

některé problémy.<br />

4.5.3 Řadící mechanismy<br />

Jak mřížky, tak stromy řeší problémy spojené s přesahem obalových těles do více buněk.<br />

Alternativou k těmto metodám jsou určitým způsobem seřazené objekty ve scéně. Výsledně<br />

naimplementovaná metoda se nazývá Sweep and prune.<br />

Sweep and prune<br />

je metoda, která funguje na principu, že si v obousměrně zřetězeném<br />

spojitém seznamu uchovává minimální a maximální hodnoty pro jednotlivé AABB konkrét-<br />

31


ních těles. Celkem obsahuje 3 spojité zřetězené seznamy pro každou osu. Metodu přibližuje<br />

následující obrázek:<br />

Obrázek 4.14: Minimální a maximální body jednotlivých AABB v dané ose jsou seřazeny dle<br />

velikosti. Převzato z [13]<br />

Pokud dojde k posunutí AABB, je nutné aktualizovat pozici minimálního a maximálního<br />

bodu ve spojitém seznamu. Metoda, která toto provádí, se nejprve podívá nalevo, zda aktuální<br />

hodnota není menší než předchozí hodnota. Pokud zjistí, že je menší, podívá se dále,<br />

dokud není nalezeno správné místo pro danou hodnotu. Ta je z původního místa smazána a<br />

následně vložena mezi dvě správné hodnoty. Obdobným způsobem se porovnávají hodnoty<br />

směrem doprava ve zřetězeném seznamu. Během hledání správného místa pro konkrétní hodnotu<br />

se hlídá, zda nedošlo k překrytí intervalu AABB s jiným AABB. Pokud se zjistí, že ano,<br />

tak je proveden test detekce kolize mezi těmito AABB. V případě, že je test pozitivní, je<br />

nalezená dvojice přidána mezi kandidáty na kolizi. Dále se během hledání musí ohlídat, zda<br />

naopak nedošlo k oddělení dvou intervalů. Pokud ano a objekty se nacházejí mezi kandidáty<br />

na kolizi, je nutné konkrétní záznam odstranit. Ve skutečnosti nejsou v seznamu uložené<br />

samotné hodnoty, ale reference na AABB. Navíc je součástí informace, která říká, zda se<br />

jedná o minimální nebo maximální hodnotu. Metoda, která vkládá nové AABB do seznamu,<br />

pracuje na podobném principu.<br />

Obecně se očekává, že se aktualizace seznamu provede v lineárním čase. Pokud se nachází<br />

mnoho objektů v jedné ose moc blízko u sebe, může být složitost O(n 2 ). Například se jedná<br />

o objekty položené na podlaze, jak znázorňuje následující obrázek 4.15 :<br />

Obrázek 4.15: Na obrázku vidíme objekty, které se nacházejí kousek od sebe v jedné ose.<br />

Pouze malý pohyb objektu může způsobit, že se hodnota uložená v seznamu posune o mnoho<br />

pozic. Převzato z [13]<br />

Jelikož se jedná o poměrně efektivní metodu a zároveň nemusí být řešeny problémy s<br />

velikostí buněk, byla použita do výsledné ukázkové aplikace. Další nespornou výhodou je, že<br />

32


se ukázka odehrává v prostředí vesmíru. Objekty se proto většinou neshlukují podél jedné z<br />

os, ale jsou různě rozprostřeny, což přesně vyhovuje použité metodě.<br />

33


5 Realizace<br />

V této kapitole se klade za cíl popsat zajímavá a neobvyklá řešení, která byla vybrána z<br />

výsledné implementace ukázkové aplikace.<br />

Hned první podkapitola 5.1 se zaměřuje na popis herní smyčky a možností jejího řešení.<br />

Ve výsledné ukázce bylo nutné řešit vykreslování průhledných objektů. Na problémy s tím<br />

spojené se snaží upozornit podkapitola 5.2. V podkapitole 5.3 je přiblížen postup, jak dochází<br />

k redukci zpracovávaných objektů grafickou kartou. Podkapitola 5.4 detailněji rozebírá<br />

způsob, jakým si uživatelé mezi sebou vyměňují informace po síti a upozorňuje na problémy<br />

s tím spojené. Poslední dvě podkapitoly 5.6 a 5.5 se zaměřují na konkrétní implementace<br />

laseru a generátoru asteroidů.<br />

5.1 Herní smyčka<br />

Herní smyčka určuje, kolikrát za sekundu dojde k aktualizaci scény a jak často se překreslí<br />

plátno, DOM ve webovém prohlížeči. Frekvence by měla být co možná největší, aby nedocházelo<br />

k zasekávání scény. Maximální hodnota opakování by neměla být vyšší než obnovovací<br />

frekvence monitoru, protože by nemuselo dojít k vykreslení některého ze snímků na obrazovku.<br />

První podkapitola 5.1.1 se zabývá samotným popisem RequestAnimationFrame API,<br />

které dnešní prohlížeče nabízejí pro lepší výkonnost. Druhá podkapitola 5.1.2 přibližuje možnosti<br />

použití tohoto API.<br />

5.1.1 RequestAnimationFrame API<br />

Web se v dnešní době stává stále více interaktivním. S vydáním HTML5 bylo uvedeno plátno<br />

Canvas [1], které dovoluje vykreslování různorodé grafiky. S jeho vydáním vzrostl požadavek<br />

na tvorbu efektivnějších animací ve webovém prohlížeči. Dříve se k modifikaci DOMu<br />

webového prohlížeče za běhu používaly a stále se někdy používají metody setTimeout a nebo<br />

setInterval, které dovolují překreslení stránky několikrát za sekundu. Tyto metody nejsou z<br />

pohledu výkonnosti moc efektivní. Animace jsou stále spuštěny i přes skutečnost, že došlo<br />

například k minimalizaci okna prohlížeče, přepnutí na jiný panel a podobně. Dokud nebylo<br />

tvůrci webových prohlížečů poskytnuto RequestAnimationFrame API”[18], tak webová platforma<br />

nenabízela tvůrcům aplikací jiný efektivní způsob, jak naplánovat jejich časování. V<br />

”<br />

dnešní době mnoho aplikací překresluje okno prohlížeče jednou za 10ms. Jde o zbytečně malou<br />

hodnotu, protože většina dnešních monitorů nedokáže aktualizovat obraz častěji než za<br />

16.7ms. To má za následek, že se některé snímky ztratí a vůbec se nevykreslí, což někdy vede<br />

k trhání výsledné animace.<br />

34


RequestAnimationFrame API”pracuje podobně jako setTimeout nebo setInterval. Hlavní<br />

”<br />

rozdíl spočívá v upozornění aplikace, že prohlížeč potřebuje aktualizovat obsah svého okna.<br />

Aplikace jsou tedy více svázány s obnovovací frekvencí okna webového prohlížeče. Počet opakování<br />

za sekundu není určen pevně, ale je dán zmíněným API. Na následujícím obrázku 5.1<br />

je vidět rozdíl ve výkonu mezi setTimeout a RequestAnimationFrame API.<br />

Obrázek 5.1: Rozdíl ve výkonu mezi setTimeout a RequestAnimationFrame API. Převzato<br />

z [18]<br />

API není zatím naimplementováno ve všech prohlížečích. Následující obrázek ukazuje<br />

podporu API jednotlivých verzí prohlížečů.<br />

Obrázek 5.2: Některé verze prohlížečů implementují API již nějakou dobu, jiné prohlížeče<br />

naopak API zatím ignorují a nebo ho připravují v budoucích verzích. Převzato z [19]<br />

35


RequestAnimationFrame API stejným způsobem jako setTimeout provádí jedno zpětné<br />

volání libovolné funkce. Z tohoto důvodu je nutné v případě potřeby více opakování, volat<br />

zmíněné API na konci cyklu, který má na starosti animační smyčku. Každý prohlížeč<br />

poskytuje API pod jiným názvem, protože jeho implementaci nemají zcela ukončenou.<br />

5.1.2 Použití RequestAnimationFrame API v aplikaci<br />

Nejdříve je nutné zjistit, pod jakým pracovním názvem se API v nejrozšířenějších prohlížečích<br />

nachází. Toto má na starosti níže uvedený fragment kódu, který je k dispozici ve výsledné<br />

platformě:<br />

window . requestAnimFrame = ( f u n c t i o n ( ) {<br />

// RequestAnimationFrame API j e z c e l a naimplementováno<br />

return window . requestAnimationFrame | |<br />

// implementace v p r o h l í ž e č i Chrome<br />

window . webkitRequestAnimationFrame | |<br />

// F i r e f o x implementace<br />

window . mozRequestAnimationFrame | |<br />

// p r a c o v í verze Opera Presto<br />

window . oRequestAnimationFrame | |<br />

// implementace IE<br />

window . msRequestAnimationFrame | |<br />

// případ , kdy p r o h l í ž e č nepodporuje<br />

RequestAnimationFrame API<br />

f u n c t i o n ( c a l l b a c k , element ) {<br />

return window . setTimeout ( c a l l b a c k , 1000/60);<br />

} ;<br />

} ) ( ) ;<br />

Herní smyčka poté ve výsledné ukázce vypadá následovně:<br />

f u n c t i o n loop ( ) {<br />

var currentTime = new Date ( ) . getTime ( ) ;<br />

i f ( t h i s . lastTime !=0){<br />

var elapsedTime = currentTime − that . lastTime ;<br />

/ / . . metody ř e š í c í animace , k o l i z e , r e n d e r i n g . . .<br />

that . lastTime = currentTime ;<br />

}<br />

// nekonečné opakování smyčky pomocí RequestAnimationFrame API<br />

nebo metody setTimeout<br />

window . requestAnimFrame ( loop , $(”#webGl−canvas ”) [ 0 ] ) ;<br />

}<br />

36


5.2 Průhlednost objektů<br />

Existují různé [?]způsoby, jak dosáhnout efektu průhlednosti. Z pohledu renderovacích algoritmů<br />

jsou uplatňovány 2 typy efektů:<br />

ˆ Takzvaný View based” efekt, kdy je poloprůhledný objekt sám vyrenderován.<br />

”<br />

ˆ Druhým způsobem je tzv Light-based” efekt, kdy objekt způsobí utlumení nebo odklonění<br />

světla. Výsledkem je větší osvětlení jiných objektů, které jsou nakonec vyren-<br />

”<br />

derovány odlišným způsobem.<br />

V ukázkové aplikaci je použita jednodušší varianta prvního způsobu, kde se poloprůhledný<br />

objekt ve své podstatě chová stejně jako barevný filtr, který je aplikován na všechny objekty<br />

za ním.<br />

První podkapitola 5.2.1 se zaměřuje na popis Z-bufferu a jeho nevýhody. Podkapitola<br />

5.2.2 popisuje techniku pro správné vykreslení průhledných objektů ve scéně.<br />

5.2.1 Z-buffer a jeho nevýhody<br />

Z-buffer v počítačové grafice řeší problém s viditelností objektů. Pokud je objekt vyrenderován,<br />

hloubka vykresleného pixelu je zaznamenána v Z-bufferu. Tento buffer je většinou<br />

udělán jako dvojrozměrné pole, které odpovídá jednotlivým pixelům. V případě, že musí být<br />

na obrazovku vykreslen jiný objekt, který se překrývá s původním, tak dojde k porovnání<br />

hloubky jednotlivých pixelů. Do Z-bufferu se zapíší pouze pixely, které se nacházejí blíže<br />

k pozorovateli. Ostatní pixely budou ignorovány a nedojde k jejich vykreslení. Z-buffer je<br />

součástí většiny moderních grafických akcelerátorů.<br />

Proč jsou vlastně v tuto chvíli zmiňovány Z-buffery? Jejich nevýhoda spočívá ve faktu,<br />

že si drží hodnotu pouze pro jeden naposledy uložený pixel. Výsledkem je, že Z-buffer sám<br />

o sobě nemůže vyřešit efekt průhlednosti. Jestliže se více průhledných objektů nachází v<br />

rámci jednoho pixelu, tak je nemožné vyhodnotit efekt průhlednosti pro všechny objekty.<br />

Dalším příkladem může být těleso, které má být vidět skrze jiný průhledný objekt. Jelikož<br />

dojde k jeho vykreslení později, jsou pixely za průhledným objektem ignorovány a nedojde<br />

k jejich vykreslení. Zmíněný problém je možné vyřešit pomocí takzvaného A-bufferu, který<br />

pracuje na podobném principu. Velice podstatnou nevýhodou je, že není mezi grafickými<br />

akcelerátory tolik rozšířen, takže jeho použití nepřipadá v úvahu.<br />

5.2.2 Vykreslení průhledných objektů<br />

Pro vykreslování průhledných objektů se často využívá techniky nazvané Alpha blending<br />

”<br />

”, kdy dochází k mísení barvy průhledného tělesa s barvou objektu za ním. Průhlednost<br />

objektu určuje hodnota alpha”. Každý pixel tedy obsahuje informaci o barvě RGB” a o<br />

” ”<br />

průhlednosti a”, dohromady RGBa. Hodnota 1.0 znamená, že je objekt zcela matný, naopak<br />

”<br />

při hodnotě alpha = 0.0 je objekt zcela průhledný.<br />

37


Operace mísení barev je zcela závislá na pořadí. Nejprve musí dojít k vykreslení matných<br />

objektů, aby bylo možné průhledné objekty míchat s objekty za nimi. Následně je zapotřebí<br />

seřadit všechny poloprůhledné objekty podle vzdálenosti od pozorovatele. Samozřejmě od<br />

nejvzdálenějšího po nejbližší. Až poté je možné poslat grafické kartě poloprůhledné objekty<br />

k vykreslení. Z-buffer v takovém případě může zůstat povolený a vykonávat svoji funkci,<br />

protože se vše vykresluje ve správném pořadí. Obrázek 5.3 z ukázkové aplikace znázorňuje<br />

situaci, kdy nejsou poloprůhledné objekty seřazeny a kdy naopak mají správné pořadí.<br />

Obrázek 5.3: a) Obrázek znázorňuje chyby ve vykreslení, pokud nejsou průhledné objekty<br />

seřazeny. b) Průhledné objekty jsou seřazeny.<br />

5.3 Viditelnost objektů<br />

Grafické karty dokáží velice efektivně provádět paralelní výpočty nad geometrickými objekty.<br />

Pokud bychom ale chtěli vyrenderovat 5000 objektů s 10000 trojúhelníky, tak bychom si moc<br />

nezahráli. Grafické kartě není nutné posílat ke zpracování vše, co se ve scéně nachází. Proč<br />

zpracovávat geometrická tělesa, která uživatel na obrazovce nevidí. Proto se používá metoda,<br />

která je popsána v podkapitole 5.3.1. Další metodu optimalizace přibližuje podkapitola 5.3.2.<br />

5.3.1 View frustum culling<br />

Takzvané View frustum[?] ve tvaru pyramidy je definováno celkem 6 plochami, které jsou<br />

uloženy v komponentě Camera. Těchto 6 ploch přesně určuje oblast, kterou uživatel aktuálně<br />

vidí. Následujícím způsobem dojde k identifikaci statických objektů, které mají být<br />

vyrenderovány:<br />

ˆ Každý objekt je umístěn v uzlu stromu Octree, o kterém bylo psáno v kapitole 4.5.2<br />

na straně 30.<br />

ˆ Před renderováním každého snímku se provede test kolize mezi výše zmíněným stromem<br />

a pyramidou, která definuje viditelnou oblast.<br />

ˆ Kolizní algoritmus vrátí všechny objekty, které se nacházejí v uzlech kolidujících s<br />

pyramidou.<br />

38


Výše zmíněným postupem došlo k významné redukci objektů, které mají být poslány k<br />

vyrenderování. Ale přesto je strom Octree naimplementován tak, že se mezi objekty dostanou<br />

i takové, které se nenacházejí ve viditelné oblasti. Pokud by výkon grafických karet nestačil,<br />

může dojít k testu kolize mezi pyramidou a nalezenými objekty. Jedná se konkrétně o test<br />

View frustum - koule. Tím se dosáhne požadovaného výsledku. Bohužel strom Octree se<br />

nehodí v aktuální implementaci k uchovávání dynamických objektů. Takový objekt by při<br />

každém pohybu musel být ze stromu vymazán a následně do něj vložen. Z tohoto důvodu je<br />

nutné provést test kolize mezi pyramidou pro každý objekt zvlášt’. Teoreticky by šlo použít<br />

způsob, kterým se testují kolize mezi všemi objekty ve scéně. Pyramida by v takovém případě<br />

musela být obalena krychlí. Poté už by se jen při každém pohybu hledali kandidáti na kolizi.<br />

5.3.2 Backface culling<br />

Backface culling je proces, při kterém dochází k identifikaci polygonů, které uživatel vidí.<br />

Tentokrát není potřeba nic implementovat, jedná se o standardní výbavu grafických karet.<br />

Pokud je Backface culling povoleno, tak dochází k ignorování polygonů, které uživatel nevidí.<br />

Nedochází ke zbytečnému zpracování vertexů, které se nacházejí na odlehlé straně. Ve<br />

výsledné aplikaci je Backface culling povoleno.<br />

5.4 Multiplayer<br />

Ukázková aplikace se odehrává v prostředí vesmíru, kde uživatelé mohou například ovládat<br />

vesmírné plavidlo, vytvářet nové brány a asteroidy. Všechny tyto změny a mnohé další se<br />

musejí promítnout u ostatních uživatelů, kteří se nacházejí ve stejný okamžik ve scéně. V<br />

prostředí internetu nikdy nelze dosáhnout stavu, že by uživatelé na druhé straně viděli změny<br />

v reálném čase. Vždy bude existovat určité zpoždění, s kterým se musí tvůrci her pro více<br />

hráčů vypořádat.<br />

Popisem známých architektur se zabývá podkapitola 5.4.1. Druhá podkapitola 5.4.2 popisuje<br />

vlastní implementaci multiplayeru v ukázkové aplikaci.<br />

5.4.1 Známé architektury<br />

V herním průmyslu existují dvě základní metody pro synchronizaci scény mezi uživateli[21]:<br />

Peer - too - peer - Jednotliví klienti komunikují přímo mezi sebou a vyměňují si informace<br />

formou zpráv. Například, pohnul jsem se o tolik a tolik, postavil jsem budovu na tomto<br />

místě, atd. Neexistuje žádný centrální server a nebo je pouze použit pro navázání<br />

komunikace mezi jednotlivými klienty. V dnešní době se metoda peer-to-peer už tolik<br />

nepoužívá. Můžeme ji vidět například v některých RTS hrách. Jsou s ní spojeny určité<br />

nevýhody. Není vždy zaručeno, že hra bude vypadat u každého hráče stejně. Někdy se<br />

mohou lišit jednotky, takže dojde k posunutí o jinou vzdálenost. Hráč se nemůže jen<br />

tak připojit v průběhu hry. Dále bývá problém v animacích a obecně v synchronizaci<br />

scény.<br />

39


Klient - server - Jedná se o doménu většiny akčních her. Místo toho, aby každý klient<br />

vykonával stejný kód a jednotliví klienti komunikovali mezi sebou, tak každý klient<br />

komunikuje pouze se serverem. Hlavní logika hry se vykonává pouze na serveru a<br />

jednotlivý klienti tvoří jakýsi terminál. Na server se odesílají pouze data ze vstupních<br />

zařízení jako je myš a klávesnice. Server aktualizuje na základě těchto dat stav scény a<br />

vrátí data s novou polohou hráče včetně informací o polohách ostatních hráčů. Aby byl<br />

pohyb ostatních hráčů plynulý, je nutné provádět interpolaci mezi předchozími stavy.<br />

Co se týče vlastní postavy ve hře, tak je nutné provádět predikci pohybu. Nějakou<br />

dobu totiž trvá než server vrátí novou polohu postavy. Odezva na vstup by tedy nebyla<br />

okamžitá a k pohybu postavy by došlo se zpožděním. Z tohoto důvodu se nečeká na<br />

odpověd’ serveru, ale normálně dojde k pohybu postavy. Server je autoritativní, takže<br />

pokud se pozice dodaná serverem bude lišit od té predikované, tak je nutné ji změnit.<br />

Zde ale nastává problém, server totiž poskytne data například 200ms stará a hráč by se<br />

posunul zpět v čase. Proto existuje buffer, který si pamatuje po určitou dobu všechny<br />

minulé stavy postavy včetně všech zmáčknutých kláves a tlačítek. Pokud přijde korekce<br />

od serveru, tak se zahodí všechny stavy, které jsou starší než aktuálně příchozí stav.<br />

Postava hráče se vrátí na pozici příchozího stavu a následně se na ni aplikují všechny<br />

vstupy uložené v bufferu. V takovou chvíli se postava nachází na správném místě a<br />

nedojde k posunutí v čase. Tento postup se neustále opakuje.<br />

5.4.2 Implementace multiplayeru v ukázkové aplikaci<br />

Do této doby Jetty server splnil vše, co se od něj očekávalo. Problém nastal při implementaci<br />

multiplayeru. Jetty server je totiž javovský a kód pro WebGl je psán v javascriptu. Z tohoto<br />

důvodu nemohla být použita implementace typu klient - server. Zde přichází v úvahu otázka,<br />

zda neexistuje lepší řešení, než kombinace WebGl + WebSocket + Jetty server? Odpověd’<br />

zní ano. Jako ideální volba se jeví kombinace WebGl + WebSocket + Node.js. Node.js se<br />

totiž chová jako standardní server, jehož kód se píše v javascriptu.<br />

Z výše napsaného textu vyplývá, že každý klient bude muset vykonávat svůj vlastní herní<br />

kód, což odpovídá metodě Peer-to-peer. Není to tak úplně pravda, protože jednotliví klienti<br />

nebudou mezi sebou komunikovat přímo, ale přes prostředníka. Technologie WebSockets totiž<br />

neumožňuje přímou komunikaci mezi webovými prohlížeči. Jednotliví klienti jsou připojeni<br />

k Jetty serveru, který má za úkol rozesílat data všem ostatním připojeným klientům. Ve<br />

vytvořené platformě je připraven objekt Multiplayer, pomocí kterého je možné se připojit<br />

k serveru. Každý klient je identifikován pod svým Id. Objekt Multiplayer obsahuje metodu<br />

pro odesílání dat ve formátu JSON ostatním klientům. Do této metody je možné vložit id,<br />

kterému klientovi se má informace poslat. Výchozí hodnotou je all”, což znamená, že se data<br />

”<br />

rozešlou všem ostatním klientům.<br />

Klienti se ve výsledné aplikaci mohou kdykoliv odpojovat a připojovat, což je pro metodu<br />

Peer-to-peer problém. Další problém nastal, kdy do scény měly být na začátku vygenerovány<br />

různé asteroidy. Kdyby každý klient při spuštění vygeneroval své asteroidy, tak by se vlastně<br />

každý hráč na začátku pohyboval v jiném prostředí. Oba zmíněné problémy řeší připojení<br />

speciálního klienta, který plní úlohu serveru a jehož Id je Server”. Takový klient musí být<br />

”<br />

40


vždy jen jeden.<br />

V dalším textu je pod pojmem server myšlen připojený speciální klient, nejedná se tedy o<br />

Jetty server. Na serveru je spuštěn stejný kód jako na jednotlivých klientech, ale nedochází k<br />

renderování informací na obrazovku. Další důležitou vlastností serveru je, že si pamatuje stav<br />

aktuální scény se všemi objekty a hráči. Pokud je zapotřebí na začátku vytvořit společnou<br />

scénu, například výše zmíněné asteroidy, tak musí být vytvořena jen pomocí serveru. V<br />

případě, že dojde k připojení nového klienta k Jetty serveru, je uplatněn následující postup:<br />

ˆ Klient informuje server, že se připojil.<br />

ˆ Server přidá mezi své objekty novou lod’ a přiřadí jí komponentu NetwokView, o které<br />

bylo psáno v kapitole 4.2.5 na straně 15. Následně jí nastaví unikátní Id. V dalším<br />

kroku přiřadí lodi komponentu Script, která má na starosti přijímání a odesílání zpráv<br />

pro daný objekt. Navíc tato komponenta provádí interpolaci stavu daného objektu,<br />

aby byl pohyb plynulý.<br />

ˆ Server odešle novému klientovi všechny informace o aktuální scéně a o ostatních hráčích.<br />

Poté všem ostatním klientům odešle všechna potřebná data o nově připojeném<br />

klientovi.<br />

ˆ Nově připojený klient vytvoří objekty na základě dat, které přijal ze serveru. Všechny<br />

takto vytvořené objekty musejí mít komponentu NetworkView s Id, které přiřadil server<br />

dané komponentě konkretního objektu. Stejně jako na serveru je novým objektům<br />

přiřazena komponenta Script, která slouží k interpolaci stavu jednotlivých pohyblivých<br />

objektů a k přijímání (odesílání) zpráv, které se týkají konkrétního objektu.<br />

ˆ Všichni ostatní klienti provedou podobné úkony jako výše popsaný klient, ale pouze<br />

pro nově přidanou lod’ připojeného klienta.<br />

ˆ Poté již dochází ke standardní komunikaci mezi klienty. Pomocí komponenty Script a<br />

metody sendState se posílá všem klientům a serveru informace o nové pozici hráče.<br />

Stejná komponenta u jiných objektů slouží pro příjem nového stavu daného objektu.<br />

U pohyblivých objektů, které neřídí sám uživatel, dochází pomocí komponenty Script<br />

k interpolaci rotace a pozice z minulých stavů objektu, aby byl pohyb plynulý.<br />

Server a jednotliví klienti používají dva rozdílné objekty multiplayer, které dědí vlastnosti<br />

z objektu WGLP. Multiplayer z výsledné platformy. Rodičovský objekt obsahuje základní<br />

metody pro připojení a komunikaci. Všechny odchozí zprávy musí obsahovat název příkazu,<br />

který se má spustit u protějšího klienta nebo serveru. Jeden z výše uvedených multiplayer<br />

objektů zprávu přijme a spustí metodu se stejným názvem, který byl uveden v příkazu.<br />

Využívá se vlastnosti javascriptu, že názvy objektů či metod mohou být doplněny dynamicky.<br />

V javascriptu jsou si totiž následující zápisy rovny:<br />

// neměnný název metody<br />

s e r v e r M u l t i p l a y e r . addSpaceShip ( ) ;<br />

// název volané metody může být změněn<br />

s e r v e r M u l t i p l a y e r [ ” addSpaceShip ”] ( ) ;<br />

41


Skript, který provádí interpolaci, potřebuje ke své činnosti vědět, s jakým zpožděním<br />

přicházejí nové stavy objektu. Z tohoto důvodu má objekt WGLP.Multiplayer zabudovanou<br />

metodu checkLatency, která následujícím způsobem zjistí zpoždění mezi Jetty serverem a<br />

připojeným klientem :<br />

ˆ Metoda odešle na Jetty server informaci o aktuálním času.<br />

ˆ Jetty server ihned odešle informaci klientovi zpět.<br />

ˆ Klient zjistí zpoždění pomocí vztahu : zpoždění = (aktuálníČas - původníČasOdesláníZprávy)/2.<br />

Každý klient musí jednou za čas aktualizovat zpoždění mezi Jetty serverem. Pokud se posílá<br />

stav některého z objektů, tak se v rámci jedné zprávy vždy odešle informace o zpoždění<br />

prvního klienta s Jetty serverem. Na druhém konci se k tomuto zpoždění přičte zpoždění<br />

druhého klienta s Jetty serverem, který zprávu obdržel. Tím se získá celková hodnota, která<br />

je potřebná k interpolaci.<br />

Klient, který tvoří server, není autoritativní. Všichni klienti nedostávají informace o stisknutých<br />

klávesách, tlačítkách, ale přímo obdržují nový stav objektu. Takový způsob není<br />

ideální z pohledu bezpečnosti, protože kdykoliv někdo může ostatním klientům podstrčit<br />

upravená data. Například se hráč může uměle teleportovat na jiné místo a ostatní klienti<br />

tomu uvěří, což u autoritativního serveru není možné. Takový přístup by nebyl ve stávající<br />

architektuře vhodný, protože server není ve skutečnosti server, ale speciální klient. Data by<br />

musela cestovat přes Jetty server ke speciálnímu klientovi a zase zpět, což by akorát zvětšovalo<br />

hodnotu zpoždění, a to není žádoucí. Navíc nemusí být řešen problém s predikcí.<br />

Očekává se také, že případní uživatelé aplikací postavených na koncové platformě, nebudou<br />

podvádět.<br />

5.5 Generátor asteroidů<br />

Ve scéně se nachází mnoho asteroidů. Z pohledu uživatele není dobrým řešením, aby každý<br />

asteroid vypadal zcela totožně. Jejich tvar a velikost by měly být variabilní. První, ne zcela<br />

ideální možností je vymodelovat několik asteroidů v modeláři a ty podle určitého vzorce ve<br />

scéně střídat. Jelikož uživatelé mají možnost generovat své vlastní asteroidy, tak by došlo k<br />

velice brzkému okoukání těch stávajících. Scéna by si zasloužila asteroidy rozmanitých velikostí,<br />

tvarů a případně barev. Proto bylo hledáno ideální řešení, jak programově vygenerovat<br />

tyto skalní útvary.<br />

Prví podkapitola 5.5.1 ukazuje princip použitého algoritmu. Druhá podkapitola 5.5.2 se<br />

zabývá popisem problému, který nastává v případě, kdy spuštěný skript trvá moc dlouhou<br />

dobu.<br />

5.5.1 Algoritmus pro generování asteroidů<br />

Nakonec bylo nalezeno řešení, které vyhovuje potřebám výsledné scény. Došlo k modifikaci<br />

algoritmu[22], pomocí kterého se dají například vytvořit různě zvrásněné kontinenty na mo-<br />

42


delu planety země. Postupuje se v několika krocích:<br />

1. Na začátku se nachází pravidelná koule získaná z modeláře.<br />

2. Dojde k náhodnému zvětšení nebo zmenšení koule.<br />

3. Koule je rozpůlena náhodně vygenerovanou rovinou.<br />

4. Všechny vertexy, které se nachází před rovinou, jsou posunuty o náhodnou hodnotu<br />

směrem od středu.<br />

5. Všechny vertexy, které se nachází za rovinou, jsou posunuty o stejnou hodnotu směrem<br />

ke středu.<br />

6. Body 3 až 5 jsou opakovány x krát, kde x je náhodně vygenerované celé číslo.<br />

Následující obrázek zobrazuje náhodně vygenerované plochy a výsledek po několika iteracích:<br />

Obrázek 5.4: a) Počáteční koule rozpůlená rovinou. b) Koule je rozpůlena jinou rovinou.<br />

Vertexy před rovinou se posunuly směrem ke středu a vertexy za rovinou směrem od středu.<br />

c) Výsledek po několika iteracích.<br />

5.5.2 Problém s generováním více asteroidů<br />

Webové prohlížeče si obecně neumějí poradit se skripty, které trvají moc dlouhou dobu.[23]<br />

V takovém případě zobrazí hlášku, která upozorňuje uživatele, že skript pracuje neúměrně<br />

43


dlouho a zda si přeje počkat na jeho dokončení. Nejspíše se jedná o nějakou formu bezpečnostního<br />

opatření. Navíc v typické smyčce vytvořené pomocí cyklů for” nelze aktualizovat DOM<br />

”<br />

prohlížeče, protože je zablokovaný. Bohužel není zablokovaný jen pro vývojáře, ale také pro<br />

uživatele, takže prohlížeč nereaguje na žádná kliknutí. Při generování například 1000 asteroidů<br />

dojde k vyskočení zmíněné hlášky, uživatel nemůže být informován o průběhu generování<br />

a navíc je blokované okno prohlížeče.<br />

Výše uvedené problémy lze vyřešit pomocí metody setTimeout(). Při jejím vykonávání<br />

se na chvíli uvolní DOM prohlížeče, takže může být aktualizován jeho obsah. Cyklus for” ”<br />

lze bud’ celý nahradit metodou setTimeout(), a nebo je možné uvedenou metodu volat jen<br />

jednou za x provedených cyklů for”. S tímto způsobem jsou spojeny určité problémy, ale<br />

”<br />

svůj hlavní účel plní. V ukázkové aplikaci se uživateli takto zobrazuje číslo generovaného<br />

asteroidu.<br />

5.6 Laser<br />

Laser je ve výsledné aplikaci používán k sestřelování bran a asteroidů. Měl by mít hezký<br />

vzhled a působit realisticky.<br />

Podkapitoly 5.6.1 a 5.6.2 popisují techniku zvanou Billboarding. Podkapitola 5.6 používá<br />

techniku popsanou v předchozích dvou podkapitolách.<br />

5.6.1 Billboarding<br />

Z důvody tvorby laseru byla do platformy přidána podpora billboardů [?] ve formě nového<br />

BillboardRendereru. Jedná se o orientovaný a otexturovaný polygon, který se otáčí v závislosti<br />

na pohybu kamery. Pomocí Billboardů s průhlednými texturami a animacemi mohou<br />

být vytvářeny různorodé efekty, které není možné udělat efektivně pomocí geometrických<br />

těles. Výborným příkladem je vegetace, obzvláště tráva. Dále kouř, oheň, mlha, exploze, atd.<br />

Billboardy se někdy používají k nahrazení objektu. Především v momentě, kdy se uživatel<br />

nachází ve větší vzdálenosti a již není schopen rozeznat detaily původního geometrického<br />

tělesa. Tím se ušetří výpočetní výkon, protože není potřeba renderovat komplexní objekt,<br />

ale pouze otexturovanou plochu. Dalším příkladem užití je HUD, na kterém se uživateli zobrazují<br />

informace o hře. Při programování WebGl aplikací je snadnější HUD vytvořit pomocí<br />

elementů jazyka HTML, protože se jedná o webovou stránku.<br />

Rotace billboardu se většinou určuje dvěma vektory(up, forward). Problém je v tom,<br />

že na sebe nebývají většinou kolmé, což není přípustné. Podle typu billboardu se jeden z<br />

těchto vektorů stane fixním. Pomocí vektorového součinu se nejprve vypočte třetí vektor,<br />

který je kolmý na oba zmíněné. Poté dojde k výpočtu vektoru, který není fixní a to tak,<br />

že se provede vektorový součin mezi fixním a nově vypočítaným vektorem. Všechny tyto tři<br />

vzniklé a následně normalizované vektory tvoří rotační matici billboardu.<br />

44


5.6.2 Nejpoužívanější typy billboardů<br />

Existují tři základní druhy billboardů, které se nejčastěji používají. Všechny tři jsou naimplementovány<br />

ve výsledné platformě. Při tvorbě komponenty BillboardRenderer je nutné si<br />

zvolit požadovaný typ billboardu. Samozřejmě je potřeba poskytnout rendereru všechny důležité<br />

informace o požadovaném billboardu. Především jde o rozměry, kameru a směr fixního<br />

vektoru.<br />

Billboard zarovnaný s obrazovkou již svým názvem napovídá, že jde o billboard rovnoběžný<br />

s obrazovkou a jehož vektor směřující vzhůru (up vector) je konstantní. Up ”<br />

vektor” je totožný s up vektorem” kamery. Jde o typ billboardu, který se v různých<br />

”<br />

aplikacích používá například jako HUD.<br />

Billboard orientovaný směrem k pozorovacímu bodu je vždy natočený směrem ke<br />

kameře (fixní vektor) a jehož vektor směřující vzhůru je pevně daný a nezávislý na<br />

rotaci kamery.<br />

Obrázek 5.5: Billboardy orientované směrem k pozorovacímu bodu<br />

Osově zarovnaný billboard není primárně natočen směrem ke kameře a navíc může rotovat<br />

kolem libovolné osy. Jednoduše řečeno má fixní ”<br />

up vector” a jeho ”<br />

forward vektor”,<br />

který ukazuje směrem ke kameře, je až podružný.<br />

5.6.3 Tvorba laseru<br />

Laser je vytvořen pomocí osově zarovnaného billboardu pokrytého průhlednou texturou červeného<br />

laseru. Orientace vesmírné lodi určuje směr up vektoru”. Pokud uživatel stiskne<br />

”<br />

klávesu, která obsluhuje laser, dojde k jeho roztažení ve směru up vektoru”. S roztažením je<br />

”<br />

nutné posunout laser tak, aby vždy začínal na špičce vesmírné lodi. MeshRendreru laseru je<br />

přiřazen obalový OBB, který nejlépe odpovídá tvaru billboardů. Reakce laseru na stisknutou<br />

klávesu zařizuje komponenta Script, která je přiřazena konkrétnímu objektu GameObject.<br />

Podle polohy objektu se obalová tělesa sice posouvají a rotují, ale nedochází k jejich zvětšení.<br />

Proto je nutné s roztahováním laseru také zvětšovat OBB ve stejném směru. Výsledný laser<br />

je zobrazen na následujícím obrázku 5.6 na následující straně:<br />

45


Obrázek 5.6: Laser z ukázkové aplikace<br />

46


6 Testování<br />

Aplikace byla otestována nejen z uživatelského hlediska, ale také s důrazem na nalezení<br />

implementačních chyb. V první podkapitole 6.1 se rozebírají nalezená zjištění od uživatelů<br />

především co se týče ovládání ukázkové aplikace. Druhá podkapitola 6.2 se zaměřuje na<br />

implementační chyby aplikace.<br />

6.1 Uživatelský test<br />

Výsledná aplikace je zaměřena spíše na mladší generaci, ale nic nebrání starším lidem, aby<br />

si ji vyzkoušeli. Pokud má uživatel základní znalosti počítačů, je schopen ovládat myš a<br />

klávesnici, může se ponořit do vytvořené virtuální reality.<br />

Uživatelé obecně neměli problém s pochopením uživatelského rozhraní. Spuštění scény<br />

se obešlo většinou bez větších komplikací. Lod’ se ovládá jen pomocí klávesnice, což byl asi<br />

největší kámen úrazu. Lidé jsou z dnešních her spíše zvyklí na ovládání pomocí myši. Velice<br />

často se stávalo, že si uživatelé pletli klávesy. Chtěli se například otočit kolem osy x a místo<br />

toho zrychlili pohyb lodě. V několika případech se stalo, že uživatel místo brány vygeneroval<br />

nový asteroid. Pro nové hráče by asi byla každá brána malá, protože se častěji stávalo, že<br />

došlo k nárazu. Velikost zůstane ale nezměněna, protože jde spíše o již zmíněný problém s<br />

ovládáním.<br />

Z provedeného testu lze usuzovat, že by uživatelé uvítali alespoň částečné ovládání pomocí<br />

myši. Dále z testování vyplynulo, že trvá delší dobu, než si uživatelé zapamatují funkcionalitu<br />

jednotlivých kláves. Přeci jenom možností, kam se může lod’ pohybovat, je trochu více.<br />

6.2 Test aplikace<br />

Aplikace byla otestována takovým způsobem, že se spustila hlavní scéna a připojilo se několik<br />

uživatelů. Problémů nebylo nalezeno mnoho, ale přeci jenom se určité nedokonalosti aplikace<br />

projevily. Při masivnějším přístupu uživatelů došlo k pádu aplikace. V konzoli se následně<br />

začaly objevovat samé hodnoty null, popřípadě jiné výjimky týkající se kolekce, ve které<br />

jsou na serveru uloženi všichni připojení uživatelé. Problém aktuálně není vyřešen, ale text<br />

výjimek naznačuje, že by se mohlo jednat o chybu způsobenou vlákny, které se snaží najednou<br />

přistupovat v jeden okamžik k výše zmíněné kolekci. Jedno vlákno například čte z kolekce<br />

data a druhé se snaží vymazat záznam, což u kolekce HashMap najednou nelze. Jak již bylo<br />

napsáno, aplikace zcela spadla, takže správně nepracovalo ani počítadlo aktuálně připojených<br />

uživatelů. Scénu bylo sice možné uložit, ale následné spuštění se nezdařilo, protože soubor<br />

obsahoval chybná data.<br />

Dalším zjištěným problémem bylo, že scéna nevydržela připojená přes noc. Technologie<br />

WebSockets totiž automaticky po nějaké době odpojuje klienta, který dlouho nevykazoval<br />

žádnou činnost a ani nedocházelo z jeho strany k příjmu dat od jiných uživatelů. Z tohoto<br />

důvodu se řídící scéna nejspíše odpojila, protože neměla s kým komunikovat. Řešením by<br />

bylo pravidelné informování serveru, že klient zůstává aktivní.<br />

47


Problémy se týkaly především sít’ové komunikace. Co se týče samotné hry a prostředí,<br />

významné chyby nebyly zatím objeveny.<br />

48


7 Závěr<br />

Cílem <strong>práce</strong> bylo navrhnout a naimplementovat webovou platformu pro interakci uživatelů v<br />

3D prostoru. Vlastnosti platformy měly být demonstrovány na ukázkové aplikaci. V kapitole<br />

2 byly stanoveny cíle <strong>práce</strong>, které se vesměs podařilo splnit, a to bud’ s menšími nebo většími<br />

obtížemi. WebGl není jedinou technologií, pomocí které je možné prezentovat 3D objekty<br />

ve webovém prohlížeči. Vývojová platforma Unity se zdá být výborná a také posloužila<br />

jako hlavní inspirace pro návrh struktury platformy. Co se týče Stage3D, tak i zde je velký<br />

potenciál k masivnějšímu rozšíření, protože téměř není člověka, který by neměl nainstalovaný<br />

Flash přehrávač na svém PC. Bude velice zajímavé sledovat, jaká z těchto technologií se více<br />

prosadí, a která spíše zapadne do stavu zapomnění.<br />

Co se týče architektury, tak se podařilo najít celkem použitelnou strukturu, která dává<br />

určitý smysl. Každý objekt ve scéně je vytvořen konstruktorem GameObject s jedinečným<br />

Id, na který jsou následně nabalovány komponenty podle potřeby. Komponenty objektu<br />

přidají fyzikální vlastnosti, obalí ho tělesem, obohatí ho o určitou logiku, umožní jeho vykreslení<br />

a obecně doplní různou funkcionalitu. Není problém vytvořit si vlastní konstruktor<br />

objektu s požadovanými proměnnými, metodami a následně zdědit všechny vlastnosti objektu<br />

GameObject. Platforma totiž neobsahuje jen objekty, metody,třídy, které jsou potřeba<br />

k vykreslování či fyzice. Ale musely být naimplementovány takové struktury jako je oboustranně<br />

zřetězený seznam, dále metoda umožňující dědění vlastností jiného objektu , metoda<br />

umožňující rozšíření stávajícího objektu a podobně.<br />

Analýza dále ukázala, že existuje velké množství obalových těles, která se hodí jen na<br />

určité typy objektů. To samé platí v případě stromů, mřížek, řadících algoritmů, pro které<br />

platí, že ne vždy se hodí do každé situace. Proto je třeba vždy velice zvážit jaké obalové těleso<br />

se přiřadí objektu, a nebo jaká se použije metoda na dělení prostoru. Fyzikální systém je<br />

určitě velice užitečný, protože dokáže simulovat chování reálného světa. Pomocí pružiny lze<br />

dosáhnou takových efektů, jako je houpání hladiny moře, pohyb oblečení a podobně. Pružina<br />

je také ideální volbou pro to, aby byl pohyb kamery za avatarem dynamický a nestála stále na<br />

jednom místě. Škoda jen, že se nestihl naimplementovat částicový systém, pomocí kterého je<br />

možné vytvářet efekty jako je kouř, oheň, mlha, exploze a podobně. Implementaci takového<br />

systému lze budoucímu vývojáři jen doporučit.<br />

V kapitole 5 bylo ukázáno, že není dobré pro různé animace v prohlížeči používat metodu<br />

setTimeout, protože je neefektivní s ohledem na výpočetní výkon. Je lepší využívat prohlížečem<br />

nabízené API, které šetří čas i peníze. Dále bylo ukázáno, jak tvořit zajímavé tvary<br />

asteroidů pomocí náhodně vygenerovaných rovin a posouváním vertexů. Musel být také vyřešen<br />

problém se sdílením scény mezi uživateli, kdy nakonec byla použita taková podivná<br />

kombinace metod klient - server a peer - to - peer. Rozhodně by bylo lepší v budoucnosti<br />

vyměnit Jetty server za Node.js, protože je možné jeho kód psát v javascriptu.<br />

Testování v kapitole 6 ukázalo, že ukázková aplikace netrpí zásadními nedostatky. Většinou<br />

se jednalo o problémy spojené se sít’ovou komunikací, které zatím nebyly vyřešeny.<br />

Nejspíše to bylo způsobeno tím, že se dvě vlákna snažila najednou měnit či číst jednu a tu<br />

samou kolekci. Tímto směrem by se měl budoucí vývojář vydat při hledání chyby.<br />

49


Celkově se nejednalo o snadnou práci, protože se týkala najednou více témat, která spolu<br />

více či méně souvisela, ale za to těch zkušeností bylo získáno opravdu velké množství, které<br />

budou určitě někdy zužitkovány. Pro budoucího vývojáře je připraven základ platformy, která<br />

se nadále může vesele rozvíjet a nadále rozšiřovat.<br />

50


Reference<br />

[1] LAWSON, Bruce ; SHARP, Remy . Introducing HTML5. Berkeley : New Riders, 2011.<br />

223 s.<br />

[2]<br />

JIŘÍ, Žára, Bedřich BENEŠ, Jiří SOCHOR a Petr FELKEL. Moderní počítačová grafika.<br />

Vyd 1. Brno: Computer Press, 2004, 609 s. ISBN 80-251-0454-0<br />

[3] SCABIA, Marco. How Stage3D works. Adobe [online]. 3.10.2011 [cit. 2012-05-<br />

18]. Dostupné z: http://www.adobe.com/devnet//flashplayer/articles/how- stage3dworks.html<br />

[4] UNITY: Game Development Tool [online]. San Francisco, © 2012 [cit. 2012-05-17].<br />

Dostupné z: http://unity3d.com<br />

[5] MUNSHI, Aaftab a Jon LEECH. OpenGL ES Common Profile Specification [online].<br />

Verze 2.0.25. The Khronos Group Inc., 2.11.2010 [cit. 2012-05-18]. Dostupné z:<br />

http://www.khronos.org/registry/gles/specs/2.0/es full spec 2.0.25.pdf<br />

[6] MARRIN, Chris. WebGL Specification. The Khronos Group Inc.<br />

[online]. Version 1.0. 10.2.2011 [cit. 2012-05-18]. Dostupné z:<br />

https://www.khronos.org/registry/webgl/specs/1.0/<br />

[7] THOMAS, Giles. Learning WebGL [online]. 13.10.2009 [cit. 2012-05-18]. Dostupné z:<br />

http://learningwebgl.com/blog/?p=28<br />

[8] WebSocket.org – A WebSocket Community [online]. Kaazing Corporation, © 2012 [cit.<br />

2012-05-19]. Dostupné z: http://www.websocket.org/index.html<br />

[9] SOMMER, Benjamin. Benjamin Sommer Weblog [online]. 13.5.2012 [cit. 2012-05-<br />

19]. Dostupné z: http://weblog.benjaminsommer.com/blog/2012/05/13/comparison-ofwebgl-framework-apis/<br />

[10] GLGE WebGL Library/Framework [online]. GLGE, 12.2.2012 [cit. 2012-05-20]. Dostupné<br />

z: http://www.glge.org/api-docs/<br />

[11] JONES, Brandon. High performance matrix and vector operations for WebGL<br />

[online]. GitHub · Social Coding, ©2011 [cit. 2012-05-20]. Dostupné z:<br />

https://github.com/toji/gl-matrix<br />

[12] MILLINGTON, Ian. Game physics engine development: how to build a robust<br />

commercial-grade physics engine for your game. 2nd ed. Boston: Morgan Kaufmann<br />

Publishers, c2010, xxix, 522 p. ISBN 01-238-1976-8.<br />

[13] ERICSON, Christer. Real-time collision detection. Vyd. 1. Boston: Morgan Kaufmann,<br />

2005, 591 s. ISBN 15-586-0732-3.<br />

[14] GLASSNER, A. Graphics gems I. San Diego: Academic Press, 1998, 301 - 303. ISBN<br />

0-12-286166-3.<br />

51


[15] LENGYEL, Eric. Mathematics for 3D game programming and computer graphics, third<br />

edition. 3rd Ed. Boston, MA: Cengage Learning, 2011, 212 - 216. ISBN 1435458869.<br />

[16] COLLADA - 3D Asset Exchange Schema. The Khronos Group Inc. [online]. ©2012 [cit.<br />

2012-05-22]. Dostupné z: http://www.khronos.org/collada/<br />

[17] Wavefront .obj file. In: Wikipedia: the free encyclopedia [online]. San Francisco<br />

(CA): Wikimedia Foundation, 2.5.2012 [cit. 2012-05-22]. Dostupné z:<br />

http://en.wikipedia.org/wiki/Wavefront .obj file<br />

[18] Using PC Hardware more efficiently in HTML5: New Web Performance APIs,<br />

Part 1. MANN, Jatinder. MSDN Blogs [online]. 6.7.2011 [cit. 2012-05-22]. Dostupné<br />

z: http://blogs.msdn.com/b/ie/archive/2011/07/05/using-pc-hardware-moreefficiently-in-html5-new-web-performance-apis-part-1.aspx<br />

[19] When can I use requestAnimationFrame?. When can I use...: Compatibility tables for<br />

support of HTML5, CSS3, SVG and more in desktop and mobile browsers. [online]. 2012<br />

[cit. 2012-05-23]. Dostupné z: http://caniuse.com/requestanimationframe<br />

[24] MÖLLER, Tomas Akenine. Real-time rendering. 3rd ed. Wellesley, Mass.: A.K. Peters,<br />

c2008, xviii, 1027 s. ISBN 978-1-56881-424-7.<br />

[21] FIEDLER, GLENN. What every programmer needs to know about game networking.<br />

Glenn Fiedler’s Game Development Articles and Tutorials [online].<br />

24.1.2010 [cit. 2012-05-23]. Dostupné z: http://gafferongames.com/networking-forgame-programmers/what-every-programmer-<br />

needs-to-know-about-game -networking/<br />

[22] Spherical Landscapes. The good-looking textured light-sourced bouncy fun<br />

smart and stretchy page [online]. 22.11.2003 [cit. 2012-05-24]. Dostupné z:<br />

http://freespace.virgin.net/hugo.elias/models/m landsp.htm<br />

[23] The Secret of Keeping Web Apps Responsive. Windy Road [online]. 30.3.2007 [cit.<br />

2012-05-25]. Dostupné z: http://windyroad.org/2007/03/30/web -apps-the-new-singlethreaded-gui/<br />

[25] FALCONER, Aubrey. NetworkView Position Sync. Unify Community<br />

[online]. 10.1.2012 [cit. 2012-05-27]. Dostupné z:<br />

http://www.unifycommunity.com/wiki/index.php?title=NetworkView Position Sync<br />

[26] JQuery: The Write Less, Do More, JavaScript Library [online]. © 2012 [cit. 2012-05-27].<br />

Dostupné z: http://jquery.com/<br />

52


A<br />

Balíky platformy<br />

Obrázek A.1: Balíčky, které strukturují zdrojový kód<br />

54


B<br />

Celkový UML diagram<br />

Obrázek B.1: Celkový uml diagram, který obsahuje všechny důležité třídy (konstruktory)<br />

56


C<br />

Uživatelská příručka<br />

Instalace<br />

Není nutné nic instalovat. Aplikace pouze vyžaduje javu minimálně ve verzi 1.7. Ke spuštění<br />

stačí webový prohlížeč s podporou WebGl a WebSockets. Chrome a Firefox již minimálně<br />

rok obě technologie podporují. Internet Explorer bohužel technologii WebGl nepodporuje a<br />

zatím to ani nemá v plánu.<br />

Nastavení<br />

Před spuštěním je potřeba nastavit v souboru websockets settings.js ip adresu a port. Soubor<br />

se nachází v adresáři ./webapp/scenes/space/app/.<br />

Spuštění Jetty serveru<br />

Zkompilovaný server se nachází v kořenovém adresáři projektu. Server se spouští přes konzoli<br />

pomocí následujícího přikazu:<br />

java − j a r s e r v e r . j a r parametr1 parametr2 parametr3<br />

kde<br />

parametr1 je ip adresa, na které se má spustit server. Nastavena defaultně na ”<br />

localhost”.<br />

parametr2 je port. Defaultně nastaven na 8080.<br />

parametr3 je webový adresář s aplikací. Defaultně nastaven na ”<br />

./webapp”.<br />

Spuštění<br />

Po zadání ip adresy do prohlížeče se objeví následující úvodní okno:<br />

58


Obrázek C.1: Úvodní obrazovka<br />

Vždy při prvním načtení úvodního okna je třeba spustit hlavní řídící scénu. Ta se spouští<br />

stisknutím klávesy S a následným kliknutím na tlačítko Spustit novou scénu. Pozor, neklikat<br />

v tomto případě na tlačítko Spustit v úvodním okně . Řídící scéna musí být spuštěna vždy<br />

jen jedna.<br />

Obrázek C.2: a) Okno, které se objeví po stisknutí klávesy S v úvodním okně. b) Okno<br />

informující o stavu scény po jejím spuštění. Pomocí tlačítka Uložit scénu lze uložit aktuální<br />

stav scény.<br />

59


Řídící scéna nejprve vygenerovala několik asteroidů a poté došlo k jejímu spuštění. Objevilo<br />

se informační okno, které ukazuje aktuální počet připojených uživatelů. Scénu je možné<br />

kdykoliv uložit. V průběhu hraní nesmí dojít k zavření okna webového prohlížeče, ve kterém<br />

je spuštěna řídící scéna.<br />

V tuto chvíli je potřeba otevřít nové okno prohlížeče a zadat opět ip adresu serveru.<br />

Otevřelo se Úvodní okno, stejné jako na obrázku C.1 na předchozí straně. Po kliknutí na<br />

tlačítko Spustit se objeví nová zatím neznámá obrazovka. Viz další obrázek C.3:<br />

Obrázek C.3: a) Okno, kde se uživatel může připojit jako nový hráč. b) Okno, kde si uživatel<br />

může vybrat ze seznamu odpojených hráčů a přebrat jeho vesmírnou lod’.<br />

Na první pohled zaujme přepínač, který nabízí 2 možnosti:<br />

Nový hráč - V případě zvolení této možnosti musí uživatel vyplnit přezdívku pod jakou si<br />

přeje ve scéně vystupovat. Poté stačí kliknout na tlačítko Spustit scénu.<br />

Vybrat hráče - Zde se uživatel nepřipojuje jako nový hráč, ale může si vybrat ze seznamu<br />

odpojených hráčů. Po spuštění scény je mu přiřazena lod’ bývalého hráče na poslední<br />

známé pozici. Nový hráč přebírá původní přezdívku odpojeného hráče.<br />

Nyní je spuštěna scéna.<br />

60


Obrázek C.4: Okno se scénou. Vlevo nahoře je vidět vzdálenost uživatele od středu, rychlost a<br />

uplynulý čas od průletu první brány. Vpravo nahoře se objevují informace o nově připojených<br />

nebo odpojených hráčích.<br />

Kdykoliv je potřeba uložit stávající scénu, tak je nutné otevřít okno webového prohlížeče,<br />

kde se nachází spuštěná řídící scéna. Jde o stejné okno jako na obrázku C.2 na straně 59,<br />

konkrétně jde o obrázek b).<br />

Co se týče načtení uložené scény, tak se postupuje zcela stejně jako když se spouští nová<br />

řídící scéna, akorát s tím rozdílem, že se neklikne na tlačítko Spustit novou scénu, ale na<br />

tlačítko Nahrát uloženou scénu. Tím dojde ke spuštění uložené scény.<br />

C.0.1<br />

Ovládání<br />

Vpřed / vzad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .W/S<br />

Zastavení . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C<br />

Vlevo / vpravo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Q/E<br />

Nahoru / dolu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .R/F<br />

Rotace kolem osy x (pitch) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . U/J<br />

Rotace kolem osy y (yaw) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A/D<br />

Rotace kolem osy z (roll) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . H/K<br />

Vytvoření brány . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B<br />

Vygenerování asteroidu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . V<br />

Laser. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Mezerník<br />

Kamera nahoru / dolu. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 / 1<br />

Kamera vpřed / vzad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 / 4<br />

61


Označení první brány (restart závodu) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 0<br />

C.0.2<br />

Hra<br />

Závod se spustí průletem první brány. Závodit může i více závodníků najednou, ale každému<br />

se čas měří od prvního průletu. Každý závodník vidí zvýrazněnou příští bránu (pro sebe) a<br />

méně zvýrazněné příští brány ostatních připojených účastníků. Pokud nemá bránu v zorném<br />

poli, vidí po straně obrazovky šipku ukazující nejbližší vzdálenost. Hráč může po stisku<br />

klávesy nechat vygenerovat asteroid nebo bránu. Asteroidy a brány je možné sestřelovat<br />

laserem. Závod lze pro sebe restartovat stisknutím klávesy 0.<br />

62


D<br />

Obsah přiloženého CD<br />

Obrázek D.1: Výpis souboru readme.txt<br />

64

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!