Pobierz projekt z www.twinbottles.com/grk/SimplePP.rar
Spróbuj skompilować kod. Jeżeli wyskoczy ci błąd
fatal error C1083: Cannot open include file ‘d3d9.h’: No such file or directory
to znaczy, że w środowisku nie są ustawione ścieżki do plików nagłówkowych i bibliotek DirectX.
Aby je ustawić wejdź do menu Tools, wybierz Options…
W drzewie opcji w Projects and Solutions wejdź do VC++ Directories
W combo box Show directories for: wybierz Include files i dodaj nową ścieżkę klikając na drugi od lewej przycisk z ikoną folderu. W nowym polu wpisz:
C:\Program Files\Microsoft DirectX SDK (March 2009)\Include
Podobnie po wybraniu w combo box Library files dodaj nową ścieżke i w polu wpisz
C:\Program Files\Microsoft DirectX SDK (March 2009)\Lib\x86
Spróbuj skompilować kod ponownie. Teraz powinno się udać.
Punktem wyjściowym do tych ćwiczeń jest kompletny program z oświetlonym tygrysem. Przetwarzanie obrazu najwydajniej jest implementować w pixel shaderze. Cała scena zamiast do back buffer renderowana jest do tekstury pomocniczej. Następnie do back buffer jest renderowany prostokąt składający się z dwóch trójkątów. Prostokąt ten zajmuje cały ekran i jest poteksturowany tekstura pomocniczą, do której została uprzednio wyrysowana scena. Dzięki temu zabiegowi możemy dowolnie modyfikować teksele sceny.
Pierwszym krokiem będzie załadowanie pliku efektu wykorzystywanego przy renderowaniu prostokąta.
Ponieważ post processing będzię działał na wyrenderowanym już obrazie, potrzebujemy stworzyć dla niego dodatkowe, niezależne funkcje i zmienne.
Potrzebny będzie kod:
LPDIRECT3DVERTEXDECLARATION9 m_pVertexDeclarationPP ;
LPD3DXCONSTANTTABLE m_pVertexConstantsPP;
LPD3DXEFFECT m_pEffectPP;
Funkcja initializująca shader ( przykładowa nazwa InitEfectPP () )będzie analogiczna do funkcji initializującej shader tygrysa (zmienią się tylko nazwy zmiennych). Wywołana powinna być na koniec funkcji InitDx( ).
Oczywiście ładowany będzie plik efektu o nazwie PostProcess1.fx a nie Shader.fx. Zmieni się także struktura wierzchołka:
// Create the shader declaration.
D3DVERTEXELEMENT9 decl[] =
{
{ 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, 16, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
D3DDECL_END()
};
Kolejnym krokiem będzie zadeklarowanie struktury wierzchołka i stworzenie tablicy czterech wierzchołków.
struct Vert{
D3DXVECTOR4 pos;
float u1,v1;
Vert vertices[4];
Wartości w tej tablicy należy ustawić w funkcji InitDX( ) za pomocą następującego kodu:
vertices[0].pos.x=-1.0f;
vertices[0].pos.y=1.0f;
vertices[0].pos.z=0;
vertices[0].pos.w=1.0f;
vertices[0].u1=0;
vertices[0].v1=0;
vertices[1].pos.x=1.0f ;
vertices[1].pos.y=1.0f;
vertices[1].pos.z=0;
vertices[1].pos.w=1.0f;
vertices[1].u1=1;
vertices[1].v1=0;
vertices[2].pos.x=-1.0f;
vertices[2].pos.y=-1.0f;
vertices[2].pos.z=0;
vertices[2].pos.w=1.0f;
vertices[2].u1=0;
vertices[2].v1=1;
vertices[3].pos.x=1.0f ;
vertices[3].pos.y=-1.0f;
vertices[3].pos.z=0;
vertices[3].pos.w=1.0f;
vertices[3].u1=1;
vertices[3].v1=1;
Konieczne będzie także przygotowanie tekstury do której będzie renderowany obraz sceny oraz powierzchni, która będzie służyła za tymczasowy bufor głębokości. Przy renderowaniu sceny do innego bufora niż backbuffer konieczne jest ustawianie własnego Zbufora. Korzystanie z domyślnego bufora głębi podczas renderingu do własnego bufora obrazu jest możliwe tylko na kartach firmy Nvidia, nie jest to jednak zachowanie zgodne ze specyfikacją DX.
/// depth
LPDIRECT3DTEXTURE9 lpTexDepth;
LPD3DXRENDERTOSURFACE m_pRenderToDepth;
LPDIRECT3DSURFACE9 pd3dsSurfaceDepth;
////
LPDIRECT3DSURFACE9 lpBackBufferTmp;
LPDIRECT3DTEXTURE9 lpTexture;
LPD3DXRENDERTOSURFACE m_pRenderToSurface;
LPDIRECT3DSURFACE9 pd3dsSurface;
Initializujemy je w nastepujący sposób (w funkcji InitEfectPP):
HRESULT hr = S_OK;// = lpD3DDevice->CreateRenderTarget(
D3DDISPLAYMODE mode;
lpD3DDevice->GetDisplayMode(0,&mode);
D3DXCreateTexture( lpD3DDevice,
800,
600,
1,
D3DUSAGE_RENDERTARGET ,
mode.Format,
D3DPOOL_DEFAULT,
&lpTexture
);
D3DSURFACE_DESC desc;
hr = lpTexture->GetSurfaceLevel(0, &pd3dsSurface);
pd3dsSurface->GetDesc(&desc);
if(FAILED(hr=D3DXCreateRenderToSurface(lpD3DDevice, desc.Width, desc.Height, mode.Format, TRUE, D3DFMT_D16, &m_pRenderToSurface)))
return false;
}
lpD3DDevice->CreateDepthStencilSurface(
D3DFMT_D16,
D3DMULTISAMPLE_NONE,
0,
TRUE,
&pd3dsSurfaceDepth,
NULL );
Warto zwrócić uwagę na fakt, że tekstura która będzie służyła za backbuffer jest tworzona z rozmiarem 800x600 a tekstura, która będzie buforem głębi jest tworzona za pomocą metody ...
Phoob