/**** ELA, NAJPRAWDOPODOBNIEJ TRZEBA ZMIENIÊ LEAD, BO JESTEM PEWIEN, ÛE WYWALË MU CONAJMNIEJ POÎOWË OBRAZKÓW. -Raf ****/ Jak ulepszyê procedurë? ----------------------- CIENIOWANIE Do dzisiejszego odcinka przygotowaîem "nieco" ilustracji. A zajmiemy sië oôwietlaniem i cieniowaniem ruchomych obiektów. Miklesz/ Damage Na poczâtek parë zaîoûeï przydatnych przy rysowaniu ôcian. Bëdziemy rysowaê czworokâtnâ ôcianë, wyznaczonâ przez punkty (0,1,2,3). Musimy jeszcze zaîoûyê jedno. Kolejne punkty ôciany zawsze "przebiegajâ" w jednym kierunku (np.: w kierunku wskazówek zegara). Pierwszâ rzeczâ, jakâ musimy zrobiê, bëdzie znalezienie najwyûszego (majâcego najmniejszâ wspóîrzëdnâ Y) punktu. Zaîóûmy, ûe bëdzie on miaî numer 0. Kiedy juû to wiemy, îatwo moûna zauwaûyê, ûe nasza figura bëdzie ograniczona z lewej strony nastëpujâcymi krawëdziami (posuwajâc sië od góry): 0-3 i 3-2. Z prawej bëdâ to 0-1 i 1-2. Wiemy, ûe Dy (wysokoôê caîej figury, liczona po osi Y) jest równa: Dy=Y2-Y0 Pozostaje nam wiëc przetablicowaê sobie obie (lewâ i prawâ) krawëdzie. Kaûdâ liczymy w dwóch etapach (lewâ: 0-3 i 3-2, prawâ: 0-1 i 1-2). Jak szybko wyliczyê wszystkie punkty odcinka? Przemnaûanie wszystkich wartoôci nie naleûy do najlepszych metod. Natomiast wyliczenie krótkiego wektora i dodawanie go do kolejnych punktów spowoduje powstawanie sporych przekîamaï, wynikajâcych ze staîoprzecinkowoôci procesora gîównego. Nie chcë byê posâdzony o pisanie tekstów za pomocâ funkcji Copy i Paste, ale poniewaû wspominaîem o metodzie, pozwalajâcej rozwiâzaê nasz problem juû kilka miesiëcy temu, to pozwolë sobie przedstawiê jâ raz jeszcze: Wyliczanie krawëdzi Caîâ krawëdú moûemy potraktowaê jako funcjë N-elementowâ, przyporzâdkowujâcâ kaûdemu elementowi (Yi) z osi Y, wartoôê (Xi) z osi X. Braliômy to juû przy okazji omawiania wektorów teksturowanych. Podajë wzór: 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 Jak jednak dokonywaê wszelkich mnoûeï i dzieleï liczb zmiennoprzecinkowych? 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. Przypuôcmy, û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 7006652. Nastëpnie caîoôê dzielimy przez 100000 (liczba zer jest oczywiôcie sumâ miejsc, o które przesunëliômy wczeôniej przecinek). Wynik: 700,6652, 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 prosto nie da sië uzyskaê samych liczb z wartoôciami po przecinku. Posiadajâc jedynie CPU, wartoôci takie uzyskaê moûemy jedynie w wyniku dzielenia przez siebie juû przeskalowanych liczb. 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 pamiëtaê oczywiôcie, û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, czego potrzebujemy, jednym SWAPem 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. Kiedy wiëc podanâ przeze mnie metodâ wyliczymy wszystkie cztery krawëdzie i po poîâczeniu tablic otrzymamy dwie: lewâ i prawâ, wystarczy (jak to robi blitter) wypeîniê przestrzeï pomiëdzy nimi. Cieniowanie ôcian Na razie narysowaliômy ôcianë w jednym kolorze. A przecieû miaîo byê o cieniowaniu! Okazuje sië, ûe wystarczy juû jedem maîy kroczek. Dla uproszczenia przyjmujemy, ûe odlegîoôê danego punktu ôciany zaleûy od jego odlegîoôci od obserwatora, liczonej w osi Z. Dziëki temu, juû po wykonaniu rotacji, znamy jasnoôci naroûników. Wystarczy wyliczyê natëûenia na caîej ôcianie. Zaczniemy od wyliczenia jasnoôci kaûdego z punktów krawëdzi. Znowu skorzystamy z usîug proporcjonalnoôci i kiedy bëdziemy wiedzieli, ûe naroûnik 0 ma jasnoôê 255, a naroûnik 1 000, to kolor I tego punktu jest równy: Ci=(C1-C0)/N*I+C0 Oznaczenia indeksów pozostajâ takie same, jak we wzorze na X i Y. Znamy juû natëûenia wszystskich punktów dwóch krawëdzi lewych i dwóch prawych. Teraz, kiedy wypeîniamy ôcianë, musimy zadbaê o pîynne przejôcie jasnoôci od lewego do prawego brzegu. Jeûeli powiem, ûe znów wykorzystamy tu proporcjonalnoôê, to nikt juû chyba nie bëdzie zaskoczony. Sposób podany przeze mnie nie jest moûe idealny, ale powstajâce w wyniku jego dziaîania niedokîadnoôci przy cieniowaniu sâ bardzo maîe. W kaûdym razie metoda sië sprawdza w 100%, a trzeba zauwaûyê, ûe jest stosunkowo szybka! Ilustracje Tradycyjnie prezentujë kilka przykîadów demek wykorzystujâcych omawiane przeze mnie techniki. Ilustracja pierwsza pochodzâca z dema "Anahalonium Lewini" grupy Tristar Red Sector Incorporation, to przykîad zastosowania prostej metody oôwietlania do skomplikowanej figury, co daîo niezîy efekt koïcowy. Druga ilustracja przedstawia obraz ôcianki jaki moûna otrzymaê po zastosowaniu algorytmu, podanego przeze mnie. Jeûeli w wyniku dziaîania Waszej procedurki "wyszîo" wam coô podobnego, to znaczy, ûe jest wszystko OK! Sîowo na niedziele Jak widzicie, cieniowanie obiektów, to nie taka straszna "Magia Davida BlitterFielda". Nadmieniê jednak naleûy, ûe wykonanie DOBREJ procedury do oôwietlania, jest dosyê czasochîonne. Ûyczë udanych prób i wspaniaîych efektów. Udanego Gourauda! Za miesiâc opowiem, jak wykonaê "RealTime Emboss".