sobota, 3 stycznia 2009

Mgiełka, plakaty tudzież niezidentyfikowana animowana maź

Jakiś młody człowiek zamiatał stopnie – teoretycznie. W praktyce przesuwał brud z miejsca na miejsce, dostarczając mu nowych widoków i okazji poznania nowych przyjaciół.

Terry Pratchett, “Maskarada”, Wyd. Prószyński i S-ka, s. 13, ok. 6-7 cm od górnej krawędzi strony i 5-11 cm od prawej krawędzi strony

Generalnie, powyższy cytat nie ma nic wspólnego z treścią notki. W praktyce oczywiście dałoby się wysnuć konkluzję – książkę Maskarada (należącą oczywiście do serii Świata Dysku) dostałem pod choinkę, podczas Wigilii, a Wigilia odbywała się podczas Świąt, a Święta były elementem Czasu Wolnego Od Uczelni, a Czas Wolny Od Uczelni był okresem, w czasie którego pisałem Program Zaliczeniowy, a w przerwach pomiędzy pisaniem Programu Zaliczeniowego pisałem kolejne elementy Własnego Frameworka, a z kolei w czasie, gdy próbowałem pisać Własny Framework, dostawałem polecenie wykonania czynności zwanej Sprzątaniem. Zatem można wydedukować wniosek płynący z cytatu – przyjemności wiążą się z nieprzyjemnościami…

A tak naprawdę, po prostu ten fragment mi się strasznie spodobał i chciałem się nim podzielić.

W każdym razie, faktycznie udało mi się napisać ok. 88% (no dobrze, 87%) trzeciego i ostatniego programu, który mam oddać w ramach zajęć z Podstaw Programowania. Zostały mi tylko trzy rzeczy – stworzenie systemu pomocy oraz gruntowne przetestowanie aplikacji i denerwowanie się błędami, które znajdę na 10 minut przed oddaniem. Najlepszym relaksem podczas tworzenia tego typu rzeczy jest pisanie czegoś na boku. Tym czymś okazał się oczywiście framework Yesta.

Poranna mgła w ściśle określonym obszarze

Czyli, krótko mówiąc, mgła objętościowa zwana też wolumetryczną. Oparta na lekcji Nehe, mimo początkowej niesforności związanej z rozszerzeniami OpenGL dała się stosunkowo łatwo zaimplementować do przestrzeni nazw CGems. Po oglądnięciu efektów pracy Nehe (a potem mojej) doszedłem jednakże do wniosku, że mgła odległościowa jest dużo bardziej efektywna w większości przypadków. Weźmy chociażby podróżowanie po lochach – zastosowanie mgły znajdującej się w ściśle określonym miejscu widzę jedynie w przypadku, kiedy chcemy zasłonić jakiś fragment, który nie ma być widoczny dla gracza albo jest elementem zawiłej zagadki w stylu “idź i zobacz, co znajduje się za tym czymś”. O wiele lepiej sprawują się tutaj standardowe algorytmy na renderowanie mgły. A co do użycia tego w Yeście:

   1: float fogColor[4] = {0.6f, 0.3f, 0.0f, 1.0f};        
   2: SetQuality(QL_NICEST);
   3: SetFogSettings(FT_LINEAR, 0.5f, 0.0f, 1.0f, fogColor);
   4: SetEffect(GE_FOG, true);
   5: SetFogType(FA_VOLUMETRIC); // SetFogType(FA_DEPTH_BASED);
   6:  
   7: //... (przechodzimy do funkcji renderującej)
   8:  
   9: EnableEffects();
  10:  
  11: //... (renderowanie z użyciem FogCoord(x))
  12:  
  13: DisableEffects();

Jakoś tak się złożyło, że w momencie włączania pierwszej mgły do frameworka nie znałem jeszcze shaderów, zatem jej generacja polega na skróconym zapisanie funkcji OpenGL-owych. Chociaż, czy teraz robiłbym to inaczej… Śmiem wątpić – jakoś przeraża mnie myśl o nakładaniu się paru shaderów jednocześnie na siebie – a zbytniego ich skomplikowania, aby obsługiwały parę efektów naraz, nie lubię. Taki dziwny ze mnie typ.

Plakaty – cholera, znowu walka wyborcza…

Na szczęście w programowaniu plakaty (billboardy) nie oznaczają wałęsających się plakatów na ulicach, drzewach, słupach, murach, ścianach, sufitach, krzaczków podlewanych przed psy, które zostają na długo po wszelkich wyborach, tylko o sposobach radzenia sobie z wielką liczbą wierzchołków potrzebnych na generowanie niektórych scen. Billboardów można

użyć na przykład do generowania trawy czy też drzewek. W tutorialu na Lighthouse 3D została przygotowana scenka z bałwanami i drzewami, które są niczym innym jak czworokątami z nałożoną teksturą drzewa. W momencie jednak, kiedy odpali się program, widać, że drzewa zwracają się w kierunku obserwatora. Wprawdzie nie machają gałązkami do kamery (to jeszcze nie ten poziom schizofrenii), ale starają się ukryć bycie płaskim obrazem poprzez odpowiednie ustawianie się. Pod linkiem, który podałem parę linijek powyżej, jest dokładnie opisany sposób plakatowania – mamy wersję sferyczną (która jest ustawiona także dla ruszania się nad i pod obiektem plakatowanym) oraz cylindryczną (tylko dla obchodzenia obiektów wzdłuż osi OX i OZ). Oba rodzaje billboardów mają swoją odmianę zwykłą i “oszukaną”. Ta druga jest widoczna na obrazku po lewej – obiekty billboardowane są ustawione nie tyle przodem do kamery co do płaszczyzny prostopadłej do obserwatora – czyli tak, jakby elementy sceny patrzyły na najbliższe cegiełki w murze znajdującym się za tuż za graczem. Pomyślałem jednak, że moje tłumaczenia mogą być mętne, dlatego zamieściłem rysunki z Lighthouse 3D. Prawdziwe plakatowanie jest przedstawione na rysunku po prawej – obiekty są zwrócone przodem do obserwatora niezależnie od jego położenia. Można wręcz rzec, że w tym przypadku elementy sceny są dużo odważniejsze – nie zawsze jest miło spoglądać na zimnych i pozbawionych wyrazu niczym surykatka po wejściu na minę bohaterów gier komputerowych. A one to robią. Znaczy, nie surykatki.

“Patrz, woda! Woda! No, to jest woda! I CO Z TEGO, ŻE NIE MA FAL?!"

water002 Całkiem niedawno zacząłem przeglądać dokładniej pracę magisterską Regedita i doszedłem do wniosku, że pewne rzeczy nie są aż tak strasznie – po prostu nie ma dobrego opisu, jak się za to zabrać. Podniesiony tą myślą na duchu, żywiołowo zabrałem się do renderowania wody. Nie będę tutaj za bardzo wnikał w szczegóły implementacji – polecam zaznajomić się z pracą Rega (pozdrawiam i gratuluję przystępnie, ale i profesjonalnie napisanej magisterki), gdzie jest to dobrze water004 opisane, a także do źródeł silnika The Final Quest oraz demka przedstawiającego możliwości engine’u. Mogę w sumie tylko nadmienić ogólną konstrukcję – cały proces polega na podaniu współczynników i wartości wektorów wiatru, wyliczeniu tego czarnomagicznymi sposobami, uwzględnienie koloru nieba, horyzontu, kaustyk i – co ciekawe – wody, a także podaniu mapy normalnych oraz kaustyk. water006 To tak z grubsza. Jako, że musiałem coś zepsuć (taka tradycja), wiele rzeczy mi nie wychodziło (co widać na screenach), ale uznałem to za warte do włożenia w szufladkę “Powinno działać przy odpowiednio dobranych parametrach. Powinno.”. Po 1,5 dnia uznałem też, że nadszedł czas na zastosowanie Pierwszej Reguły SceNtriCa dotyczącej shaderów. Brzmi ona: “Jeśli S jest shaderem, a X liczbą należącą do zbioru liczb całkowitych dodatnich, to w celu ulepszenia efektu należy dopisać X losowych i niezrozumiałych dla autora linijek kodu do jednego lub water007 obu programów shadera pod warunkiem, że całość będzie poprawna pod względem semantycznym i syntaktycznym.”. Jest jeszcze niestety Druga Reguła SceNtriCa dotycząca shaderów, która jest uzupełnieniem pierwszej. Brzmi ona: “Skuteczność stosowania Pierwszej Reguły SceNtriCa wynosi ok. 10%. W reszcie przypadków powoduje maniakalny śmiech pochodzący od autora.”. Tak mniej więcej przedstawiała się sprawa z próbą dodania parallaxa do wody (ciecz nagle przestała się ruszać – widocznie się obraziła). Jedyne co zadziałało i spowodowało, że przedstawiony powyżej drugi i trzeci screen mocno się od siebie różnią, to ten kawałek kodu zawarty w shaderze wierzchołków:

   1: float3 lightP = mul((float3x3)Matrix, LightPosition);
   2: float3 LightDir = normalize(lightP - float3(pos.x, pos.y, pos.z));
   3: float3 binormal = cross(In.Tangent, In.Normal);
   4: float3x3 tbnMatrix = float3x3(In.Tangent, binormal, In.Normal);
   5: Out.LightDir = mul(tbnMatrix, LightDir);

Konkretnie chodzi o trzy ostatnie linijki – dwie pierwsze są standardowe (wtedy LightDir jest tak naprawdę Out.LightDir). Po próbie wyliczenia tego na papierze (tak, czasami umiem się obyć bez komputera) wyszło mi, że wektor powstały po zmianie jest mocno powiększony w stosunku do tego “standardowego” (przynajmniej po wzięciu przeze mnie przykładowych wartości). W każdym razie, światło powstałe przy użyciu tego wektora wyliczone we fragment shaderze jest dużo mocniejsze – co mi się akurat optycznie podoba. Jako, że zżerała mnie też ciekawość przy próbie implementacji czegoś co się nazywa Environmental Mapping (mapowanie środowiskowe), wprowadziłem drugi rodzaj programów shadera, właśnie z użyciem “refrakcji” (bo czy to jest taka prawdziwa refrakcja, to bym się mocno zastanawiał, a i tak pewnie bym wcześniej zrezygnował z rozważań), co przy okazji wymusiło na mnie zajęcie się mapami sześciennymi (cube mapami). Czy efekt jest warty nadmienienia – widać (a raczej nie widać) na ostatnim screenie. W każdym razie, było to ciekawe doświadczenie.

Natomiast, jeśli komuś przyszłoby do głowy zajmować się wodą w dużo bardziej realistyczny sposób, polecam tę pracę. Osobiście skończyłem czytać po pierwszym akapicie. Ale nawet fajna fabuła.

Nie będzie dzisiaj mrożącego krew w żyłach i zapierającego… Nieważne – po prostu to był kolejny raport z placu boju na płaszczyźnie frameworkowej. Uff, to teraz wypada się zająć w końcu uczelnią… No i kolejną książką ze Świata Dysku.

Pozdrawiam i dziękuję – SceNtriC.

0 komentarze: