1 DirectX ª% MgÅ‚a
Witam. Wiem, że się niecierpliwicie, aby rozpocząć czytanie, no ale jako, że lubię sobie tak od czasu do czasu pogawędzić,
więc na początek kilka słów, jak to już mamy w zwyczaju. Dzisiaj nadal będzie o ...mieszaniu. Tak, tak. Dzięki mieszaniu
będziemy osiągać sporo efektów, które zadziwią nie tylko nas samych. Zachęcony artykułem na pewnej stronie, o której
zresztą już pewnie wiecie, postanowiłem dzisiaj napisać o mgle. Czyli dowiemy się, jak skutecznie zaciemnić obraz, tak żeby
nic lub prawie nic nie było widać na naszej scenie. Mgła pomoże nam także nieco ulepszyć nasze sceny, ale o tym już za
chwilę. Dzisiejsza lekcja może nie będzie aż tak obszerna jak poprzednie, ale może na dziś odpuścimy sobie omawianie
poszczególnych funkcji i zajmiemy się tą jedną, która tak naprawdę będzie miała znaczenie. Pozostałe funkcje były już tyle
razy wałkowane, że nie ma sensu robić tego n-ty raz, bo nic nowego to nie wnosi, a czasu szkoda. Żeby nie przedłużać,
zamglijmy więc nieco naszą scenę, żeby nie wszystko było już tak jasne i klarowne.
Chyba każdy z nas widział kiedyś mgłę. Czym jest mgła? Definicja encyklopedyczna mówi coś w stylu:
Mgła to zawiesina bardzo małych kropel wody (o średnicy poniżej 0,05 mm) lub lodu w powietrzu. Mgły można podzielić
na:
" Radiacyjne, wywołane silnym ochłodzeniem gruntu na skutek nocnego wypromieniowania ciepła. Ich powstaniu
sprzyjajÄ… pogodne i bezwietrzne noce.
" Powstające w przyziemnej warstwie, gdy ciepłe i wilgotne powietrze miesza się powoli z chłodnym, mniej
wilgotnym.
" Adwekcyjne, wywołane napływem ciepłego i wilgotnego powietrza nad wychłodzoną powierzchnią Ziemi - lądową
lub wodnÄ….
" Wywołane parowaniem z cieplejszej, swobodnej powierzchni wodnej, charakterystyczne dla jesiennych wieczorów i
nocy nad jeziorami i dużymi rzekami.
" Smog.
Trąci to trochę jakimiś naukowymi teoriami, no ale chyba wszyscy z nas mieli z czymś takim do czynienia. Jeśli nie -
zapraszam kiedyś w góry, kiedy pogoda nie jest najlepsza, dużo chmur i jakąś taką niewielką górkę 1500 - 1700 metrów.
Napatrzycie się na mgłę, tak że będziecie mieli dosyć na kilka lat ;-). Jednak dla tych, którym się nie chce, powiemy dzisiaj
jak sprawić, żeby mgła zagościła na ekranach naszych komputerów, abyśmy mogli się nią rozkoszować bez ruszania się z
domu, co jednak nie oznacza, że powinniście siedzieć w nim cały czas i psuć sobie oczy gapieniem się w monitor po 16
godzin na dobÄ™. Jednak wracajÄ…c do rzeczy.
Mgłę na ekranie naszego monitora uzyskamy oczywiście jak wspomniałem za pomocą mieszania. Mieszanie urasta nam do
nie byle jakiego wynalazku i takim jest w istocie, ponieważ dzięki niemu uzyskujemy sporo efektów niemożliwych do
osiągnięcia innymi metodami. Jak mieszanie jest powiązanie z naszą mgłą i całą sceną? Otóż - kiedy nakażemy naszemu
urządzeniu włączenie mgły, pewną, dobrze nam już znaną jego metodą, urządzenie zacznie przeprowadzać dodatkowe
obliczenia, które spowodują, że przy odpowiednich ustawieniach, dostaniemy na ekranie wrażenie mgły. Bo trzeba sobie
jasno powiedzieć, że będzie to tylko wrażenie... wprawdzie bardzo realne, no ale to nie to co prawdziwa mgła - zimna i
wilgotna. Na czym polega generowanie mgły? Jak wiadomo jeśli gdzieś na ziemi wystąpi zjawisko mgły, to nie wszędzie na
raz, stąd logiczny wniosek, że gdzieś tam mgła się zaczyna a gdzieś kończy. Podobnie jest oczywiście w mgle komputerowej.
Gdzieś ona musi się zaczynać a gdzieś skończyć. Ponieważ nasza scena ma ograniczony zasięg (nie jest nieskończona), więc
dla potrzeb komputerowych wystarczy ustawić po pierwsze pewne zakresy mgły. Dla konkretnej sceny takie zakresy będą
oczywiście rożne, w zależności od potrzeb. Głównym zastosowaniem mgiełki w grafice, jest pomoc przy ukrywaniu daleko
leżących obiektów. Nawet w rzeczywistym świecie, jeśli wejdzie się na coś wysokiego (np. komin fabryki), to patrząc w dal,
da się zauważyć, że im dalej, tym obiekty widać coraz mniej wyraznie. Jeśli powietrze jest w miarę czyste, to pewnie
będziemy widzieć obiekty nawet do linii horyzontu. Ale ponieważ nie jest ono doskonałe (jak wszystko na tym świecie),
więc w pewnym momencie zacznie nam się wszystko zlewać, aż w końcu stanie się jednolitą masą w bliżej nieokreślonym
kolorze. Musimy tutaj oczywiście pamiętać, że nawet powietrze nie jest przezroczyste, bo zawiera mnóstwo rożnych
cząsteczek. Jeśli natomiast pójdziemy w góry w nienajlepszą pogodę i jeśli będziemy mieli "szczęście", to wdepniemy w
naprawdę gęstą mgłę, w której nic nie widać na odległość kilku metrów. Analogicznie do mgły w rzeczywistym świecie,
odpowiednio operując zakresami mgły, możemy uzyskać odpowiedni efekt - albo zaćmienia gdzieś daleko na horyzoncie,
albo nie widzieć nawet końca naszego sześcianu.
Po drugie - kolor mgły. W rzeczywistym świecie mgła ma prawie zawsze jednakowy kolor i bez specjalnych chemicznych
zabiegów nie będzie inna - naturalny kolor to w zasadzie taki nijaki, szarobiały. Komputery dają możliwość, bez żadnych
wielkich zabiegów, wygenerowania sobie mgły o dowolnym, wymarzonym przez nas kolorze. Co bardziej absurdalne,
zbliżenie się do naturalnego nie zawsze się udaje, bo trzeba mieć naprawdę duże wyczucie artystyczne :-).
Po trzecie - mgła może być albo gęsta, tak że można ją "kroić nożem", albo być tylko ledwo widoczną poranną mgiełką,
unoszącą się nad jakimś dawno zapomnianym jeziorem. Te trzy podstawowe parametry mgły, pochodzące z rzeczywistego
świata - zakres, kolor i gęstość, będą miały także decydujący wpływ na tą, którą my za chwilę tu wygenerujemy. Jeśli ktoś
kiedyś przyglądał się dokładniej mgle, to wie, że nie jest ona jakimś regularnym tworem. Mam na myśli to, że w jednym
miejscu może być gęstsza, w jednym rzadsza, bliżej nas może być gęstsza, dalej rzadsza. Niestety - tej jednej właściwości
mgły jak na razie nie bardzo da się odtworzyć w grafice komputerowej, przynajmniej nie tą metodą, jaką my zastosujemy. Na
naszej scenie może być tylko jeden rodzaj mgły i będzie ona miała tę właściwość, że im obiekty znajdujące się we mgle będą
bliżej nas, tym będą one wyrazniejsze. W pewien sposób twórcy bibliotek takich jak DirectX czy OpenGL starali się nam to
urozmaicić, wprowadzając pewne sposoby liczenia mgły na naszej scenie w zależności od odległości, no ale nasza mgła i tak
będzie zbyt idealna. No ale cóż, jeśli będzie wystarczająco gęsta, to i tak będzie nam wszystko jedno, prawda? ;-)
Aby jeszcze bardziej urealnić naszą mgłę, w Direct3D wprowadzono rożne sposoby jej tworzenia. Dziś możemy mówić o tak
2 DirectX ª% MgÅ‚a
zwanej "mgle wierzchołkowej" (ang. vertex fog) i "mgle pikselowej" (ang. pixel fog). Czym one się różnią i po co nam to w
ogóle potrzebne?
Mgła pikselowa (ang. pixel fog).
Ten rodzaj mgły zawdzięcza swoją nazwę procesowi powstawania. Każdy piksel na ekranie posiada pewną wartość z bufora
głębokości. Kiedy mgła jest obliczana, w ten właśnie sposób Direct3D tworzy tablicę, w której znajdują się współczynniki
mgły dla poszczególnych wartości odległości od obserwatora i na ich podstawie, biorąc każdy piksel z bufora Z, Direct3D
dobiera odpowiedni odcień koloru mgły do zmieszania z pikselem znajdującym się w buforze. Mgła taka nazywana jest
czasami mgłą tablicowaną, ponieważ niektóre sterowniki graficzne używają takich tablic, obliczonych wcześniej do
dobierania współczynnika gęstości mgły dla danej odległości z. Należy jeszcze zaznaczyć, że jeśli użyjemy własnego vertex
shadera, to mgła ta nie będzie obliczana. Wtedy musimy stosować inne, własne metody jej obliczania na naszej scenie.
Mgła wierzchołkowa (ang. vertex fog).
Ta mgła jest liczona przez naszą kartę w trakcie przeprowadzania transformacji i oświetlania wierzchołków. W takim
przypadku, na podstawie odległości wierzchołka, pobranej z bufora głębokości, obliczany jest jego kolor w połączeniu z
mgłą. Dlatego właśnie mgła ta nazywana jest wierzchołkową. Wartości kolorów są liczone tylko dla wierzchołków, reszta
kolorów na ścianach jest aproksymowana poprzez akcelerator. Jeśli uprzemy się jak osioł, żeby używać mgły
wierzchołkowej, a nasza aplikacja sama będzie przeprowadzać oświetlenie i przekształcenia geometrii, to także obliczenia
dotyczące mgły musi przeprowadzić niestety sama. W takim przypadku współczynnik, przez który zostaną zmieszane kolory
z kolorem mgły, może zostać umieszczony w składowej alfa części specular koloru. Kiedy używamy mgły wierzchołkowej,
musimy ją włączyć oraz ustalić jej kolor poprzez odpowiednie wywołania naszej ulubionej metody urządzenia renderującego.
Odwrotnie jak w przypadku mgły pikselowej, kiedy używać będziemy vertex shadera, a zachce nam się nagle mgły,
konieczne stanie się użycie właśnie mgły wierzchołkowej. Oczywiście wynika z tego, że jeśli aplikacja używa własnego
sposobu przetwarzania wierzchołków i świateł, to musi to samo robić z mgłą. Czasem użycie mgły powoduje niepożądane
efekty na naszej scenie objawiające się tym, że obiekty - owszem, są renderowane we mgle, ale coś nam nie gra w ich
wyglądzie, kolorze czy nawet stopniu ich zamglenia. Pewnie znacie ten przykład z dokumentacji SDK, no ale, że nie mamy
innego posłużymy się nim i my. Mamy dwa obiekty, jak widać na załączonym obrazku. Jeden znajduje się we mgle, drugi
zaś jest na tyle blisko nas, że nie ginie nam w niej. Jeśli teraz poruszymy się a dokładniej obrócimy się w miejscu, to nasz
obiekt nagle znajdzie się we mgle co jest zupełnie bez sensu przecież, bo nasza odległość do niego w ogóle się nie zmieniła!
Poniższe rysunki pokazują tę, jakże niepożądaną przez nas, sytuację.
Mgła oparta na mierzeniu zasięgu jest jeszcze innym, bardziej dokładnym sposobem odwzorowania tego efektu. W tym
trybie Direct3D używa aktualnej odległości od wierzchołka do punktu położenia oka, aby określić kolor wierzchołka po
"przepuszczeniu" go przez mgłę. Direct3D oczywiście zwiększa wpływ mgły na wierzchołek, jeśli odległość pomiędzy tymi
punktami się zwiększa, nie bazując przy tym na położeniu wierzchołka w buforze Z, ponieważ to jak widać może
powodować zupełnie błędne działanie. W powyższym przykładzie obrót wokół własnej osi obserwatora powoduje
oczywiście zmianę współrzędnych i ich położenie w buforze głębokości, ale nie zmienia odległości od obserwatora! To
rozwiązanie ma jednak pewną wadę. Ponieważ bazuje ono na odległościach pomiędzy punktami, może być użyte tylko i
wyłącznie podczas obliczania mgły w trybie wierzchołkowym, mgła pikselowa w tym momencie zupełnie odpada.
Dodatkowo nie każdy akcelerator obsługuje ten typ mgły. Dlatego też wcześniej należy za pomocą wywołania metody
GetDeviceCaps() upewnić się, czy nasze urządzenie renderujące może coś takiego dla nas wykonać. Ale o właściwościach
urządzenia, ich pobieraniu i określaniu powiemy sobie w oddzielnym tutorialu.
Przystąpmy zatem do analizy naszego kodu. Dzisiaj napiszemy sobie funkcję do ustawiania mgły, jej wszystkich parametrów
oraz sposobu jej obliczania.
void SetupFog( DWORD Color, DWORD Mode, BOOL UseRange, FLOAT Density )
{
3 DirectX ª% MgÅ‚a
float Start = 3.0f; // Linear fog distances
float End = 6.0f;
g_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_FOGCOLOR, Color );
// Set fog parameters.
if( D3DFOG_LINEAR == Mode )
{
g_pd3dDevice->SetRenderState( D3DRS_FOGSTART, *(DWORD *)(&Start) );
g_pd3dDevice->SetRenderState( D3DRS_FOGEND, *(DWORD *)(&End) );
}
else
{
g_pd3dDevice->SetRenderState( D3DRS_FOGDENSITY, *(DWORD *)(&Density) );
}
g_pd3dDevice->SetRenderState( D3DRS_FOGTABLEMODE, Mode );
// g_pd3dDevice->SetRenderState( D3DRS_FOGVERTEXMODE, Mode );
// g_pd3dDevice->SetRenderState( D3DRS_RANGEFOGENABLE, TRUE );
}
Po pierwsze:
float Start = 3.0f;
float End = 6.0f;
Ustawiamy sobie więc zakresy naszej mgły, to znaczy mówimy naszemu urządzeniu, gdzie się ona kończy a gdzie zaczyna.
Tak szczerze mówiąc, to chyba nie da się nigdy określić dokładnie jakie wartości powinny przyjąć zmienne odpowiedzialne
za te parametry. Wszystko zależy od naszej sceny, jak daleko i ile zamierzamy widzieć, jak gęsta jest mgła i jaki ma kolor.
Trzeba się raczej zdać na wyczucie i dobierać te wspołczynniki metodą prób i błędów. U nas współczynniki te (odległości) są
trochę większe niż największa współrzędna z naszej bryły.
g_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, TRUE );
g_pd3dDevice->SetRenderState( D3DRS_FOGCOLOR, Color );
Nasze wspaniałe urządzenie i jego niemniej wspaniała metoda SetRenderState(). Tym razem posłuży nam do włączenia na
naszej scenie mgły. Stała D3DRS_FOGENABLE nie wymaga chyba większego komentarza. Może przyjmować tylko dwie
wartości - albo mgła jest, albo jej nie ma. I na tym koniec. Druga stała D3DRS_FOGCOLOR będzie nam definiować kolor
naszej mgły. Jak napomknąłem wcześniej, komputer daje nam tę przewagę nad rzeczywistością, że naszą mgłę możemy
zabarwić na dosłownie miliony rożnych kolorów. Jako drugi parametr w wywołaniu metody SetRenderState() z tą stałą
podajemy nasz kolor w dobrze nam już znanym formacie koloru DWORD. Możecie sobie poeksperymentować i potworzyć
mgły zielone, czerwone, ba! nawet czarne. Tylko tu muszę powiedzieć o jednej rzeczy, bez której nasza mgła nie będzie
wyglądać tak, jak powinna. Chodzi mianowicie o tło. Wprawdzie chyba nie będzie się często to zdarzać, ale jeśli kiedyś
nasza scena nie będzie miała jakiegoś tła zbudowanego z brył 3D z nałożoną teksturą, a jedynie pustą przestrzeń za sobą,
która będzie miała kolor ustalony za pomocą metody Clear() urządzenia stosowanej w funkcji renderującej, to należy zawsze
pamiętać, że kolor ustalony tą metodą i kolor mgły muszą być takie same, lub co najmniej bardzo podobne! Jeśli mi nie
wierzycie, to spróbujcie w naszym przykładzie ustalić sobie na przykład czyszczenie tła na kolor czarny, a kolor mgły na
czerwony. Prawda, że nieładnie to wygląda? Jeśli natomiast obiekty będą zapełniać całą scenę, łącznie z tłem, to wtedy to
zmartwienie odpada nam z głowy.
// Set fog parameters.
if( D3DFOG_LINEAR == Mode )
{
g_pd3dDevice->SetRenderState( D3DRS_FOGSTART, *(DWORD *)(&Start) );
g_pd3dDevice->SetRenderState( D3DRS_FOGEND, *(DWORD *)(&End) );
}
Trochę wyżej wspomniałem o pewnych urozmaiceniach, jakie starali się wprowadzić do komputerowej mgły jej twórcy. Jeśli
czytaliście dokumentacje, to wiecie już co nieco o "przepisach na mgłę". Przepis taki mówi nam w jaki sposób ma być
obliczana nasza mgła. Wiemy już, że jest ona obliczana na jakimś dystansie - im bliżej nas tym lepiej widać. Ale aby nie było
to zbyt monotonne, wprowadzono właśnie to, o czym teraz wspomnę. Zarówno DirectX jak i OpenGL umożliwiają nam w
pewnym stopniu kontrolę nad tym, jak nasza mgła jest obliczana na pewnym odcinku. Jak wszystko inne w grafice 3D, mgłę
oblicza się z pewnych wzorów, które stanowią o wyglądzie naszej sceny. Dla poprawy jej wyglądu, wprowadzono rożne
sposoby jej obliczania. I tak, możemy mieć mgłę liniową, czyli rozkładającą się równo na całej scenie, co wcale nie oznacza,
że nie będzie jej widać. Im dalej będziemy "patrzeć", tym obiekt będzie widać słabiej, ale będzie to "malenie" stałe wraz z
4 DirectX ª% MgÅ‚a
odległością. Żeby nie było nudno, wprowadzono także eksponencjalny rozkład mgły i to na dwa rożne sposoby. Oczywiście
na wszystko są wyprowadzone wzory, które możecie zobaczyć poniżej:
Dla mgły o rozkładzie liniowym:
Natomiast dla mgieł o rozkładzie eksponencjalnym wzór przyjmuje postać (dla pierwszego stopnia):
Dla drugiego:
Jeśli ktoś nie domyśla się znaczeń poszczególnych symboli we wzorach:
d - odległość punktu od obserwatora,
start - punkt, w którym mgła się zaczyna,
end - punkt, w którym mgła się kończy,
density - gęstość mgły,
e - czyli po prostu liczba e = 2.718281829... itd.
Istnieje także wykres pokazujący, jak nasza mgła będzie się rozkładać przy rożnych ustawieniach i gęstości.
Mam nadzieję, że analiza tego wykresu pomoże Wam zrozumieć i dobrać sobie taki wygląd mgły, jaki Wam pasuje. W
ostateczności można nawet w jakimś programie matematycznym to zasymulować, na pewno minuta roboty. No dobra, tylko
ktoś zapyta po co ja to wszystko mówię właśnie teraz. Ano, jak widzicie, w tym fragmencie kodu ustawienie zasięgu mgły
odbywa się tylko, jeśli tryb rozkładania mgły na scenie jest liniowy. Dlaczego? Jeśli popatrzyliście dokładnie we wzory, to
już wiecie - dla rozkładów ekspotencjalnych zakres początku i końca nie mają znaczenia! Tak samo, w przypadku rozkładu
liniowego, nie ma znaczenia gęstość mgły, co widać po fragmencie kodu, który wykona się tylko w przypadku, kiedy tryb
będzie inny niż liniowy.
else
{
g_pd3dDevice->SetRenderState( D3DRS_FOGDENSITY, *(DWORD *)(&Density) );
}
Czy te rożne tryby rozkładania mgły dają nam aż taką satysfakcję w różnorodności wyglądu mgły można by polemizować,
ale na pewno przy pewnym umiejętnym doborze parametrów różnicę będzie widać. Zwłaszcza jeśli dla rozkładu
5 DirectX ª% MgÅ‚a
eksponencjalnego ustawić większą gęstość (>0.5f), chętni mogą oczywiście poeksperymentować.
Ponieważ na samym początku wspomniałem o mieszaniu, więc oczywiście muszę wspomnieć o wzorze, na podstawie
którego się oblicza kolor pikseli na naszej scenie. Co bardziej dociekliwi i myślący pewnie już sami go sobie wymyślili, no
ale dla porzÄ…dku:
C = f * Cx + (1 - f) * Cx
przy czym:
C - kolor, jaki powstanie przez zmieszanie piksela z mgłą,
Cx - piksel, jaki znajduje się w buforze przed wkroczeniem naszej mgły na scenę,
f - współczynnik mgły, która nam tu próbuje zaciemnić obraz, wzory macie powyżej.
g_pd3dDevice->SetRenderState( D3DRS_FOGTABLEMODE, Mode );
// g_pd3dDevice->SetRenderState( FOGVERTEXMODE, Mode );
// g_pd3dDevice->SetRenderState( D3DRS_RANGEFOGENABLE, TRUE );
No i tu fragment kodu, którego będziemy używać w zależności od tego, co nam się zachce. Teraz nasza niezawodna metoda
pozwoli nam zdecydować, czy używać mgły wierzchołkowej czy pikselowej. Po podaniu stałej oznaczającej tryb, czyli
FOGVERTEXMODE lub D3DRS_FOGTABLEMODE jako drugi parametr podamy rodzaj rozkładu mgły, który na
scenie sobie życzymy, czyli czy będzie to rozkład liniowy czy któryś z eksponencjalnych. Ostatnie, zakomentowane
wywołanie, to wspomniane wcześniej obliczanie mgły na podstawie odległości pomiędzy wierzchołkami i obserwatorem.
Chętni mogą oczywiście włączyć to sobie i posprawdzać jak to działa w jakiejś bardziej skomplikowanej scenie. No i cóż.
Teraz pozostaje nam już tylko wywołać naszą funkcję gdzieś na początku programu, ale oczywiście po utworzeniu i
zainicjalizowaniu urządzenia renderującego, stworzyć jakieś obiekty i gotowe. Jeśli zrozumieliście wszystko i dobrze
wklepaliście kod, to powinniście na ekranie dostać coś podobnego jak ja.
Wyszukiwarka
Podobne podstrony:
MSP430 DirectivesdirectorActive Directory omówienie domyślnych jednostek organizacyjnychbarcelona 6 directory v1 m56577569830521452directorypathsdirectLEIBNIZ DIRECTIONES wersja robocza XII 2012Domena i Active DirectoryDirect3D Wstepdirecto3Microsoft DirectX 10 Technical BriefActive DirectorydirectionsSHSpec 189 6209C18 Directing PC s AttentionDirect3D TeksturyDirect3D SwiatlaE1 PTAct 8 5 1 Directionswięcej podobnych podstron