English Welcome Kecy Programování 3D - Engine Guestbook Odkazy Downloady O autorovi Napiš mi Mailform |
3D - Engine 02 - matice a transformace
Tak už jsem tady zase ! Dneska si ještě vysvětlíme ty matice a pak už se vrhneme na první
3D Engine. Jo když jsem si na to vzpomněl - trochu to komentujte lidi ! Copak nikdo nemáte
ruce, abyste mohli napsat e-mail ? Vždyť ani nevím jestli to vůbec někdo čte, jestli je
všechno jasný, jestli jdu dost pomalu a srozumitelně. Trošku se taky snažte, vy ! Přece není
možný aby to každej chápal. No nic, snad jsem vás trochu povzbudil ;-) Tak do těch matic :
Matice je matematické vyjádření pole čísel o dvou souřadnicích (přesně je to pole vektorů,
kde vektor je pole čísel o nějaké velikosti) :
Taková matice by se pak značila anm (všechny písmena za a jsou indexy). Pro 3d
engine budeme používat matice o rozměrech 4×4. Je nutné aby byly hodně přesné a
proto budou v c-čku realizované typem float :
Co pak ale s maticí ? Co vlastně matice obsahuje ? Jsou to čtyři vektory. Jeden ukazuje kde bude "vpravo", druhý ukazuje "nahoře" a třetí míří "dopředu". Ten čtvrtý je vlastně bod, je to posunutí od počátku souřadnicového systému (značí se O, O = [0, 0, 0]) Jsou umístěny svisle v prvních třech řádcích matice. Z toho plyne že transformace bodu maticí by měla vypadat nějak takhle :
Tady jsou ale využité jen tři řádky matice. Co s tím čtvrtým ? Jestli jste se dívali do nějakých papírů o maticích tak jste si asi všimli že když chcete mezi sebou násobit matice, musí jedna mít stejný počet řádků jako druhá počet sloupců. Jsou sice systémy, které uchovávají v paměti jen ty tři řádky a čtvrtý se doplňuje až při použití matice, nebo je matice tři na tři a jeden bod pro pozici a šetří se tím paměť. Tím to ale nebudeme komplikovat, hlavně když se dnes prodávají 128 Mb moduly za pár stovek. Teď ale přichází otázka, co v paměti má být. Z transformace můžete lehce odvodit, že aby byl objekt v původní poloze (tx = x, ty = y, tz = z) musí být matice jednotková. Taková matice má jedničky jen v tzv. hlavní diagonále :
No a s tímto tvarem matice přichází i první funkce :
Možná si říkáte co to je za zápis, ale je to zcela normální céčkovský zápis, který urychlí vaši práci :-). Dobře, tak máme matici na začátku. Ale co když budu chtít s objektem někam pohnout ? Některé z vás možná napadlo že poslední sloupec matice (m[3][0], m[3][1], m[3][2]) budou posunutí po osách světa. Takže pokud chcete zjistit pozici objektu nebo kamery tak jen přečtete tyhle buňky. Z toho potom vychází i naše Backface culling. Ale už jsme si řekli, že objekt se bude posouvat po svých osách a ne po osách světa, takže posouvání se nedělá přičítáním čísel do matice (i když by to samozřejmě fungovalo), ale vytvoří se nová matice, inicializuje se a místo těchto tří buněk se dají hodnoty posunu po osách objektu (kamery). A naše milá matice objektu se s touto maticí vynásobí a je hotovo. Takže budeme potřebovat ještě násobení matic. Když to děláte na papír, sepíšete si první matici pod a vlevo od druhé a násobíte řádky se sloupci a výsledky potom sčítáte. (takže a × b nerovná se b × a !) V céčku to bude vypadat nějak takhle :
Je to jednoduché a prosté. Nebo ne ? Můžete si to porovnat s vaší učebnicí matematiky, pokud nějakou máte. No a už si můžeme napsat funkci pro posunutí matice :
Je to přesně jak jsme si to řekli. Vytvoří se jednotková, dají se koeficienty posunutí a vynásobí se s maticí objektu. Úplně stejné to je s rotací. Můžete si to odvodit z rotace bodu okolo nuly o úhel. Když rotujete podle osy X, tak vlastně budete měnit jen Y a Z vektory (Y je nahoru a Z bude dopředu) Já už jenom vypíšu zdrojáky, stejně je to už dneska docela dlouhý :
No, a máme to za sebou. Teď už je jen jedna otázka. Umíme pohybovat s objekty, kamerou, ale pořád ještě nevíme jak smíchat matici objektu a kamery tak, aby se s ní daly transformovat vertexy. Dělá se to tak, že vezmete matici kamery, vytvoří se k ní inverzní matice a k ní ještě transponovaná matice (prohozené řádky a sloupce - obvykle se to nekomplikuje a dá se to všechno do jedné funkce, počítající inverzní matici) a tou se vynásobí matice objektu. Výsledná matice je tzv. transformační matice a tou se transformují vertexy tak jak jsme si řekli na začátku. K tomu potřebujeme nějakou funkci, která by inverzní matici spočítala. Inverzní matice se docela jednoduše počítá pomocí determinantu. Vezme se determinant celé matice (nesmí vyjít nula) a potom subdeterminanty. Ty se počítají pro každý prvek nové matice. Je to vlastně determinant té první, ale vynechá se řádek a sloupec, v němž leží onen prvek a celý se vynásobí mínus jedničkou, umocněnou na součet indexů toho prvku. Nakonec se všechny prvky vydělí společným determinantem. My ale víme že chceme v posledním řádku matice "0 0 0 1", a tak se to dá trochu zoptimalizovat. Ještě pro pořádek bych měl říct že součinem matice a matice k ní inverzní je jednotková matice. Tady to je :
Tak to by bylo. Pro pořádek - Sarrusovo pravidlo je pravidlo pro počítání determinantu. V matici se násobí šikmo jdoucí sloupce a ty se sčítají / odčítají podle směru. Kdo by chtěl vidět jak se to dělá postupně, je to v sekci Javascript na Techiho stránkách Ale jestli si vzpomínáte, řekl jsem že souřadnice se musí ještě perspektivně korigovat. K tomu potřebujete konstantu perspektivního zkreslení, pro rozlišení 320×200 je to pro úhel 45° zhruba 256. Dá se to odvodit z podobnosti trojúhelníků - kamera totiž vidí "pyramidu" a vy potřebujete obraz předělat tak, aby se ta pyramida vešla do "kvádru", jehož přední stranou je vaše obrazovka. To znamená že souřadnice budete dělit vzdáleností a násobit právě tímhle číslem. Ve výsledku to je : z_delta = n_Width / (tan(psi / 2) * 2); Kde n_Width je šířka obrazu a psi je zorný úhel (tady v radiánech). Normálně je to 90°, ale jsou i jiné možnosti použití - "aliení vidění" je něco okolo 150° a sniper - mód bývá tak 20° (ve fyzice jste se možná učili že dalekohled, mikroskop .. pracují právě se zorným úhlem oka ;-)) Čím míň vyjde z_delta, tím větší úhel. Nula by pak byla 180 stupňů, ale tu tam dát nesmíte, jedině číslo blízké nule. Už to rovnou hodím do céčka :
No a je to ! Teď už můžete napsat jenoduchý engine, který by zobrazoval body nějákého objektu. Potřebujete jen nějaké grafické rozhraní, pro začátek stačí jen Windowsovské okno. Taky potřebujete něco, odkud byste zdrojáky tahali - dneska použijeme formát ASC ze 3D - Studia (myslím že ho umí i milkshape, ke stažení někde na swedishcake.com ..) To je docela dobrej formát, protože se dá normálně otevřít v notepadu - jako text. Všechno je zapsaný jako text, takže není složitý z toho vytáhnout objekty a jejich verterxy. Později (asi v příštím díle) vám ukážu jak se to dělá s DirectX. Taky místo ASC tu bude 3ds (3D - Studio) formát. Tak si ho někde sežeňte (3D - Studio nebo 3D MAX). No a teď už si můžete stáhnout jednoduchý sampl i se zdrojáky : 3D Engine 01 |