Több vertexbuffer létrehozása, bemenetek kezelése
1. Kezdjünk új projektet az EmptyProject-ből!
2. Adjuk hozzá a szokásos eseménykezelőket, az FVF leírást, a struktúrát, amibe a vertex-adatok kerülnek és két vertexbuffert!
Ha a vertex formátum (FVF) ugyan olyan több vertexbuffer között, akkor nincs szükség újabb struktúra vagy FVF leírás létrehozására. (Igazából külön vertexbufferre sincs feltétlenül szükség, de ez haladóbb kérdés).
3. Inicializáljuk nullára a vertexbuffereket, és gondoskodjunk a felszabadításukról!
4. Töltsük le a bunny.h file-t, majd include-oljuk a .cpp-nkben!
5. A bunny.h-ban deklarált függvények segítségével töltsük fel és rajzoljuk ki az első vertex buffert!
HRESULT Multi::onCreateDevice() { VERTEXFORMAT* vs = (VERTEXFORMAT*)get_bunny_buffer(); HRESULT hr; V( _device->CreateVertexBuffer(sizeof(VERTEXFORMAT) * get_vertex_count(), 0, FVF, D3DPOOL_MANAGED, &_vb_bunny, 0) ); void * vdata; V( _vb_bunny->Lock(0, sizeof(VERTEXFORMAT) * get_vertex_count(), &vdata, 0) ); CopyMemory(vdata, vs, sizeof(VERTEXFORMAT) * get_vertex_count()); _vb_bunny->Unlock(); delete [] vs; return D3D_OK; }
void Multi::onFrameRender( double fTime, float fElapsedTime ) { _device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(65, 105, 225), 1, 0); if ( SUCCEEDED(_device->BeginScene()) ) { _device->SetFVF(FVF); D3DXMATRIX r, t; D3DXMatrixRotationZ(&r, 3.1415f); D3DXMatrixTranslation(&t, 0, -1, 5); r *= t; _device->SetTransform(D3DTS_WORLD, &r); _device->SetStreamSource(0, _vb_bunny, 0, sizeof(VERTEXFORMAT)); _device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, get_tri_count()); _device->EndScene(); } }
A modellünk még fekete a megvilágítás miatt, ezért azt kapcsoljuk ki az onResetDevice-ban, és ugyan itt állítsuk be a projektív transzformációt is:
HRESULT Multi::onResetDevice() { _device->SetRenderState(D3DRS_LIGHTING, FALSE); D3DXMATRIX pers; D3DXMatrixPerspectiveFovLH(&pers, 3.1415f*45/180, (float)getWidth()/getHeight(), 0.1f, 10); _device->SetTransform(D3DTS_PROJECTION, &pers); return D3D_OK; }
Tegyük lehetővé, hogy a modellt billentyűzetről lehessen forgatni!
1. Adjunk új adattagokat az osztályhoz! Legyen pitch az X és yaw az Y tengely körüli forgatás (mindkettő float típusú). Ezeket nullázzuk is a konstruktorban.
2. Adjuk hozzá az osztályhoz a keyboardProc eseménykezelőt, majd írjuk meg a .cpp-ben:
void Multi::keyboardProc( UINT nChar, bool bKeyDown, bool bAltDown ) { switch (nChar) { case VK_LEFT: yaw += 0.05f; break; case VK_RIGHT: yaw -= 0.05f; break; case VK_UP: pitch += 0.05f; break; case VK_DOWN: pitch -= 0.05f; break; } }
Ezek segítségével adjunk meg egy újabb transzformációt a rajzolás előtt:
D3DXMATRIX r, t, ypr; D3DXMatrixRotationZ(&r, 3.1415f); D3DXMatrixTranslation(&t, 0, -1, 5); D3DXMatrixRotationYawPitchRoll(&ypr, yaw, pitch, 0); r *= t * ypr; _device->SetTransform(D3DTS_WORLD, &r);
Ez még az eltolási mátrix miatt nem úgy néz mozog, mint szeretnénk, ezért adjunk meg egy nézeti transzformációt is, de ehhez használjuk az egér kezelést!
3. Új float adattagok: lookX, lookY. Konstruktorban nullázzuk őket!
4. Új segédfüggvény:
void Multi::setView(float atX, float atY, float atZ) { D3DXMATRIX look; D3DXVECTOR3 eye = D3DXVECTOR3(0,0,-4); D3DXVECTOR3 at = D3DXVECTOR3(atX, atY, atZ); D3DXVECTOR3 up = D3DXVECTOR3(0,1,0); D3DXMatrixLookAtLH(&look, &eye, &at, &up); _device->SetTransform(D3DTS_VIEW, &look); }
Osztályleírásban deklarálni kell!
5. Írjuk meg az egérmozgás eseménykezelőjét!
void Multi::mouseProc(bool bLeftButtonDown, bool bRightButtonDown, bool bMiddleButtonDown, bool bSideButton1Down, bool bSideButton2Down, INT nMouseWheelDelta, INT xPos, INT yPos ) { static int oldX, oldY; static bool pressed = false; bool changed = false; if (bLeftButtonDown) { if (!pressed) pressed = true; else { lookX += 2.0f*(oldX-xPos)/this->getHeight(); lookY += -2.0f*(oldY-yPos)/this->getWidth(); changed = true; } oldX = xPos; oldY = yPos; } else if (pressed) { pressed = false; changed = true; } if (changed) setView(lookX,lookY,0); }
6. Hogy már a program indulásakor helyes képek kapjunk, hívjuk meg a setView(lookX, lookY, 0)-t az onResetDevice-ban!
7. Az onFrameRender már nincs szükség az Z-tengelyes eltolásra.
Hogy lesz nyuszi a háromszögekből? A következő állapot beállítással meg lehet nézni:
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
Önálló feladatok
1. Egy VERTEXFORMAT tömbbe add meg egy kockát alkotó háromszögek adatai, majd ezt töltsd be a második vertexbufferbe, és rajzold ki!
Az egyes lapok legyenek különböző színűek, és a kocka D3DCULL_NONE beállítás nélkül is jelenjen meg helyesen!
2. A kockát a nyúltól függetlenül lehessen forgatni WASD-vel!
3. Rajzolj ki több kockát és nyulat a meglévő vertexbufferek segítségével!