Jak ulepszyê procedurë? (odc. 6.) --------------------------------- TEXTURED VECTORS Ostatnio w kaûdym dobrym demie moûemy ujrzeê tzw. wektorówki teksturowane, czyli majâce naîoûonâ na ôciany grafikë. Jak stworzyê takie "cudo"? Miklesz/Damage Sâ w zasadzie dwie metody. Pierwsza polega na odpowiednim rysowaniu ôcian i specjalnym nanoszeniu na nie grafiki. Trzeba jednak mieê na uwadze, ûe metoda ta wymaga trochë wiëkszego wkîadu pracy, a omówië jâ w póúniejszych odcinkach, przy okazji przedstawiania cieniowania ôcian (Gouraud). Natomiast drugi sposób polega na obracaniu wszystkich punktów obrazka i rysowaniu ich po kolei. Jest to sposób stosunkowo prosty, lecz niezbyt szybki. Z uwagi na jego prostotë zajmë sië nim dzisiaj i postaram sië dokîadnie go omówiê... Wyobraúmy sobie, ûe chcemy obróciê "obrazek" o rozmiarach 16 x 16 pikseli (dla uproszczenia). Normalnie mamy 16 x 16 = 256 punktów do przeliczenia. Nieprzyzwoicie duûo. Przy wiëkszych rozmiarach to i Silicon nie da sobie rady. Ale jest na to rada, podam Wam sposób, jak obliczajâc JEDEN punkt, moûemy poznaê pozycje wszystkich punktów kwadratowego obrazka! Ale zacznijmy od poczâtku... Najpierw taka umowa: wszystkie punkty ponumerowane sâ od (0,0) do (F,F). Da nam to klarowny obraz, który "dot" mam akurat na myôli. Jak juû wspominaîem, rotujemy jeden punkt, ten o symbolu (0,0). To juû 1/256 sukcesu! Zaraz bëdziemy juû znali dwa punkty. Zauwaûmy, ûe punkt (F,0) moûemy otrzymaê, zamieniajâc wspóîrzëdne (X,Y) punktu (0,0) ze sobâ, a nastëpnie negujâc Y. Radzë to sobie przeanalizowaê na ukîadzie wspóîrzëdnych (jest to tzw. mirror cheating). Nastëpnym krokiem bëdzie wyliczenie punktów na caîej krawëdzi pomiëdzy (0,0) i (F,0). Poniewaû tak sië zîoûyîo, ûe znamy liczbë punktów wchodzâcych w jej skîad i w naszym wypadku wynosi ona 16, moûemy brakujâce wspóîrzëdne wyliczyê, korzystajâc z proporcjonalnoôci. Wiëkszoôê z Was zrozumiaîa juû zapewne, o co chodzi. Dla tych, którzy sië jeszcze z takim dziwadîem nie spotkali, podajë wzór ogólny: I -- indeks N -- liczba punktów; X0 -- wspóîrzëdna X punktu (0,0); Xn -- wspóîrzëdna X punktu (N,0); Xi -- wspóîrzëdna X punktu (I,0); Y0 -- wspóîrzëdna Y punktu (0,0); Yn -- wspóîrzëdna Y punktu (N,0); Yi -- wspóîrzëdna Y punktu (I,0); Xi=(Xn-X0)/N*I+X0 Yi=(Yn-Y0)/N*I+Y0 Nooo.... Teraz juû chyba wszystko jest jasne. Jak zapewne zauwaûyliôcie, osiâgnëliômy juû 16 punktów i gwarantujë Wam, ûe teraz pozostaje jedynie kilka dodawaï i odejmowaï, aby otrzymaê wszystkie 256 punktów obrazka! Zauwaûmy, ûe nasza krawëdú to 1/16 obrazka. Gdybyômy potraktowali jâ jako linië i nastëpnie odpowiednio 15 razy skopiowali, przesuwajâc za kaûdym razem o odpowiedni wektor, to otrzymalibyômy peîny obrazek! No dobrze, ale skâd wiedzieê, o jaki wektor przesuwamy? Nic trudnego... Wektor pomiëdzy punktem (0,0) a (0,1) jest równy wektorowi pomiëdzy (0,0) i (1,0), obróconemu w prawo o 90 stopni. Jak obróciê wektor o kât prosty, juû wiecie (wykorzystamy do tego mirror cheating). Czynnoôê kopiowania wspóîrzëdnych z translacjâ powtarzamy 15 razy i mamy obrócone wszystkie punkty obrazka! Teraz wystarczy tylko nanieôê to wszystko na ekran. Na razie jedynie chwaliîem ten sposobik. Teraz coô o jego wadach. Po pierwsze obojëtnie jak maîy obszar zajmowaîaby ôcianka na ekranie, to i tak obliczamy wszystkie punkty obrazka úródîowego, mimo ûe duûa ich czëôê sië pokryje. Po drugie kiedy z kolei zaczniemy powiëkszaê ôcianë, zacznâ powstawaê "dziury". Dlatego najlepiej wykorzystaê sposób podany przeze mnie do wszelkiego rodzaju teksturowanych obiektów punktowych, majâcych wyraúne oddzielone od siebie punkty. Trzeciâ wadâ jest sprawa perspektywy, która musi byê, niestety, staîa dla caîej ôciany lub czasami nawet dla caîego obiektu. Bywa, ûe wpîywa to ujemnie na koïcowy efekt. Tak czy siak metoda jednak dziaîa, a przykîadem jej wykorzystania mogâ byê, zrobione przeze mnie, trzy teksturowane szeôciany, obracajâce sië w demie "Noxzema"/Damage. Po tej dawce teorii na temat rotowania punktów, parë praktycznych uwag. Jak zapewne zauwaûyliôcie, wektory, np. pomiëdzy (0,0) i (1,0) oraz pomiëdzy (1,0) i (2,0), sâ sobie równe. Dlaczego wiëc nie wyliczyê ich raz, a póúniej tylko powielaê? Moûna, ale zauwaûcie, ûe najczëôciej nie majâ one wartoôci caîkowitej. W zwiâzku z tym caîy obrazek przeskakiwaîby wyraúnie i trudno by byîo uznaê jego drgawki za rotacjë. Oczywiôcie jeûeli mamy koprocesor matematyczny, to problem z gîowy, lecz co wtedy, gdy nie jesteômy wîaôcicielami FPU? Pozostaje nam jedynie symulacja liczb zmiennoprzecinkowych na liczbach staîoprzecinkowych. Zacznë od przykîadu, którego bezpoôrednio nie moûna by byîo wykorzystaê w asemblerze, z uwagi na mnoûenie przez potëgi liczby 10, a nie 2. My jednak procesorami nie jesteômy, wiëc 10 wyglâda dla nas trochë przyjaúniej. Ale moûe po kolei... Przypuôêmy, ûe chcemy pomnoûyê liczbë 12,34 przez 56,78. Normalnie procesor gîówny obciâîby wszystko to, co po przecinku, i otrzymalibyômy 12 x 56 = 672. Jest to oczywiôcie niezgodne z prawdziwym wynikiem wynoszâcym 12,34 x 56,78 = 700,6652. Przypuôêmy, ûe jeszcze bîâd rzëdu +1/-1 byîby dopuszczalny, ale pomyîka o prawie 1/10 wyniku to juû powaûna sprawa. A caîoôê wyglâda jeszcze groúniej, kiedy musimy póúniej zsumowaê kilka bîëdnie wyliczonych wartoôci! Ale jest sposób na otrzymywanie dokîadniejszych wyników. Najpierw nasze dwie wartoôci pomnóûmy przez 100 (czyli przesuïmy przecinek na koniec cyfry). Otrzymamy 1234 i 5678. Teraz spokojnie mnoûymy obie liczby przez siebie, otrzymujâc w wyniku 7 006 652. Nastëpnie caîoôê dzielimy przez 100 000 (liczba zer jest oczywiôcie sumâ miejsc, o które przesunëliômy wczeôniej przecinek, zresztâ chyba wszyscy pamiëtamy to z podstawówki :-). Wynik: 7 006 652, czyli po odjëciu zer, równe 700. Bîâd wyniósî 0,6652, jest to znacznie mniej niû jeden procent caîoôci, a to chyba dokîadnoôê wystarczajâca, aby nasza wektorówka wyglâdaîa estetycznie. Pozostaje pytanie, jak to wszystko mnoûyê w asemblerze? To proste, wszelkie operacje wykonujemy przy liczbach juû wczeôniej przemnoûonych przez jakâô potëgë dwójki, czego dokonujemy oczywiôcie nie przez MULa.b, lecz przez przesuniëcia bitowe. Tu warto zwróciê uwagë, ûe im bardziej wczeôniej przeskalujemy wartoôci poczâtkowe, tym dokîadniejszych wyników moûemy póúniej oczekiwaê. Oczywiôcie tak îatwo nie da sië uzyskaê samych liczb z wartoôciami po przecinku. Majâc jedynie CPU, moûemy uzyskaê takie wartoôci jedynie w wyniku dzielenia przez siebie liczb juû przeskalowanych. Obecnie na 68EC020++ moûemy juû operowaê na QuadWordach, tak wiëc zakresów nam raczej nie zabraknie. Jeûeli zaô chodzi o przesuwanie bitowe, to polecam szybkâ instrukcjë SWAP.W, która w "ekspresowy" sposób z kaûdej liczby $0000abcd, zrobi nam przeskalowanâ $abcd0000. Naleûy oczywiôcie pamiëtaê, ûe wszelkie operacje na przeskalowanych wartoôciach muszâ mieê rozmiar dîugiego sîowa (.L), gdyû mniejsze rozmiary bëdâ dotyczyîy jedynie cyfr "po przecinku". Kiedy juû wyliczymy sobie to, co potrzebujemy, jednym SWAP-em sprowadzamy liczbë "na ziemië", czyli obcinamy zera (w zasadzie to wysyîamy je "do góry", lecz przy dalszych operacjach na samym sîowie (.W) nie ma to juû znaczenia, choê czasami moûe warto i o tym pamiëtaê), a czëôê caîkowitâ otrzymujemy w dolnych szesnastu bitach rejestru. Proste? Jeûeli na razie nie mieliôcie zbyt dîugiego kontaktu z teksturowanymi wektorówkami, to muszë uprzedziê, ûe ten typ efektów naleûy do "raczej" czasochîonnych, i to zarówno w sensie czasu poôwiëconego na napisanie procedury, jak i czasu ekranowego, potrzebnego do narysowania wszystkich ôcian. One Frame naleûy tu do rzadkoôci, a co bardziej skomplikowane obiekty na wolniejszych maszynach poruszajâ sië niebywale wolno, mimo ûe koder naprawdë wycisnâî z Amigi, co sië tylko daîo. Dla tych, którzy jeszcze nie widzieli lub nie sîyszeli, podajë, ûe ostatnio w demach zachodnich pojawiajâ sië obiekty teksturowane i przy okazji na przykîad deformowane, cieniowane. Przy okazji pragnë wyjaôniê, ûe wszelkiego rodzaju WolfSteiny i Doomy sâ zazwyczaj (choê nie zawsze) wektorówkami. Te wszystkie prostsze sâ zbliûone bardziej do tzw. Comanche'y (wszystkie te nazwy pochodzâ oczywiôcie od gier pecetycznych, w których dany efekt pojawiî sië po raz pierwszy). Zastanawiaê moûe fakt, dlaczego to kompatybilni pierwsi zaczëli tworzyê takie rzeczy. Jest to skutkiem nieposiadania przez koôci OCS, ECS i AGA trybu chunky pixel. Operacje na bitplane'ach, jak wiadomo, choê upraszczajâ tworzenie na przykîad "Glenz Vectorów", to spowalniajâ stawianie pojedynczych punktów w duûej liczbie kolorów. Teoretycznie nawet do oômiu razy. W tej sytuacji dopiero pojawienie sië trybu chunky, czëôciowo emulowanego na Copperze, oraz szybkich konwerterów "Chunky To Plannar" przyôpieszyîo rozwój wszelkiej grafiki teksturowanej i cieniowanej. Nim zakoïczë dzisiejszy odcinek, zabiorë jeszcze gîos w takiej pewnej sprawie... Doszîy mnie sîuchy, ûe Szanowni Czytelnicy zareagowali na mój cykl dotyczâcy asemblera. Z jednej strony cieszë sië, gdyû znaczy to, ûe ktoô czyta, to co ja tam bazgrzë, a to juû jest sukces. Z drugiej strony jednak okazaîo sië, ûe Szanowni Czytelnicy zareagowali negatywnie... A to juû mniej cieszy. A wîaôciwie, to wcale. Jednak nikt z Was nie zaproponuje nic konstruktywnego, tylko mówicie (najczëôciej do sîuchawki), ûe Wam sië nie podoba i juû. Jeûeli macie jakiô pomysî, to powiedzcie, a nie tylko krytykujcie. Jeûeli chcecie, bym napisaî np. o tunelach, to napiszë. Jeûeli jednak po prostu nie podoba Wam sië cykl sam w sobie (lub moja osoba, co teû jest prawdopodobne), to po prostu dam sobie spokój i po mnie ktoô inny zacznie n-ty cykl pt. "Jak otworzyê okienko i napisaê w nim: Tu byîem, Tony Halik" ;-) Czy jednak komuô sië to naprawdë przyda przy kodowaniu dema? Oglâdajâc najnowsze dema, dochodzi sië do wniosku, ûe teksturowane wektory sâ domenâ nie tylko pecetów. Amiga, mimo braku chunky pixel, radzi sobie nieúle z generowaniem takich obiektów. Wam równieû ûyczë wspaniaîych "teksturowaïców". Juû dziô zapowiadam, ûe w nastëpnym odcinku dogonimy niebieskiego w kolejnej branûy... Wykonamy lot nad fraktalowymi górami, rysowanymi, oczywiôcie, w czasie rzeczywistym!