Navigálás a 3D-s térben

0. Folytassuk az előzőekben elkezdett programot!

Eddig egy semmi jele nincs annak a programunkban, hogy a háromszög valóban térben van.

Bővítsük a programot, hogy a háromszög magától forogjon az Y-tengely körül!

1. Adjunk hozzá egy onFrameMove eseménykezelőt az osztályunkhoz!

2. Ebben hozzunk létre egy D3DXMATRIX és a D3DXMatrixRotationY függvény segítségével készítsünk belőle forgatási mátrixot! A kész transzformációs mátrixot a IDirect3DDevice9::SetTransform függvénnyel adjuk át DirectX-nek!

void Triangle::onFrameMove( double fTime, float fElapsedTime )
{
    static const float rotSpd = 0.5f;
    
    D3DXMATRIX rot;
    D3DXMatrixRotationY(&rot, (float)fTime*rotSpd);
    _device->SetTransform(D3DTS_VIEW, &rot);
}

* Pár furcsaság:

A) Miért csak fél háromszög látszik?

A "világ" a Z-tengely mentén csak 0-tól 1-ig "tart". Ami ezen kívül kerül, azt levágja a DirectX.

1. megoldási ötlet: Hozzuk létre hátrébb a háromszöget! Módosítsuk a onCreateDevice-ban a létrehozást!

    vs[0].v = D3DXVECTOR3(0,0.5f,0.5f);
    vs[1].v = D3DXVECTOR3( 0.5f,-0.5f,0.5f);
    vs[2].v = D3DXVECTOR3(-0.5f,-0.5f,0.5f);

Probléma: Így nem a tengelye körül forog a háromszög. (És még mindíg kimászik!)

2. megoldási ötlet: Maradjon mégis az eredeti helyén a háromszög, forgassuk meg, és utána toljuk hátrébb! Ehhez kell egy új mátrix, és a kettő szorzatát kell átadni a DirectX-nek.

void Triangle::onFrameMove( double fTime, float fElapsedTime )
{
    static const float rotSpd = 0.5f;
    
    D3DXMATRIX rot, trans;
    D3DXMatrixRotationY(&rot, (float)fTime*rotSpd);
    D3DXMatrixTranslation(&trans, 0, 0, 0.5f);
    rot *= trans;
    _device->SetTransform(D3DTS_VIEW, &rot);
}

Megjegyzések:

B) Miért tűnik el néha teljesen?

A hátlapeldobás miatt, amikor a háromszög "hátulról" látszik (amikor a csúcsainak a sorrendje az óra járásával ellentétes), akkor a rendszer nem rajzolja ki. Ez állítható a D3DRS_CULLMODE állapot segítségével.

_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

* Rendben, hogy most belefér a háromszög a "világba", de akkor nem is használhatók a [0, 1]-en kívüleső pontok???

De igen, ha valamilyen vetítést alkalmazunk.

1. Kapcsoljuk ki a forgatást most egy darabig! (Pl. kommentezzük ki a forgatás kódját)

2. Rajzoljuk ki kétszer a hátomszöget, az egyiket mélyebbre, mint a másikat!

void Triangle::onFrameRender( double fTime, float fElapsedTime )
{
    D3DXMATRIX m;
    _device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                    D3DCOLOR_XRGB(107, 63, 160), 1, 0);

    if ( SUCCEEDED(_device->BeginScene()) )
    {
        _device->SetStreamSource(0, _vbuffer, 0, sizeof(VERTEXFORMAT));
        _device->SetFVF(FVF);

        D3DXMatrixTranslation(&m, -0.5f, 0, 0);
        _device->SetTransform(D3DTS_WORLD, &m);
        _device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

        D3DXMatrixTranslation(&m, 0.5f, 0, 0.5f);
        _device->SetTransform(D3DTS_WORLD, &m);
        _device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

        _device->EndScene();
    }
}

Futassuk a programot!

Hiába van az egyik háromszög hátrébb, mint a másik, mind kettő ugyanakkora.

Ez néha jó lehet (pl műszaki rajzoknál), de általában nem ezt szeretnénk, hanem perspektívikus ábrázolást.

3. Hozzunk létre egy perspektívikus transzformációt a onResetDevice-ban és adjuk át a DirectX-nek!

    D3DXMATRIX pers;

    D3DXMatrixPerspectiveFovLH(&pers, 3.1415f*45/180,
                               (float)getWidth()/getHeight(), 0.1f, 10);
    _device->SetTransform(D3DTS_PROJECTION, &pers);

Valami történt, de egyenlőre nem látszik, hogy mi is.

4. Vigyük hátrébb a nézőpontunkat! Ehhez ismét bővítsük a onResetDevice-ot!

    D3DXMATRIX look;
    D3DXVECTOR3 eye = D3DXVECTOR3(0,0,-2);
    D3DXVECTOR3 at = D3DXVECTOR3(0,0,0);
    D3DXVECTOR3 up = D3DXVECTOR3(0,1,0);

    D3DXMatrixLookAtLH(&look, &eye, &at, &up);
    _device->SetTransform(D3DTS_VIEW, &look);

Megjegyzések: