+-+-+--+--+-+-++-+----+ | +-++ ---+ | ++ +--+ | | +--+ +--+ +- +++ +| | | + +-+ + | | | +-+| +----+ +- ++| ++ | | ++ | +- --+- --+-- -+ +----+-+--------------+ P O R T Á L Y Příroda má jednu opravdu zajímavou vlastnost. Většinu zákonů jimiž vládne, lze vyjádřit různě složitě, ale platí jedno pravidlo, kterým se řídí spousta vědců po celém světě. Čím je matematický popis určitého děje jednodušší, tím vyjadřuje mnohem více a nabývá obrovské síly a krásy. Mnohdy značně složité procesy se nakonec podaří shrnout do jednotného vyjádření pomocí něklika jednoduchých matematických nebo geometrických formulí. Příkladem může být Maxwellova teorie elektromaginetického pole nebo Einsteinova obecná teorie relativity. Pokud se někdo snaží nějakou teorii zdokonalovat, nikdy nepřestane, dokud nedosáhne určitého stupně symetrie, kdy lze prohlásit, že teorie je již natolik krásná, že má schopnost obstát před konkurencí. Zatím ale stále existuje spousta problémů, jejichž vyjádření a popis je značně transcendentní a nedokonalý, je potřeba jej stále zkoumat a vylepšovat. Je zajímavé, že tuto vlastnost mají vlastně všechny exaktně chápané problémy,a tak nás nepřekvapí, že některé geniální algoritmy počítačové grafiky mají onu prostou jednoduchost a zároveň velikou sílu a krásu. Jeden takový jednoduchý algortimus řeší viditelnost obecného nekonvexního prostoru. Na první pohled by se mohlo zdát nepřiměřeně složité zjišťovat, jaké stěny a objekty vidí lidské oko nebo jiný optický přístroj v naprosto obecném prostoru, ale pokud si odmyslíte třetí rozměr a začnete si celý problém kreslit na papír, zjistíte, že lze nalézt opravdu velice efektivní algoritmus, který bude fungovat naprosto spolehlivě na jakékoli rozložení čar a pozici pozorovatele. Tento algoritmus má trochu fantasktní pojmenování -- portály -- ale jak brzy zjistíte, přesně vyjadřuje geometrickou podstatu celého problému. Je to vysoce elementární způsob, který můžete aplikovat sami pouze pomocí tužky a pravítka, pokud chcete přesně narýsovat, které stěny zadaného bludiště jsou viditelné z jistého místa. Má tedy z geometrického hlediska Thaletovský charakter. Jak známo, cokoli lze narýsovat pomocí tužky a pravítka, lze i interpretovat lineární analytickou geometrií, což se nám velmi hodí. Ve své podstatě nám stačí znát analytické vyjádření úsečky na ploše a z něj vyplývající rovnice určující jejich průsečík. To je naprosto vše, co budeme počítat. Další věcí je nadefiování celého prostoru. Tady se dostáváme k prvnímu úskalí celého problému. Ne že by způsob definice prostoru nějak snižoval srozumitlenost algoritmu, ale výrazným způsobem snižuje jeho rychlost, což z matematického hlediska nic neznamená, ale pro nás počítačové grafiky je to dosti značná nevýhoda. Je potřeba nadefinovat konvexní oblasti, z nichž je celý prostor prospojován. Řekněme, že dostanete jakousi změť orientovaných čar. Každá čára nám rozděluje rovinu na dvě části. Je potřeba určit, která část rovniny je stěna a která volný prostor, tím se naprosto jednoznačně nadefinuje zkoumaný svět. Ale nám tato definice prostě nestačí, alespoň pokud chceme algortimicky aplikovat portály. Dalo by se ukázat, že pro účely tužky a pravíka není problém i na takto hrubé zadání portály aplikovat, ale počítač není člověk a nemá zažité jisté geometrické cítění, takže je potřeba mu ho nějak vnutit. Existují velice složté algortimy, které dokáží takto zadaný prostor rozstříhat na co nejmenší počet konvexních oblastí, ale jejich popis není rozhodně předmětem tohoto článku a patří mezi značně složité pasáže teorie počítačové grafiky, přestože se z lidského hlediska jedná o naprosto jednoduchou záležitost. Pro počítačové účely je potřeba již od začátku stavět světy v "portálech". Kdo z vás někdy editoval mapy Dooma, jistě ví, co takové editování obnáší. Mně osobně se velmi líbí a strávil jsem hodně času stavěním. Mnohem složitější situace nastává v 3D prostoru. Tam je podobná editace pro člověka už značně obtížná záležitost, zvláště když svět obsahuje velmi rozličně tvarované objekty. O problematice přechodu do třetího rozměru ale více pohovořím na závěr tohoto článku. Takže máme svět vytvořený pomocí konvexních n-úhelníků. Každá hrana toho polygonu má buď charakter neprůhledné stěny nebo portálu. Portál je tedy průhledné propojení mezi dvěma polygony. Dále máme bod, ve kterém se nachází pozorovatel a tzv. první portál, což může být například určitá stěna jakéhosi virtuálního polygonu, obklopujícího pozici pozorovatele. Polygon se bude pohybovat světem a můžeme ho také využít například pro detekci kolizí se stěnami. Umístíme jej do určitého místa ve světě. Zatím pouze tak, aby se jeho stěny neprotínaly se stěnami a portály světa. A začínáme s detekcí. První na řadu přijde konvexní polygon, ve kterém právě stojíme. Vyšleme dva paprsky. Paprsek je vlastně orientovaná polopřímka, její počátek se nachází v bodě oka pozorovatele a prochází jedním z krajních bodů prvního portálu. Postupně zkontrolujeme průsečíky se všemi stěnami a portály polygonu, na jehož "podlaze" právě stojíme. Použijeme k tomu jednoduchého výpočtu. Máme jednu polopřímku a n úseček: polopřímka: x = x0 + (x1 - x0)*s s ε <0;ω> y = y0 + (y1 - y0)*s úsečka: x = x2 + (x3 - x2)*t t ε <0;1> y = y2 + (y3 - y2)*t bod [x0;y0] je pozice oka, bod [x1;y1] je pozice jednoho z bodů, který definuje první portál a body [x2,y2] a [x3,y3] definují jednu ze hran polygonu, který právě zkoumáme. Hledané průsečíky spočítáme právě z parametrů s a t tak, že obě rovnice navzájem porovnáme: x2 + (x3 - x2)*t = x0 + (x1 - x0)*s y2 + (y3 - y2)*t = y0 + (y1 - y0)*s x2 - x0 + (x3 - x2)*t s = ----------------------- x1 - x0 y0 - y2 + (y1 - y0)*s t = ----------------------- y3 - y2 x2 - x0 + (x3 - x2)*t y2 + (y3 - y2)*t = y0 + (y1 - y0) * ----------------------- x1 - x0 x0*(y1 - y2) + x1*(y2 - y0) + x2*(y0 - y1) s = -------------------------------------------- (x0 - x1)*(y2 - y3) + (x3 - x2)*(y0 - y1) stačí vypočítat jeden z parametrů a všechny další hodnoty lze snadno zjistit z výše uvedených vztahů. Dosazením parametrů s a t do původních rovnic obdržíme X-ovou a Y-ovou souřadnici půsečíku dvou přímek. Abychom mohli určit, zdali se vypočítaný průsečík nachází opravdu ve směru paprsku a na hraně konvenčního polygonu,který právě počítáme, musíme se podívat na hodnoty jednotlivých parametrů. Z definice je zřejmé, že bod leží na úsečce zadané dvěma body právě tehdy, když parametr t je v intervalu <0;1>. U polopřímky platí podobná podmínka, tedy, že s>0. Jsou-li obě tyto podmínky splněny, můžeme s klidem říci, že daná hrana nebo portál se nachází na průsečíku s přímkou vymezující zorný úhel pozorovatele. Tím pádem všechy hrany a portály nacházející se v rozmezí těchto dvou průsečíků jsou viditelné celé a ostatní nejsou viditelné vůbec. Pokračujem druhou fází algoritmu.Je potřeba zjistit,které ty portály a hrany se vlastně v zorném úhlu nacházejí. Pokud máme oindexované všechny úsečky, ze kterých je polygon složen, lze vše vyřešit zcela elegantně tak, že všechny hrany a portály s indexy v rozmezí intervalu <a;b>, kde a je index první viditelné úsečky a b poslední viditelné úsečky, jsou viditelné. Je důležité dávat pozor na pořadí orientace, nejčastěji se používá orientace po směru hodinových ručiček, jinak by se vám mohlo stát, že získáte inverzní výsledek. Pokud indexování nemáme, není problém tuto viditelnost určit analyticky. Prostě spojíme oko s jedním z bodů úsečky a hledáme průsečík s přímkou prvního portálu.Pokud se nachází přímo v portálu, je úsečka vidět. A máme vyhráno. Na závěr projedeme všechny viditelné úsečky postupujem následovně: 1) je-li úsečka portál, pokračujeme rekurzivně dál do prostoru tak, že nahradíme první portál touto úsečkou a jako počítaný polygon světa zvolíme ten, který je na ní indexově nalepen z druhé strany. 2) je-li úsečka stěna, vykreslíme ji jako viditelnou a končíme. Je potřeba dávat pozor, jestli jsme náhodou nenarazili na úsečku, která je viditelná pouze zčásti, pak je nutné nahradit neviditelý bod novým bodem, který jsme vypočítali v první fázi algoritmu. Podívejte se na obrázek . Jak může vypadat takový jednoduchý příklad. Nelekejte se té změti čar. Stačí si uvědomit, že šedivá stěna není vidět, bílá je vidět, zelená čára značí využitý portál, modrá nevyužitý a tenké bílé čáry jsou paprsky. Pro přehlednost jsem očísloval všechny aktivní portály, takže si můžete celý průběh zrekonstruovat sami. Držte se instrukcí algortimu a uvidíte, že vám to půjde jako po másle. Nejlépe všechno pochopíte, když si pustíte nějaký kreslící program. Nakreslíte si nějaký zajímavý svět, zvolíte pozorovatele, první portál a sami si budete kreslit čáry a vyplňovat viditelné stěny a portály. Pokud si budete chtít zkusit 2D portály naprogramovat, mám tu pro vás mojí verzi . Ovládání je jednoduché. Jako vstup slouží textový soubor maze.txt s mapou 13x13, kde '#' značí stěnu a ' ' je logicky prázdné místo. Vznikne tak něco jako mapa pro Wolfensteina. Myší a klávesnicí zvolíte polohu oka (klávesa 'e') a polohy dvou bodů, které nadefinují první portál (klávesy '1' a '2'). Pak už jen klávesou ''' spustíte celý algoritmus a jako výsledek se vám zobrazí zeleně viditelné části světa. Můžete si také odkomentovat kreslení jednotlivých paprsků. Uvidíte pak, kolik jich vlastně musí program vyslat, aby dosáhl svého cíle. Program je napsán v C pro DJGPP. Ale při troše snahy se vám ho podaří předělat pro váš kompilátor, je nutné pouze změnit pár systémových věcí, jako je výstup do videopaměti a porty. Předem upozorňuji, že nefunguje ošetření kolize mezi prvním portálem a některým z polygonů světa, takže při volbě prvního portálu umístěte oba body do jednoho čtverce. Pokud chcete zdávat pozici poněkud obecněji, je třeba před začátkem výpočtu rozdělit první portál na více kusů. Každý kus patří jednomu polygonu a pro každý z těchto portálů startujeme calý algortimus beze změny. Je tedy zřejmé, že na pozici oka nezáleží, může ležet klidně i mimo svět. Důležité je, kde leží první portál. Tak a na závěr něco více o problémech a použitelnosti tohoto jednoduchého algoritmu. Výborně se hodí pro hry jako Doom nebo Wolfenstein. S jeho pomocí se vykreslují pouze ty části polygonů, které jsou opravdu viditelné. Tedy odpadá jakákoli transformace bodů a třídení polygonů podle vzdálenosti. Lze ji s výhodou použít při implementaci zrcadel. Problémy nastávají při přechodu do 3D prostoru. Jednak je potřeba místo průsečíku hledat průsečnice rovin a s rostoucím počtem portálů rapidně klesá účinnost. Zde jasně vedou BSP stromy. Ale ani v 3D světech nejsou portály k zahození. Používají se jako doplněk k BSP stromům. Svět se rozdělí na jednotlivé místnosti, které mají většinou nějaký jednoduchý tvar. A v každé z nich je předpočítán BSP strom, který se aktivuje, pokud se pozorovateli podaří nahlédnout portálem zrovna do této místnosti. Výrazně se tím urychlí výpočet viditelnost celého světa a taky to umožnuje udržovat v chodu rozsáhlé světy i při menších paměťových nárocích díky tomu, že celý level nemá jeden BSP strom, ale hned několik, které lze dle potřeby nahrávat a uvolňovat. V neposlední řadě jsou tu i zrcadla. Dalo by se říci, že zrcadla a různé kouzelné brány jsou v současné době asi jediný důvod, kvůli kterému se portály používají. ReDox výheň