V dneÜnφ lekci p°idßme podporu vertex a index buffer∙ do naÜeho enginu. V druhΘ Φßsti si povφme n∞co o technice mipmap, tak₧e dßle rozÜφ°φme t°φdu XTexture z p°edminulΘ lekce.
Tyto buffery jsou podobn∞ jako textury pova₧ovßny za zdroje, tak₧e je nutnΘ je p°i ztrßt∞ za°φzenφ smazat, znovu vytvo°it a naplnit. Zde nastßvß problΘm jak uchovat data z bufferu. Mohli bychom vytvo°it kopii t∞chto dat a z tΘto kopie obnovit obsah, ale tento zp∙sob by byl znaΦn∞ pam∞¥ov∞ neefektivnφ, nebo¥ bychom data m∞li v pam∞ti dvakrßt! Na druhou stranu bychom se o obnovu bufferu nemuseli v∙bec starat. ProblΘm m∙₧eme vy°eÜit tak, ₧e po obnovenφ buffer∙ (tj. po volßnφ funkce RestoreBuffer()) znovu naplnφme buffer, tak₧e o obsah se bude starat klientskß aplikace (v naÜem p°φkladu program Tester). U dynamick²ch buffer∙ tento problΘm v∙bec nenastßvß, proto₧e tyto buffery jsou pln∞ny v ka₧dΘm cyklu aplikace, tak₧e staΦφ pouze znovu vytvo°it buffer.
Do projektu Display p°idßme dv∞ novΘ t°φdy:
- XVertexBuffer
- XIndexBuffer
Ob∞ tyto t°φdy budou mφt velice podobnΘ metody:
- Create()
- Release()
- Restore()
- GetBuffer()
- GetDevice()
VÜimn∞te si, ₧e metody jsou velice podobnΘ t∞m z t°φdy
XTexture. Ob∞ t°φdy se budou liÜit jen v n∞kolika parametrech metody
Create().
Deklarace t°φd:
class
XVertexBuffer
{
UINT m_uiLength;
DWORD m_dwUsage;
DWORD m_dwFVF;
D3DPOOL m_d3dPool;
IDirect3DVertexBuffer8* m_pVertexBuffer;
IDirect3DDevice8* m_lpDevice;
public:
int Create(UINT uiLength, DWORD dwUsage, DWORD dwFVF, D3DPOOL
dwPool, LPDIRECT3DDEVICE8 lpDevice);
int Restore();
void Release();
LPDIRECT3DVERTEXBUFFER8 GetBuffer() { return m_pVertexBuffer;
}
LPDIRECT3DDEVICE8 GetDevice() {return m_lpDevice; }
public:
XVertexBuffer(void);
~XVertexBuffer(void);
};
class XIndexBuffer
{
UINT m_uiLength;
DWORD m_dwUsage;
D3DFORMAT m_dwFormat;
D3DPOOL m_d3dPool;
IDirect3DIndexBuffer8* m_pIndexBuffer;
IDirect3DDevice8* m_lpDevice;
public:
int Create(UINT uiLength, DWORD dwUsage, D3DFORMAT dwFormat,
D3DPOOL dwPool, LPDIRECT3DDEVICE8 lpDevice);
int Restore();
void Release();
LPDIRECT3DINDEXBUFFER8 GetBuffer() { return m_pIndexBuffer; }
LPDIRECT3DDEVICE8 GetDevice() {return m_lpDevice; }
public:
XIndexBuffer(void);
~XIndexBuffer(void);
};
Z minul²ch lekcφ ji₧ vφme jakΘ parametry majφ tyto buffery. VÜechny tyto
parametry musφme ulo₧il ve t°φd∞, abychom mohli buffer obnovit. Uklßdßme takΘ
ukazatel na za°φzenφ a samotn² buffer. Implementace metod bude velice podobnß
jako u t°φdy XTexture. Uvedu zde pouze implementaci
metod t°φdy XVertexBuffer, proto₧e implementace
t°φdy XIndexBuffer je obdobnß.
XVertexBuffer::XVertexBuffer(void)
{
m_lpDevice = NULL;
m_pVertexBuffer = NULL;
}
XVertexBuffer::~XVertexBuffer(void)
{
Release();
m_lpDevice = NULL;
}
int XVertexBuffer::Create(UINT uiLength, DWORD dwUsage, DWORD dwFVF, D3DPOOL
dwPool, LPDIRECT3DDEVICE8 lpDevice)
{
if(!lpDevice)
{
THROW("CreateVertexBuffer: Device is
invalid.");
}
if(!m_pVertexBuffer)
{
m_lpDevice = lpDevice;
m_uiLength = uiLength;
m_dwUsage = dwUsage;
m_dwFVF = dwFVF;
m_dwPool = dwPool;
DWORD dwRet = m_lpDevice->CreateVertexBuffer(uiLength,
dwUsage, dwFVF, dwPool, &m_pVertexBuffer);
if(dwRet != S_OK) {
THROWERR("Cannot
create Vertex buffer due", dwRet);
}
return 0;
}
return -1;
}
int XVertexBuffer::Restore()
{
if(m_lpDevice && !m_pVertexBuffer)
{
DWORD dwRet = m_lpDevice->CreateVertexBuffer(m_uiLength,
m_dwUsage, m_dwFVF, m_dwPool, &m_pVertexBuffer);
if(dwRet != S_OK) {
THROWERR("Cannot
create Vertex buffer due", dwRet);
}
return 0;
}
return -1;
}
void XVertexBuffer::Release()
{
SAFE_RELEASE(m_pVertexBuffer);
}
Ve funkci Create() je nutnΘ zßlohovat vÜechny parametry vytvß°enΘho bufferu. Tyto parametry pozd∞ji vyu₧ijeme v metod∞ Restore().
Na zßv∞r tΘto Φßsti jeÜt∞ p°idßme podporu buffer∙ do naÜeho mana₧eru zdroj∙. P°idejme dv∞ dynamickß pole:
std::vector <XVertexBuffer*>
m_arVB;
std::vector <XIndexBuffer*> m_arIB;
a dvojici metod pro obsluhu t∞chto polφ:
int AddVertexBuffer(XVertexBuffer *
pBufferToAdd);
int AddIndexBuffer(XIndexBuffer * pBufferToAdd);
Princip je obdobn² jako v p°φpad∞ textur a mesh∙.
V tΘto Φßsti si vysv∞tlφme co je to mipmapping a upravφme t°φdu XTexture tak, aby mipmapping podporovala.
Zßkladnφm problΘmem u textur je pou₧itφ sprßvnΘ velikosti nebo detailnosti textury. Pokud pou₧ijete texturu o rozm∞rech 1024x1024, tak sice docφlφte perfektnφho vzhledu blφzk²ch objekt∙, ale vzdßlenΘ objekty budou vypadat divn∞ (je vid∞t, ₧e textura je zbyteΦn∞ detailnφ) a navφc bude vykreslovßnφ mnohem pomalejÜφ! Pokud naopak pou₧ijete texturu 16x16, tak budou vÜechny objekty vylo₧en∞ oÜklivΘ! DoporuΦenß velikost textury je 256x256. S touto texturou by m∞ly grafickΘ karty pracovat nejrychleji. N∞kdy ale pot°ebujete jen 64x64, pak vytvo°φte texturu 256x256 a v nφ polφΦka o rozm∞rech 64x64. V ka₧dΘm polφΦku pak bude jinß textura. Sprßvnou texturu vybereme pomocφ texturov²ch sou°adnic. ProblΘm s detaily vÜak p°etrvßvß. NejlepÜφ by bylo, kdyby objekty, kterΘ jsou blφzko m∞ly detailnφ texturu a objekty vzdßlenΘ m∞ly mΘn∞ detailnφ texturu. A p°esn∞ tohle d∞lß mipmapping!
Jak to pracuje?
M∞jme zßkladnφ texturu o rozm∞rech 256x256. K tΘto zßkladnφ textu°e
vytvo°φme dalÜφ textury o rozm∞rech 128x128, 64x64, 32x32, 16x16, 8x8, 4x4, 2x2,
1x1 podle ·rovn∞ mipmap. SystΘm DirectD3 pak chyt°e nanßÜφ na nejbli₧Üφ objekty
nejdetailn∞jÜφ texturu, na vzdßlen∞jÜφ objekty mΘn∞ detailnφ texturu atd. Ve
skuteΦnosti tak zabijete dv∞ mouchy jednou ranou: vÜechny objekty ve scΘn∞
vypadajφ tak jak majφ a zßrove≥ nepou₧φvßte zbyteΦn∞ velkΘ textury na vzdßlenΘ
objekty, tak₧e vykreslovßnφ je rychlejÜφ.
Jak vytvo°φme mipmapy?
Zde je n∞kolik mo₧nostφ. Bu∩ vytvo°φte ruΦn∞ vÜechny textury jednotliv²ch
·rovnφ mipmap, kterΘ pak ruΦn∞ nahrajete. Nebo textury vytvo°φte programov∞ ze
zßkladnφ textury anebo pou₧ijete funkci
D3DXLoadTextrureFromFileEx(), kterß ud∞lß vÜe za vßs:) V naÜem p°φklad∞
pou₧ijeme t°etφ mo₧nost.
Nynφ zavedeme podporu mipmap do naÜeho projektu. P°idßme metodu LoadTextureFromFileEx(). Metoda bude vypadat podobn∞ jako LoadTextureFromFile(), ale p°idßme navφc jeden parametr typu int. Tento parametr urΦφ poΦet ·rovnφ mimap. Je zbyteΦnΘ vytvß°et mipmapy a₧ do ·rovn∞ 1x1. Pokud v tomto parametru zadßte 1, textura se vytvo°φ bez mipmap (k tomuto ·Φelu je ale lepÜφ volat metodu LoadTextureFromFile()). V p°φpad∞, ₧e p°edßte parametr rovn² 0, vytvo°φ se kompletnφ °et∞z mipmap tj. a₧ do ·rovn∞ 1x1.. Dßle je t°eba p°idat barevn² formßt textury, proto₧e tento parametr vy₧aduje rozÜφ°enß funkce D3DXLoadTextureFromFileEx(). Formßt zφskßme ze t°φdy XDisplay. UvedenΘ dva parametry musφme ulo₧it do t°φdy XTexture, abychom mohli texturu obnovit v metod∞ Restore().
int XTexture::LoadTextureFromFileEx(LPCSTR
szFileName, int iMipLevels, D3DFORMAT formatTextureFormat, LPDIRECT3DDEVICE8
lpDevice)
{
if(!lpDevice)
{
THROW("LoadTextureFromFileEx: Device
is invalid.");
}
if(!m_lpTexture)
{
// create full path to the texture
if(!cmnGetDataFilePath(m_szFilePath, szFileName))
{
TRACE("Cannot
create full path to the texture.");
}
if(D3D_OK !=
D3DXCreateTextureFromFileEx(lpDevice, m_szFilePath, 0, 0, iMipLevels,
D3DUSAGE_RENDERTARGET, formatTextureFormat, D3DPOOL_DEFAULT,
D3DX_DEFAULT , D3DX_DEFAULT, 0, NULL, NULL, &m_lpTexture))
{
TRACE("Texture
'%s' was loaded.", szFileName);
}
else
{
TRACE("Texture
'%s' wasn't loaded.", szFileName);
}
// save information to restore
m_lpDevice = lpDevice;
m_iMipLevels = iMipLevels;
m_formatTextureFormat =
formatTextureFormat;
return 0;
}
return -1;
}
Upravenß metoda LoadTextureFromFileEx() je vlastn∞ stejnß jako primitivnφ verze, jen mφsto D3DXLoadTextureFromFile() pou₧φvß D3DXLoadTextureFromFileEx() a uklßdß poΦet mipmap ·rovnφ a formßt textury.
Pro ·plnost jeÜt∞ uvedu p∙vodnφ metodu LoadTextureFromFile():
int XTexture::LoadTextureFromFile(LPCSTR
szFileName, LPDIRECT3DDEVICE8 lpDevice)
{
if(!lpDevice)
{
THROW("LoadTextureFromFile: Device is
invalid.");
}
if(!m_lpTexture)
{
// create full path to the texture
if(!cmnGetDataFilePath(m_szFilePath,
szFileName))
{
TRACE("Cannot
create full path to the texture.");
}
if(D3D_OK !=
D3DXCreateTextureFromFile(lpDevice, m_szFilePath, &m_lpTexture))
{
TRACE("Texture
'%s' was loaded.", szFileName);
}
else
{
TRACE("Texture
'%s' wasn't loaded.", szFileName);
}
// save information to restore
m_lpDevice = lpDevice;
m_iMipLevels = 1;
return 0;
}
return -1;
}
Zde si musφme poznamenat, ₧e textura je bez mipmap, tak₧e mß pouze jednu ·rove≥.
Na zßv∞r si uvedeme rozdvojenou metodu Restore():
int XTexture::Restore()
{
// reinit texture
if(m_lpDevice)
{
if(m_iMipLevels == 1)
{
// try to
create texture
if(D3D_OK ==
D3DXCreateTextureFromFile(m_lpDevice, m_szFilePath, &m_lpTexture))
{
TRACE("Texture '%s' was reloaded.", m_szFilePath);
}
else
{
TRACE("Texture '%s' wasn't reloaded.", m_szFilePath);
}
}
else
{
if(D3D_OK !=
D3DXCreateTextureFromFileEx(m_lpDevice, m_szFilePath, 0, 0, m_iMipLevels,
D3DUSAGE_RENDERTARGET, m_formatTextureFormat, D3DPOOL_DEFAULT,
D3DX_DEFAULT , D3DX_DEFAULT, 0, NULL, NULL, &m_lpTexture))
{
TRACE("Texture '%s' was reloaded.", m_szFilePath);
}
else
{
TRACE("Texture '%s' wasn't reloaded.", m_szFilePath);
}
}
}
return -1;
}
Mo₧nß jste si vÜimli t∞chto t°φ °ßdk∙ v metod∞ Init() t°φdy XDisplay:
// Set texture filter
for first stage
m_lpD3DDevice->SetTextureStageState(0,
D3DTSS_MIPFILTER, m_tftMipTextureFilter);
m_lpD3DDevice->SetTextureStageState(0, D3DTSS_MAGFILTER, m_tftMagTextureFilter);
m_lpD3DDevice->SetTextureStageState(0, D3DTSS_MINFILTER, m_tftMinTextureFilter);
Takto nastavφme filtrovßnφ textur a filtrovßnφ mezi jednotliv²mi ·rovn∞mi mipmap.
Prom∞nnΘ m_tftXXXTextureFilter nastavujeme podle nßsledujφcφ tabulky v projektu Setup:
Typ filtrovßnφ | Typ MAG filtru | Typ MIN filtru | Typ MIPMAP filtru |
Bilinear filtering | linear magnification | linear minification | point mipmapping |
Trilinear filtering | linear magnification | linear minification | linear mipmapping |
Bilinear Anisotropic filtering | anisotropic magnification | anisotropic minification | point mipmapping |
Trilinear Anisotropic filtering | anisotropic magnification | anisotropic minification | linear mipmapping |
Na zßv∞r lekce vyzkouÜφme novΘ funkce naÜeho enginu v projektu Tester. Vytvo°φme jednoduch² Φtverec v prostoru, kter² se bude sklßdat ze Φty° vertex∙. Tyto vrcholy ulo₧φme do vertexu bufferu a indexovat je budeme pomocφ index bufferu. Dßle nahrajeme texturu, u kterΘ vytvo°φme mipmap °et∞z. Aby byl vid∞t efekt mipmap, pou₧il jsem texturu velk²ch rozm∞r∙, kterou naneseme na relativn∞ malou plochu.
Nadeklarujete tyto novΘ prom∞nnΘ:
XVertexBuffer g_vbQuad;
XIndexBuffer g_ibQuad;
XTexture g_texMipmap;
BOOL g_bQuadVis = FALSE;
BOOL g_bQuadStop = FALSE;
// world matrix
D3DXMATRIX g_matWorld1;
D3DXMATRIX g_matWorld2;
Rotujφcφ Φtverec mß jinou sv∞tovou transformaΦnφ matici (otßΦφ se kolem osy Z) ne₧ ostatnφ objekty (otßΦφ se kolem osy X), tak₧e jsem pro ob∞ transformace vytvo°il zvlßÜtnφ sv∞tovΘ matice. V p°φÜtφ lekci tuto techniku trochu vylepÜφme. Rotaci Φtverce navφc bude mo₧no zastavit mezernφkem a to urΦφ prom∞nnß g_bQuadStop. To, zda-li je Φtverec vid∞t, urΦφ prom∞nnß g_bQuadVis. Ostatnφ prom∞nnΘ jsem popsal v²Üe. Dßle p°idejme funkci, kterß naplnφ oba buffery daty:
void FillBuffers();
Tyto °ßdky p°idejte do funkce WinMain():
// init world matrices
D3DXMatrixIdentity(&g_matWorld1);
D3DXMatrixIdentity(&g_matWorld2);
// prepare quad
g_vbQuad.Create(4 * sizeof(VERTEX),
D3DUSAGE_WRITEONLY, VERTEXFORMAT, D3DPOOL_DEFAULT, g_theDisplay.GetDevice());
g_ibQuad.Create(6 * sizeof(WORD), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16 ,
D3DPOOL_DEFAULT, g_theDisplay.GetDevice());
g_texMipmap.LoadTextureFromFileEx("grass.bmp", 5, g_theDisplay.GetTextureFormat(),
g_theDisplay.GetDevice());
g_theDisplay.GetResourceManager()->AddIndexBuffer(&g_ibQuad);
g_theDisplay.GetResourceManager()->AddVertexBuffer(&g_vbQuad);
g_theDisplay.GetResourceManager()->AddTexture(&g_texMipmap);
FillBuffers();
Zde inicializujeme ob∞ matice, dßle vytvo°φme oba buffery.
Mßme 4 vrcholy a 6 index∙ (dva troj·helnφky po t°ech vrcholech), vytvo°φme
texturu pomocφ novΘ metody LoadTextureFromFileEx()
a vÜechny zdroje vlo₧φme do mana₧eru zdroj∙. Nakonec zavolßme funkci
FillBuffers(), kterß naplnφ oba buffery daty:
void FillBuffers()
{
VERTEX *pVertices;
g_vbQuad.GetBuffer()->Lock(0, 0, (BYTE**) &pVertices, 0);
pVertices[0].vecPos = D3DXVECTOR3(-4.0f, -4.0f, 2.0f);
pVertices[1].vecPos = D3DXVECTOR3(4.0f, -4.0f, 2.0f);
pVertices[2].vecPos = D3DXVECTOR3(-4.0f, 4.0f, 2.0f);
pVertices[3].vecPos = D3DXVECTOR3(4.0f, 4.0f, 2.0f);
pVertices[0].vecNormal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
pVertices[1].vecNormal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
pVertices[2].vecNormal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
pVertices[3].vecNormal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
pVertices[0].tu1 = 0.0f;
pVertices[0].tv1 = 0.0f;
pVertices[1].tu1 = 1.0f;
pVertices[1].tv1 = 0.0f;
pVertices[2].tu1 = 0.0f;
pVertices[2].tv1 = 1.0f;
pVertices[3].tu1 = 1.0f;
pVertices[3].tv1 = 1.0f;
pVertices[0].dwDiffuse = 0xFFFFFFFF;
pVertices[1].dwDiffuse = 0xFFFFFFFF;
pVertices[2].dwDiffuse = 0xFFFFFFFF;
pVertices[3].dwDiffuse = 0xFFFFFFFF;
g_vbQuad.GetBuffer()->Unlock();
WORD *pIndices;
g_ibQuad.GetBuffer()->Lock(0, 0, (BYTE**) &pIndices, 0);
pIndices[0] = 0;
pIndices[1] = 1;
pIndices[2] = 2;
pIndices[3] = 1;
pIndices[4] = 3;
pIndices[5] = 2;
g_ibQuad.GetBuffer()->Unlock();
}
Tento postup jsme ji₧ pou₧ili v n∞kterΘ p°edeÜlΘ lekci. Nejprve je t°eba buffer
uzamknout a tak zφskat p°φm² p°φstup do pam∞ti tohoto bufferu. Na zßv∞r je
samoz°ejm∞ t°eba volat metodu Unlock() pro oba
buffery.
Nynφ upravme obslu₧nou proceduru okna tak, aby se stiskem klßvesy F8 zobrazil nßÜ nov² Φtverec, ale zßrove≥ se musφ vÜechny ostatnφ objekty skr²t. Pod mezernφk navφc namapujeme funkci zastavenφ rotace Φtverce:
case VK_F9:
g_theDisplay.RestoreDisplay();
RestoreUserObjects();
FillBuffers();
break;
case VK_F1:
g_Sphere.Visible(!g_Sphere.IsVisible());
g_bQuadVis = FALSE;
break;
case VK_F2:
g_Torus.Visible(!g_Torus.IsVisible());
g_bQuadVis = FALSE;
break;
case VK_F3:
g_Box.Visible(!g_Box.IsVisible());
g_bQuadVis = FALSE;
break;
case VK_F4:
g_Cylinder.Visible(!g_Cylinder.IsVisible());
g_bQuadVis = FALSE;
break;
case VK_F5:
g_Teapot.Visible(!g_Teapot.IsVisible());
g_bQuadVis = FALSE;
break;
case VK_F6:
g_Tiger.Visible(!g_Tiger.IsVisible());
g_bQuadVis = FALSE;
break;
case VK_F7:
g_Airplane.Visible(!g_Airplane.IsVisible());
g_bQuadVis = FALSE;
break;
case VK_F8:
g_Torus.Visible(FALSE);
g_Sphere.Visible(FALSE);
g_Box.Visible(FALSE);
g_Tiger.Visible(FALSE);
g_Airplane.Visible(FALSE);
g_Teapot.Visible(FALSE);
g_Cylinder.Visible(FALSE);
g_bQuadVis = TRUE;
break;
case VK_SPACE:
if(g_bQuadVis)
g_bQuadStop = !g_bQuadStop;
break;
case VK_ESCAPE:
PostQuitMessage(0);
break;
Dßle si vÜimn∞te volßnφ funkce FillBuffers() po volßnφ RestoreUserObjects(). Zde prßv∞ plnφme ji₧ novΘ buffery, kterΘ systΘm vytvo°il po resetu za°φzenφ. Nakonec zde uvedu funkci UpdateFrame():
void UpdateFrame()
{
// svetlo se bude pohybovat po kruznici
g_PointLight.Position.x = 0.0f;
g_PointLight.Position.y = float(4.0f * sin(double(GetTickCount())/300.0f));
g_PointLight.Position.z = float(5.0f * cos(double(GetTickCount())/300.0f));
g_theDisplay.SetLight(1, &g_PointLight);
g_theDisplay.EnableLight(1, TRUE);
// draw scene
g_theDisplay.UpdateBackground();
g_theDisplay.GetDevice()->BeginScene();
g_Sphere.Draw();
g_Torus.Draw();
g_Box.Draw();
g_Cylinder.Draw();
g_Teapot.Draw();
// tygr nema definovane normalove vektory, takze je treba
vypnout osvetleni
g_theDisplay.GetDevice()->SetRenderState(D3DRS_LIGHTING,
FALSE);
g_Tiger.Draw();
g_theDisplay.GetDevice()->SetRenderState(D3DRS_LIGHTING, TRUE);
g_Airplane.Draw();
if(g_bQuadVis)
{
D3DXMATRIX matRot;
float fFactor = cmnGetTime(TIMER_GETELAPSEDTIME1);
if(fFactor != 0 && !g_bQuadStop) {
D3DXMatrixRotationZ(&matRot, 0.9f * fFactor);
D3DXMatrixMultiply(&g_matWorld2, &g_matWorld2, &matRot);
g_theDisplay.GetDevice()->SetTransform(D3DTS_WORLD,
&g_matWorld2);
}
g_theDisplay.GetDevice()->SetRenderState(D3DRS_LIGHTING,
FALSE);
g_theDisplay.GetDevice()->SetVertexShader(VERTEXFORMAT);
g_theDisplay.GetDevice()->SetStreamSource(0,
g_vbQuad.GetBuffer(), sizeof(VERTEX));
g_theDisplay.GetDevice()->SetIndices(g_ibQuad.GetBuffer(),
0);
g_theDisplay.GetDevice()->SetTexture(0,
g_texMipmap.GetTexture());
g_theDisplay.GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
0, 4, 0, 2);
g_theDisplay.GetDevice()->SetRenderState(D3DRS_LIGHTING,
TRUE);
}
else
{
D3DXMATRIX matRot;
float fFactor = cmnGetTime(TIMER_GETELAPSEDTIME1);
if(fFactor != 0) {
D3DXMatrixRotationX(&matRot, 0.9f * fFactor);
D3DXMatrixMultiply(&g_matWorld1, &g_matWorld1, &matRot);
g_theDisplay.GetDevice()->SetTransform(D3DTS_WORLD,
&g_matWorld1);
}
}
g_theDisplay.GetDevice()->EndScene();
if(D3DERR_DEVICENOTRESET == g_theDisplay.Present())
{
RestoreUserObjects();
FillBuffers();
}
}
Zde rozliÜujeme p°φpad, kdy je rotujφcφ Φtverec vid∞t a kdy
ne. Pokud je vid∞t, je t°eba aplikovat jinou transformaci na sv∞tovou matici
scΘny (matice mßme dv∞, aby pohyb obou soustav zaΦal v₧dy tam kde skonΦil) a pak
vykreslφme Φtverec v t∞chto krocφch:
1) Vypnutφ sv∞tla
2) Nastav∞nφ formßtu vrchol∙
3) Nastav∞nφ zdrojovΘho vertex bufferu
4) Nastavenφ zdrojovΘho index bufferu
5) Nastavenφ textury
6) SamotnΘ vykreslenφ Φtverce
7) Zapnutφ sv∞tla
VÜechny tyto kroky jsme ji₧ rozebφrali podrobn∞ji v minul²ch lekcφch. V druhΘm p°φpad∞, pokud nenφ rotujφcφ Φtverec vid∞t, nastavφme jinou sv∞tovou matici, kterou provßdφme rotaci ostatnφch objekt∙ kolem osy X.
Nynφ se ji₧ t°φda XDisplay nestarß o transformaci sv∞tovΘ matice, tak₧e tento k≤d m∙₧ete zcela odstranit (jednß se o deklaraci matice, vytvo°enφ a samotnou transformaci matice). Dßle jsme pou₧ili strukturu VERTEX deklarovanou nßsledovn∞:
struct VERTEX
{
D3DXVECTOR3 vecPos;
D3DXVECTOR3 vecNormal;
DWORD dwDiffuse;
float tu1, tv1;
};
V naÜem p°φkladu inicializujeme i normßlovΘ vektory, ale v praxi je vlastn∞ nepou₧ijeme, proto₧e vypφnßme osv∞tlenφ.
Klßvesou F8 zobrazφte rotujφcφ Φtverec, na kterΘm je nanesena velkß textura. Kdy₧ si Φtverec zastavφte (mezernφkem) ve sprßvnΘ poloze, jsou vid∞t jednotlivß rozhranφ mipmap (nejlΘpe je to vid∞t, kdy₧ mßte nastaveno obyΦejnΘ bilineßrnφ filtrovßnφ).
V p°φÜtφ lekci se koneΦn∞ podφvßme na transformaci jednotliv²ch objekt∙ pomocφ matic.
T∞Üφm se p°φÜt∞ nashledanou.