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!