DirectX9 - 3. návod - Matice
DirectX9 - 3. návod - Matice
3. Matice
Cíl
Příprava
InitD3D - Vytvoření vykreslovacího zařízení
InitGeometry - Vytvoření geometrie scény
Cleanup - Uvolnění alokovaných proměnných
SetupMatrices - Nastaví transformační matice
Render - Funkce pro vykreslení
MsgProc - Zachytávání a zpracování zpráv okna
WinMain - Vstupní bod naší aplikace
Poznámka na závěr
Příklad je zde ke staženíCíl
Nyní když už víme jak vytvořit D3DDevice a vykreslit díky němu nějaké 2D vertexy, můžeme jít o krůček dál a vykreslit 3D geometrii. Abychom se ale s 3D prostorem vypořádali, potřebujeme zasvětit do používání 4x4 transformačních matic pro posun, rotaci, zvětšení a projekci do 2D. Zní to náročně, ale práce s těmito maticemi je po krátké době velmi intuitivní.Geometrie je definována v modelovém prostoru. Můžeme objekt posouvat (translation), otáčet (rotation), natahovat (scaling) atd, nebo rovnou aplikovat kombinaci těchto operací. To vše pomocí "World" matice. O geometrii se poté říká, že je ve world (modelovém) prostoru. Další věcí je umístění kamery a natočení směru pohledu na objekt. Další transformační maticí tedy bude "View" matice, tedy matice pohledu na scénu. Díky ní můžeme posouvat, natáčet a nebo třeba rotovat pohledem kamery. Po aplikaci i této matice říkáme, že objekt je ve "View" prostoru, česky něco jako v prostoru pohledu kamery. Poslední, tedy třetí transformací, je "Projection" matice, tedy matice finální projekce z 3D prostoru před kamerou do 2D prostoru okna.
Všimněme si, že v tomto tutoriálu namísto knihovny D3D9 používáme D3DX9. Rozdíl je ten, že X verze obsahuje navíc spoustu užitečných nástrojů, mimo jiné i pro práci s maticemi. Pro použití D3DX9 knihovny stačí namísto d3d9.h includovat d3dx9.h a slinkovat s knihovnou d3dx9.lib
nahoru
Příprava
Založíme si projekt (viz. Nultý tutorial). A můžeme začít psát zdrojový text... Nejdříve naincludujeme potřebnou DirectX hlavičku, tentokrát to namísto d3d9.h bude d3dx9.h#include <d3dx9.h>Nyní si připravíme globální proměnné, které budeme potřebovat. Změnou oproti minulému tutoriálu je to, že nedefinujeme již transformovanou pozici každého vertexu do 2D, ale poctivě ještě ve 3D. Je to tedy poprvé, kdy opravdu programujeme DirectX 3D aplikaci.
LPDIRECT3D9 g_pD3D = NULL; // Používá se k vytvoření D3DDevice
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; // Naše vykreslovací zařízení
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer k uchování vertexů
// Struktura pro náš uživatelsky definovaný vertex
struct CUSTOMVERTEX
{
FLOAT x, y, z; // Netransformovaná 3D pozice pro vertex
DWORD color; // Barva
};
// Uživatelský FVF (flexibilní vertex-formát),který popisuje naši strukturu
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE)
nahoru
InitD3D - Vytvoření vykreslovacího zařízení
HRESULT InitD3D( HWND hWnd )Tato funkce je téměř stejná jako ta v předchozím návodu, tedy nejprve klasicky vytvoříme D3D objekt a z něho poté vykreslovací zařízení d3dDevice.
// Vytvoříme D3D objekt
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
// Nastavíme strukturu použitou pro vytvoření D3DDevice
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// Vytvoříme D3DDevice (vykreslovací zařízení)
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
return E_FAIL;
}
Nyní ale oproti předchozímu tutoriálu konečně nastavíme alespoň dva parametry pro naše vykreslovací zařízení. Potřebujeme totiž
vypnout kontrolu natočení polygonů (culling), díky které bychom neviděli zadní stranu
polygonu. Déle ještě vypneme hardwarové osvětlování scény, protože máme barvy jednotlivých
vertexů dány napevno.
// Vypneme "culling", díky tomu uvidíme i zadní stranu polygonu
g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
// Vypneme D3D osvětlování, protože už barvu vertexu máme pevně danou
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
return S_OK;
nahoru
InitGeometry - Vytvoření geometrie scény
HRESULT InitGeometry()Tato funkce se bude nyní objevovat namísto předešlé InitVB (inicializace vertex bufferu) Její obsah bude podobný, tedy vytvoření vertex bufferu a naplnění ho hodnotami. Později se ale naučíme získávat geometrii ze souborů a Vertex buffer nahradí Mesh.
Protentokrát je ale obsah opravdu velmi podobný, vytvoříme si tři vertexy (tentokrát ve 3D), poté Vertex buffer a nakonec ho těmito vertexy naplníme.
// Inicializujeme tři vertexy pro náš trojúhelník
CUSTOMVERTEX g_Vertices[] =
{
{ -1.0f,-1.0f, 0.0f, 0xffff0000, },
{ 1.0f,-1.0f, 0.0f, 0xff0000ff, },
{ 0.0f, 1.0f, 0.0f, 0xffffffff, },
};
// Vytvoříme vertex buffer
if( FAILED( g_pd3dDevice->CreateVertexBuffer( 3*sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB,
NULL ) ) )
{
return E_FAIL;
}
// Naplníme vertex buffer
VOID* pVertices;
if( FAILED( g_pVB->Lock( 0, sizeof(g_Vertices), (void**)&pVertices, 0 ) ) )
return E_FAIL;
memcpy( pVertices, g_Vertices, sizeof(g_Vertices) );
g_pVB->Unlock();
return S_OK;
nahoru
Cleanup - Uvolnění alokovaných proměnných
VOID Cleanup()I tato funkce byla podrobněji nastíněna v 1. příkladu. Jedinou změnou zde je nutnost krom d3dDevice (vykreslovacího zařízení) a D3D (Instance Direct3D) uvolnit také vertex buffer.
if( g_pVB != NULL )
g_pVB->Release();
if( g_pd3dDevice != NULL )
g_pd3dDevice->Release();
if( g_pD3D != NULL )
g_pD3D->Release();
nahoru
SetupMatrices - Nastaví transformační matice
VOID SetupMatrices()Nová funkce, která nám při každém snímku přenastaví všechny tři matice (world, view, projection). První z nich (world) v podstatě znamená umístění objektu - nastavujeme tzv. modelový prostor. V našem případě budeme touto maticí otáčet kolem osy y s dobou periody 1s a tedy se nám v důsledku bude otáčet objekt. Druhá matice (view) nám udává v podstatě umístění kamery. Tato se měnit nebude, kamera se bude stále dívat z pozice 5 jednotek zpět po ose z a 3 jednotky vzhůru a směřovat bude na počátek (0,0,0). Třetí a poslední maticí (projection) nastavíme způsob promítnutí do 2D plochy našeho okna. Zde nastavíme zorný úhel Pi/4 radiánů, poměr stran 1:1, a vykreslovat budeme vše ve vzdálenosti od 1.0 do 100.0
// Pro World matici bude stačit rotace kolem osy y
D3DXMATRIXA16 matWorld;
UINT iTime = timeGetTime() % 1000;
FLOAT fAngle = iTime * (2.0f * D3DX_PI) / 1000.0f;
D3DXMatrixRotationY( &matWorld, fAngle );
g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
// Nastavíme View matici (kameru)
D3DXVECTOR3 vEyePt( 0.0f, 3.0f,-5.0f );
D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
D3DXMATRIXA16 matView;
D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );
// Nyní ještě Projection matici
D3DXMATRIXA16 matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
nahoru
Render - Funkce pro vykreslení
VOID Render()Již známá funkce. Jediným rozdílem je, že po zahájení vykreslovaní (není nutností) a ještě před tím, než něco skutečně vykreslíme, zavoláme funkci SetupMatrices(), která se postará o nastavení všech tří matic.
// Vyčistíme back buffer na černou barvu
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
// Zahájíme vykreslování
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
// Nastavíme world, view a projection matici
SetupMatrices();
// Vykreslíme obsah vertex bufferu
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 1 );
// Ukončíme vykreslování
g_pd3dDevice->EndScene();
}
// Zobrazíme vše na obrazovku
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
nahoru
MsgProc - Zachytávání a zpracování zpráv okna
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )Na konec klasicky dvě funkce pro režii Windows. Tentokrát se zde opravdu ničeho nového nedočkáme a proto jen uvádím jejich zdrojový text.
switch( msg )
{
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
nahoru
WinMain - Vstupní bod pro naši aplikaci
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )Poslední a hlavní funkce, po spuštění se volá právě ona.
// Registrace třídy okna
WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
"Dx9 Tutorial 3", NULL };
RegisterClassEx( &wc );
// Vytvoření okna aplikace
HWND hWnd = CreateWindow( "Dx9 Tutorial 3", "Dx9 3 - Matice",
WS_OVERLAPPEDWINDOW, 100, 100, 256, 256,
NULL, NULL, wc.hInstance, NULL );
// Inicializace Direct3D
if( SUCCEEDED( InitD3D( hWnd ) ) )
{
// Vytvoření geometrie scény
if( SUCCEEDED( InitGeometry() ) )
{
// Zobrazení okna
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// Vstoupíme do smyčky zpracování zpráv
MSG msg;
ZeroMemory( &msg, sizeof(msg) );
while( msg.message!=WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
Render();
}
}
}
UnregisterClass( "Dx9 Tutorial 3", wc.hInstance );
return 0;
nahoru
Poznámka na závěr
Tento text je téměř přesným opisem výsledného zdrojového textu. Vynechány byly částečně komentáře, které nahrazuje tento text. Zdrojový text ke stažení na konci této stránky ale ony komentáře obsahuje a umožní Vám to lepší orientaci i bez stálého připojení na tyto stránky.Dále byly vynechány složené závorky jednotlivých těl funkcí.
nahoru
Příklad je zde ke stažení
- Příklad #3 Src - Zdrojové texty s projektem pro Microsoft Visual Studio 2005
- Příklad #3 Exe - Spustitelný, již zkompilovaný program
nahoru
| Jan Zelený | 22.3.2007 |
© 2008 Jan Zelený | monade.cz





