Mipmapy

Transkrypt

Mipmapy
Mipmapy
W momencie, gdy oglądami pewien obiekt z nałożoną teksturą możemy zaobserwować wiele
jego szczegółów. Jednak, gdy jest on daleko od nas, nie widzimy już go tak dokładnie. Gdyby
wtedy był wyświetlany z mniejszą liczbą szczegółów zapewne byśmy tego nie zauważyli. Jak
wiadomo tekstury bardziej szczegółowe, a przez to o większych rozmiarach zmuszają
procesor do większej liczby obliczeń. Możemy uniknąć tego problemu stosując tak zwane
mipmapy.
Mipmapa jest powierzchnią złożoną. Zawiera ona w sobie inne powierzchnie, mniejsze, z
mniejszymi obrazkami. Owe powierzchnie są nazywane mipmapami o określonym poziomie.
Mipmapa najbardziej szczegółowa (czyli o najwyższych rozmiarach) ma poziom 0. Mipmapa
mniejsz szczegółowa ma poziom 1 itd. Zatem większa liczba opisująca poziom oznacza
mipmapę mniej szczegółową.
Na rozmiar mipmap jest narzucona pewna zasada: każda kolejna mipmapa musi być dwa razy
mniejsza od mipmapy o poziomie o jeden niższym. Dodatkowo rozmiary mipmap powinny
być potęgami liczby 2, np.:
Poziom 0 - 256x256
Poziom 1 - 128x128
Poziom 2 - 64x64
Poziom 3 - 32x32
Itd…
Na poniższym rysunku przedstawiono prostokąt pokryty teksturą z mipmapami widziany w
róznych odległościach:
Dość trudno zauważyć zmnianę szegółowości tekstury (może wrzuciłem zbyt małe obrazki).
Odpowiednia mipmapa jest wybierana utomatycznie. Mamy kilka jej wyboru. Należy w tym
celu ustawić odpowiedni filtr za pomocą polecenia
device.SetTextureStageState 0, D3DTSS_MIPFILTER, value As Long
Jako wartość value przekazujemy jedną z możliwych opcji:
D3DTFP_NONE - mipmaping jest wyłączony
D3DTFP_POINT - wybierana jest mipmapa rozmiarach najbardziej zbliżonych do rozmiarów
wielokąta
D3DTFP_LINEAR - wybierane są dwie mipmapy o rozmiarach najbardziej zbliżonych do
rozmiarów wielokąta, po czym dokonywana jest ich interpolacja i wynik jest nakładany na
wielokąt. Poniżej pokazano wynik zastosowania tego filtru:
Jak widać została dokonana interpolacja między
mipmapą o poziomie 0 a 1.
Jak łatwo można się domyśleć ostatnia opcja jest najbardziej pracochłonna dla procesora.
Teskturę zawierającą mipmapy ustawia się tak samo jak zwykłą teksturę:
Device.SetTexture 0, DDMipMap
Tworzenie tekstury z mipmapami
Napiszemy teraz procedurę tworzącą teksturę z mipmapami:
Public Sub Create_Mipmaps(file As String, ByRef MipMap As DirectDrawSurface7, num As
Byte, width As Single, height As Single)
'….
'…..
Edn Sub
file - to fragment nazwy pliku. Będziemy używać podobnych do siebie nazw plików, np.
brick0.bmp, brick1.bmp, brick2.bmp itd. To ułatwi nam wybór odpowiedniej bitmapy.
MipMap - to tworzona tekstura z mipmapami.
Num - liczba mipmap w tej teksturze
Width, height - rozmiary mipmapy o poziomie 0
W funkcji zadeklarujemy kilka zmiennych:
Dim MipMapDesc As DDSURFACEDESC2 'opis powierzchni zawierającej mipmapy,
konieczny do jej utworzenia
Dim Level As DirectDrawSurface7 ' mipmapa o określnym poziomie szczegółowości
Dim NextLevelDesc As DDSCAPS2
'opis następnej mipmapy o danym poziomie
Dim i As Integer
'do określenia poziomu mipmapy
Przechodzimy teraz do utworzenia tekstury z mipmapami. Musimy wcześniej przygotować
dla niej opis:
With MipMapDesc
'Takie pola zostaną za chwilę opisane
.lFlags = DDSD_CAPS Or DDSD_MIPMAPCOUNT Or DDSD_WIDTH Or
DDSD_HEIGHT
.lMipMapCount = num 'określamy ilość mipmap w teksturze
'Tworzymy złożoną powierzchnię (complex), bo tworzymy jeszcze w niej mipmpy
'Powierzchnia jest teksturą i jednocześnie mipmapą
.ddsCaps.lCaps = DDSCAPS_TEXTURE Or DDSCAPS_MIPMAP Or
DDSCAPS_COMPLEX
.ddsCaps.lCaps2 = DDSCAPS2_D3DTEXTUREMANAGE
.lWidth = width
'rozmiary pierwszej mipmapy o poziomie 0
.lHeight = height
End With
Flaga DDSCAPS2_D3DTEXTUREMANAGE - zarządzaniem teksturami zajmuje się
Direct3D.
Teraz już można stworzyć odpowiednią powierzchnię:
Set MipMap = DD.CreateSurface(MipMapDesc)
Ładujemy do niej obrazek. Funkcja PutImageInExistSurface ładuje obrazek bitmapy do
istniejącej już powierzchni. (zostanie omówiona później).
PutImageInExistSurface MipMap, file & Trim(Str(0)) & ".bmp"
Wybraliśmy dla niej plik z numerem 0. Gdybyśmy jako file do funkcji przekazali:
App.path & "\brick" to zostanie stworzona nazwa App.path & "\brick0.bmp".
Utworzona powierzchnia zawiera w sobie mipmapy o wyższych poziomach i jest
jednocześnie mipmapą o poziomie 0.
Wiemy, że mipmapa o poziomie 0 zawiera mipmapę o poziomie 1. Z kolei mipmapa o
poziomie 1 zawiera mipmapę o poziomie 2 itd… Jeśli chcemy uzyskać dostęp do jakiejś
powierzchni, która jest zawarta w innej powiwrzchni, to należy użyć metody
GetAttachedSurface. W ten sposób utworzymy mipmapę o poziomie 1. Wcześniej jednak
ustawimy odpowiedni opis. Należy zaznaczyć że jest to tekstura - mipmapa:
NextLevelDesc.lCaps = DDSCAPS_MIPMAP Or DDSCAPS_TEXTURE
Set Level = MipMap.GetAttachedSurface(NextLevelDesc)
Utworzona mipmapa level nie jest jakąś odrębną strukturą. Jest ona w rzeczywistości zawarta
w mipmapie o poziomie niższym MipMap. Za pomocą obiektu level jedkan możemy w jakiś
sposób dostać się do tej wewnętrznej powierzchni i zmodyfikować ją.
Ładowanie dalszych obrazków i tworzenie kolejnych mipmap zrobimy w pętli:
On Local Error Resume Next
i=1
While Err.Number = DD_OK 'tworzymy kolejne mipmapy, "wyciągając" je z mipmap o
poziomie niższym
PutImageInExistSurface Level, file & Trim(Str(i)) & ".bmp" 'umieszczamy obrazek w
ostatnio utworzonej mipmapie
i=i+1
Set Level = Level.GetAttachedSurface(NextLevelDesc)
Wend
W przypadku błędu (obsłużymy wszystkie mipmapy, a wywołanie GetAttachedSurface nie
zostanie wykonane i sposwoduje błąd), pętla jest kończona.
W pętli umieszczamy obrazek na ostatnio wydobytej mipmapie. Przy pierwszym wejściu w
pętlę będzie to mipmapa o poziomie 1. Następnie z mipmapy o poziomie 1 wydobywamy
mipmapę o poziomie 2. Zaczynamy pętlę od początku i umieszczamy na niej obrazek itd…
Po wyjściu z pętli usuwamy tymczasową powierzchnię:
Set Level = Nothing
Usuniemy tylko obiekt level, mipmapy zawarte wewnątrz powierzchni MipMap nie będą
usunięte.
Do omówienie pozostała funkcja PutImageInExistSurface umieszczająca obrazek na
stworzonej wcześniej powierzchni.
Public Sub PutImageInExistSurface(ByRef destSurf As DirectDrawSurface7, file As String)
Dim PicSurf As DirectDrawSurface7
'opis tymczasowj powierzchni z obrazkiem
Dim Desc As DDSURFACEDESC2
'opis powierzchni
Dim SrcRect As RECT
'obdzas źródłowy kopiowania, czyli rozmiar powierzchni
z obrazkiem
Dim DestRect As RECT
'obszar docelowy
Desc.lFlags = DDSD_CAPS 'to pole będzie opisywane
Desc.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN Or DDSCAPS_VIDEOMEMORY
'powierzchnia niewidoczna, w pamięci karty graficznej
Set PicSurf = DD.CreateSurfaceFromFile(file, Desc) 'tworzymy powierzchnię z obrazkiem
PicSurf.GetSurfaceDesc Desc
'pobieramy jej opis, aby poznać jej rozmiary
'Ustalamy obszar źródłowy kopiowania
SrcRect.Left = 0
SrcRect.Top = 0
SrcRect.Right = Desc.lWidth
SrcRect.Bottom = Desc.lHeight
destSurf.GetSurfaceDesc Desc
'pobieramy opis powierzchni docelowej
'Ustalamy obszar docelowy kopiowania
DestRect.Left = 0
DestRect.Top = 0
DestRect.Right = Desc.lWidth
DestRect.Bottom = Desc.lHeight
destSurf.Blt DestRect, PicSurf, SrcRect, DDBLT_WAIT 'kopiujemy obrazek
Set PicSurf = Nothing
End Sub
Możemy tworzyć powierzchnie, które zawierają obrazek za pomocą metody
CreateSurfaceFromFile. Jednak nie możemy umieścić w ten sposób obrazka na istniejącej już
powierzchni. Dlatego tworzymy dodatkową powierzchnię PicSurf, która będzie zawierała
obrazek. Umieszczamy go tam w momencie jej tworzenia. Jej rozmiary są wybierane
automatycznie i są to rozmiary obrazka. Na właściwą powierzchnię destSurf obrazek po
prostu skopiujemy z powierzchni PicSurf. W tym celu musimy ustalić obszar źródłowy i
docelowy kopiowania. Można je uzyskać z opisów tych dwóch powierzchni. Najpierw
pobieramy opis powierzchni PicSurf, uzupełniamy strukturę SrcRect. W podobny sposób
robimy ze struktórą DestRect. Na koniec pozostało kopiowanie:
destSurf.Blt DestRect, PicSurf, SrcRect, DDBLT_WAIT

Podobne dokumenty