DirectX (23.)

A je tu dalÜφ lekce o Direct3D, ve kterΘ se budeme podrobn∞ji v∞novat n∞kter²m detail∙m, kterΘ jsme minule nestihli. Nap°φklad rozÜφ°φme t°φdu XMesh. V druhΘ Φßsti lekce se podφvßme na sv∞tla.

23.1 Materißly

Na zaΦßtku lekce se zmφnφm o materißlech. Podrobn∞ji se jimi budeme zab²vat v poslednφ Φßsti kapitoly, nynφ si jen povφme, co to vlastn∞ je! Materißlem urΦφme, jakΘ sv∞telnΘ slo₧ky se odrß₧ejφ od povrchu a jakΘ naopak povrch pohlcuje. Pozd∞ji se dovφme, ₧e mßme n∞kolik typ∙ osv∞tlenφ scΘny: ambient, diffuse, specular a emissive. V materißlu urΦφme, jak urΦit² povrch reaguje na vÜechny tyto typy sv∞tla. Zatφm se netrapte tφm, ₧e nevφte, jak si kter² typ osv∞tlenφ p°edstavit. To se dozvφte v Φßsti o sv∞tlech. M∙₧eme nap°φklad nastavit, ₧e ambient osv∞tlenφ se od danΘho povrchu ΦßsteΦn∞ odrß₧φ a t°eba jen modrß slo₧ka tohoto sv∞tla je pohlcena. Pak se tento objekt zdß b²t ₧lut², proto₧e do vaÜeho oka dopadajφ pouze ΦervenΘ a zelenΘ slo₧ky sv∞tla. Samoz°ejm∞ takΘ zßle₧φ, jakou barvu mß dopadajφcφ sv∞tlo a jakou barvu mß objekt samotn² (textura, barva vertexu).

V Direct3D je materißl reprezentovßn datovou strukturou D3DMATERIAL8:

typedef struct _D3DMATERIAL8
{
    D3DCOLORVALUE Diffuse;
    D3DCOLORVALUE Ambient;
    D3DCOLORVALUE Specular;
    D3DCOLORVALUE Emissive;
    float Power;
} D3DMATERIAL8;

D3DCOLORVALUE je dalÜφ struktura, kterß obsahuje slo₧ky ΦervenΘ, modrΘ, zelenΘ a alpha kanßlu. Tyto hodnoty nastavujeme v rozmezφ od 0.0 do 1.0, kde 0.0 je Φernß a 1.0 bφlß. Hodnotami, kterΘ jsou vyÜÜφ ne₧ 1.0 m∙₧ete zp∙sobit dalÜφ efekty "zv²ÜenΘho" odrazu nebo naopak zßporn²mi hodnotami vytvo°φte "Φernou dφru".

Aby se materißl pou₧il, musφte zavolat metodu za°φzenφ SetMaterial() s ukazatelem na materißl. Materißly se nechovajφ jako zdroje, tudφ₧ je nemusφte uvol≥ovat p°i ztrßt∞ za°φzenφ, ale po resetu za°φzenφ je t°eba op∞tovn∞ nastavit poslednφ materißl.

Nev∞domky jsme tuto strukturu pou₧ili v minulΘ lekci, proto₧e jsme pot°ebovali nastavit n∞jak² zßkladnφ materißl pro vÜechny objekty ve scΘn∞. V dalÜφ Φßsti zjistφte, ₧e meshe majφ pro ka₧dou svou pod-Φßst jin² materißl.

P°φklad pou₧itφ materißlu z minulΘ lekce:

D3DMATERIAL8 mtrl;
ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) );
mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;
mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
m_lpD3DDevice->SetMaterial(&mtrl);

23.2. T°φda XMesh

Nejprve trochu rozÜφ°φme tuto t°φdu z minulΘ lekce. ╪ekli jsme si, ₧e mesh se m∙₧e (a taky v∞tÜinou sklßdß) z vφce Φßstφ. Ka₧dß tato Φßst mß sv∙j materißl a texturu. Informace o materißlech a texturßch jsou ulo₧eny p°φmo v souboru .X, ze kterΘho model naΦφtßme. Nynφ trochu upravφme t°φdu XMesh, abychom zφskali informace o texturßch a materißlech meshe. Za prvΘ musφme p°idat pole textur a materißlu, dßle poΦet materißl∙:

// number of materials
DWORD m_dwNumMat;
// arrays of textures and materials
XTexture *m_pTextures;
D3DMATERIAL8 *m_pMaterials;

Upravφme metodu LoadMeshFromFile(). P°idßme t°etφ parametr typu ukazatel na XResourceManager:

int LoadMeshFromFile(LPCSTR szFileName, LPDIRECT3DDEVICE8 lpDevice, XResourceManager * pResMan);

A upravφme implementaci metody:

if(D3D_OK == D3DXLoadMeshFromX(m_szFilePath, 0, lpDevice, NULL, &pD3DXMtrlBuffer, &m_dwNumMat, &m_lpMesh))
{
    TRACE("Mesh '%s' was loaded.", szFileName);
    // get material buffer
    D3DXMATERIAL* d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
    // create arrays of materials and textures
    m_pTextures = new XTexture[m_dwNumMat];
    m_pMaterials = new D3DMATERIAL8[m_dwNumMat];
    //
    // get materials and load textures
    for(int i = 0; i < (int)m_dwNumMat; i++)
    {
        m_pMaterials[i] = d3dxMaterials[i].MatD3D;
        m_pMaterials[i].Ambient = m_pMaterials[i].Diffuse;

        if(d3dxMaterials[i].pTextureFilename)
        {
            m_pTextures[i].LoadTextureFromFile(d3dxMaterials[i].pTextureFilename, lpDevice);
            pResMan->AddTexture(&m_pTextures[i]);
        }
    }
    pD3DXMtrlBuffer->Release();
}

Nynφ si vysv∞tlφme, co vlastn∞ provßdφme. Volßnφm funkce D3DXLoadMeshFromX() nynφ navφc zφskßme napln∞n² buffer ID3DXBuffer, ve kterΘm jsou ulo₧eny informace o materißlech a jmΘna textur. Ty zφskßme pomocφ objektu D3DXMATERIAL. Ukazatel na tuto strukturu zφskßme p°φmo z ID3DXBufferu. Dßle vytvo°φme pot°ebn² poΦet materißl∙ a textur. Nakonec vÜe v cyklu zinicializujeme. Nesmφme zapomenout p°idat vytvo°enΘ textury do mana₧eru zdroj∙ (to je ten t°etφ parametr metody). Zde je d∙le₧itΘ si uv∞domit, ₧e ne vÜechny materißly majφ k sob∞ p°φsluÜnou texturu. V souboru .x m∙₧e b²t ulo₧ena informace o materißlu, ale samotn² objekt je bez textury. V tomto p°φpad∞ je °et∞zec obsahujφcφ jmΘno textury prßzdn² (null).

Dßle upravφme destruktor t°φdy XMesh tak, aby se zruÜily vÜechny materißly a textury:

XMesh::~XMesh(void)
{
    Release();
    m_lpDevice = NULL;
    SAFE_DELETE_ARRAY(m_pMaterials);
    SAFE_DELETE_ARRAY(m_pTextures);
}

Nynφ m∙₧eme mesh vykreslit. Vytvo°φme metodu Draw(). Minule jsme pro ka₧d² mesh m∞li pomocnou prom∞nnou, kde jsme uchovßvali informaci o viditelnosti meshe ve scΘn∞. Nynφ tuto prom∞nnou m_bVisible p°esuneme do samotnΘ t°φdy XMesh.

int XMesh::Draw()
{
    if(m_lpDevice && m_bVisible && m_lpMesh)
    {
        if(m_meshType == CUSTOM)
        {
            for(int i = 0; i < (int)m_dwNumMat; i++)
            {
                m_lpDevice->SetMaterial(&m_pMaterials[i]);
                m_lpDevice->SetTexture(0, m_pTextures[i].GetTexture());
                m_lpMesh->DrawSubset(i);
            }
        }
        else
        {
            // set default material
            D3DMATERIAL8 mtrl;
            ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) );
            mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
            mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
            mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;
            mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
            m_lpDevice->SetMaterial(&mtrl);

            m_lpDevice->SetTexture(0, NULL);
            m_lpMesh->DrawSubset(0);
        }
        return 0;
    }
    return -1;
}

V tΘto metod∞ nejd°φve zkontrolujeme sprßvnou inicializaci a viditelnost objektu. Dßle metodu rozd∞lφme na dva p°φpady. P°eddefinovanΘ objekty majφ pouze jednu Φßst a nenφ definovßna textura ani materißl (mesh dokonce neobsahuje texturovΘ sou°adnice). Proto je t°eba nastavit standardnφ materißl a texturu "vynulovat". Pokud je mesh nahrßn ze souboru, m∙₧e obsahovat vφce Φßstφ a ke ka₧dΘ se zvlßÜ¥ nastavφ materißl a textura.

K prom∞nnΘ m_bVisible navφc p°ipφÜeme dvojici inline metod, pro nastavenφ a zφskßnφ stavu:

BOOL IsVisible() { return m_bVisible; }
void Visible(BOOL bVis = TRUE) { m_bVisible = bVis; }

V dalÜφ Φßsti si povφme vφce o sv∞tlech a implementujeme podporu sv∞tel do naÜeho "enginu".


23.3. Sv∞tla v Direct3D

U₧ jsme si pov∞d∞li k Φemu slou₧φ materißl. Materißlem nastavujeme vlastnosti povrchu. V tΘto Φßsti si povφme o osv∞tlenφ scΘny v Direct3D. RozliÜujeme dva zßkladnφ zdroje sv∞tla: tzv. okolnφ (ambient) a sm∞rovΘ (directional) osv∞tlenφ. Okolnφm osv∞tlenφm nastavφme celkovou sv∞tlost scΘny. Toto sv∞tlo nemß ₧ßdnou pozici ani sm∞r - je vÜudyp°φtomnΘ. Jedinou vlastnostφ tohoto sv∞tla je barva. Ambient sv∞tlo nastavφme pomocφ metody za°φzenφ SetRenderState() s parametrem D3DRS_AMBIENT a barvou sv∞tla ve formßtu RGBA. Zde m∙₧ete pou₧it makro D3DCOLOR_RGBA(r, g, b, a), kde jednotlivΘ parametry jsou v rozmezφ 0 - 255. Nap°φklad bφlΘ sv∞tlo nastavφme pomocφ p°φkazu:

m_lpD3DDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_RGBA(255, 255, 255, 255));

Tφmto p°φkazem ovÜem celou scΘnu "p°esv∞tlφte", tak₧e uvidφte vÜechny objekty bφlΘ! Aby sv∞tla zaΦala fungovat, musφte zapnout osv∞tlenφ Direct3D, navφc je t°eba mφt nastaven² n∞jak² materißl. V naÜem p°φkladu nastavujeme standardnφ materißl pro p°eddefinovanΘ meshe a pro tygra nastavujeme vlastnφ materißl. Aby osv∞tlenφ sprßvn∞ fungovalo, musφ mφt ten kter² objekt sprßvn∞ nastavenΘ normßlovΘ vektory - tyto vektory jsou v problematice sv∞tel klφΦovΘ! Normßlov² vektor je vektor kolm² na plochu, nap°φklad:

kde N je prßv∞ normßlov² vektor, podle kterΘho se nßsledn∞ spoΦφtß osv∞tlenφ. Odra₧enΘ sv∞tlo je dßno ·hlem, kter² svφrß paprsek sv∞tla a normßlov² vektor. Sv∞tlo zapneme p°φkazem:

m_lpD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

V p°φpad∞ tygra je t°eba sv∞tlo zase vypnout, proto₧e mesh tygra nemß definovanΘ normßlovΘ vektory a Direct3D nemß podle Φeho spoΦφtat sv∞tlo. V p°φkladu si ukß₧eme mesh, kter² normßlovΘ vektory definovanΘ mß. Zde pak budeme moci pou₧φt osv∞tlenφ Direct3D a mesh bude stφnovan². Samotn²m ambient sv∞tlem vÜak stφnovßnφ neud∞lßme, proto₧e toto sv∞tlo p∙sobφ na vÜechny plochu meshe stejn∞.

23.3.1. Sm∞rovß sv∞tla

V Direct3D je n∞kolik typ∙ t∞chto sv∞tel, ka₧dΘ mß rozdφlnΘ vlastnosti a pou₧itφ. SpoleΦnΘ pro n∞ je ovÜem struktura D3DLIGHT8, kterß p°edstavuje samotnΘ sv∞tlo. M∙₧eme pou₧φt tyto typy:

BodovΘ sv∞tlo - point light

Toto sv∞tlo mß pozici a barvu, ale svφtφ vÜemi sm∞ry stejn∞ intenzivn∞. P°φkladem m∙₧e b²t t°eba ₧ßrovka. Dßle je mo₧nΘ nastavit parametr Range, kter² p°edstavuje dosah paprsk∙. Za touto vzdßlenostφ ji₧ sv∞tlo nebude ovliv≥ovat objekty.

PloÜnΘ sv∞tlo - directional light

PloÜnΘ sv∞tlo mß sm∞r a barvu, nikoliv pozici. Toto sv∞tlo by se dalo p°irovnat ke sv∞tlu Slunce! Paprsky tohoto sv∞tla jsou tudφ₧ rovnob∞₧nΘ, jako kdyby zdroj sv∞tla byl v nekoneΦnu. Toto sv∞tlo takΘ pou₧φvßme v naÜem jednoduchΘm p°φkladu, kde takto osv∞tlujeme rovnom∞rn∞ celou scΘnu. U tohoto sv∞tla parametr Range nenastavujeme. Paprsky majφ stßle stejnou intenzitu.

Sm∞rovΘ sv∞tlo - spot light

Poslednφ typ je spojenφ obou p°edchozφch sv∞tel dohromady, proto₧e mß sm∞r, pozici a samoz°ejm∞ i barvu. Toto sv∞tlo osv∞tluje tzv. vnit°nφ ku₧el rovnom∞rn∞. Vn∞jÜφ ku₧el je osv∞tlen nerovnom∞rn∞, tato nerovnom∞rnost je urΦena parametrem Falloff. Tento parametr v∞tÜino nastavujeme na hodnotu 1.0 pro rovnom∞rnΘ rozlo₧enφ sv∞tla mezi vnit°nφm a vn∞jÜφm ku₧elem. Proto₧e toto sv∞tlo je docela slo₧itΘ, ukß₧eme si vÜechno na obrßzku:

Velikost vnit°nφho a vn∞jÜφho ku₧ele je definovßna dv∞ma ·hly Phi a Theta, kterΘ zadßvßme v radißnech.

Nakonec si jeÜt∞ povφme o parametrech Attenuation0, Attenuation1 a Attenuation2. Pomocφ t∞chto parametr∙ °φdφme intenzitu sv∞tla v prostoru - definujeme vlastn∞ pr∙b∞h klesajφcφ intenzity s rostoucφ vzdßlenosti od zdroje ke vzdßlenosti urΦenΘ parametrem Range (z toho vypl²vß, ₧e tyto parametry op∞t nemajφ v²znam pro ploÜnΘ sv∞tla). Tyto hodnotu mohou b²t v rozsahu od 0 do nekoneΦna, p°iΦem₧ vÜechny najednou by nem∞ly b²t 0. Standardn∞ nastavujeme Attenuation0 a Attenuation2 na 0 a Attenuation1 na 1.0. Pak intenzita klesß nep°φmo ·m∞rn∞ se vzdßlenostφ od zdroje.

Nynφ se podφvejme na strukturu D3DLIGHT8:

typedef struct _D3DLIGHT8 {
    D3DLIGHTTYPE Type;
    D3DCOLORVALUE Diffuse;
    D3DCOLORVALUE Specular;
    D3DCOLORVALUE Ambient;
    D3DVECTOR Position;
    D3DVECTOR Direction;
    float Range;
    float Falloff;
    float Attenuation0;
    float Attenuation1;
    float Attenuation2;
    float Theta;
    float Phi;
} D3DLIGHT8;

VÜechny parametry jsme probrali v²Üe. Ka₧dΘ sv∞tlo mß n∞kolik "sv∞teln²ch" slo₧ek: diffuse - rozpt²lenΘ sv∞tlo, ambient - sv∞tlo okolφ a specular - odrazy. VÜechny tyto slo₧ky jsou reprezentovßny strukturou D3DCOLORVALUE, se kterou jsme se ji₧ setkali v prvnφ Φßsti a i zde platφ stejnΘ pravidla pro hodnoty jednotliv²ch barevn²ch slo₧ek. Typ sv∞tla m∙₧e nab²vat t∞chto hodnot: D3DLIGHT_POINT pro bodovΘ sv∞tlo, D3DLIGHT_SPOT pro sm∞rovΘ a D3DLIGHT_DIRECTIONAL pro ploÜnΘ.

23.3.2. P°φklad

Nynφ p°idßme podporu sv∞tel do naÜeho p°φkladu. Nejprve je t°eba otestovat, kolik m∙₧eme mφt maximßln∞ aktivnφch sv∞tel. Ve struktu°e D3DCAPS8 je atribut MaxActiveLights. Tak₧e nejprve ve funkci Init() zavolßme metodu za°φzenφ GetCaps() a zφskßme pot°ebn² parametr, kter² ulo₧φme ve t°φd∞ XDisplay. PotΘ sledujeme poΦet zapnut²ch sv∞tel a tento poΦet omezφme v²Üe uvedenou konstantou (dneÜnφ karty majφ v∞tÜinou 8 sv∞tel). Maximßlnφ poΦet sv∞tel si ulo₧φme nap°φklad do prom∞nnΘ m_iMaxLights.

P°idßme nßsledujφcφ dv∞ metody:

int XDisplay::EnableLight(int iIndex, BOOL bEnable)
{
    if(m_lpD3DDevice && (iIndex >= 0 && iIndex < m_iMaxLights))
    {
        return m_lpD3DDevice->LightEnable(iIndex, bEnable);
    }
    return -1;
}

int XDisplay::SetLight(int iIndex, D3DLIGHT8 * pLight)
{
    if(m_lpD3DDevice && pLight && (iIndex >= 0 && iIndex < m_iMaxLights))
    {
        return m_lpD3DDevice->SetLight(iIndex, pLight);
    }
    return -1;
}

Metody LightEnable() a SetLight() jsme volali ji₧ v minulΘ lekci. Ve scΘn∞ m∙₧ete mφt aktivnφch jen n∞kolik mßlo sv∞tel a to s jak²m prßv∞ pracujete urΦuje prvnφ parametr t∞chto metod.

Na zßv∞r lekce jeÜt∞ vÜechny novΘ funkce vyzkouÜφme v programu Tester.exe. P°idßme dalÜφ mesh a dv∞ sv∞tla. Tento mesh budeme nahrßvat ze souboru .X a koneΦn∞ bude mφt definovanΘ normßlovΘ vertexy, tak₧e na n∞m budou vid∞t sv∞telnΘ efekty jako na p°eddefinovan²ch objektech. Prvnφ sv∞tlo bude jakΘsi slunce, kterΘ svφtφ stßle v jednom sm∞ru modrou barvou. Toto sv∞tlo bude ploÜnΘ. Dßle vytvo°φme jedno bodovΘ sv∞tlo, kterΘ budou obφhat kolem objekt∙ ve scΘn∞.

P°idejme tyto objekty:

XMesh g_Airplane;

D3DLIGHT8 g_PointLight;
D3DLIGHT8 g_Sun;

Dßle upravφme funkci WinMain():

// inicializace Direct3D
g_theDisplay.Init(g_hWnd);

// preddefinovane objekty
g_Sphere.CreateSphere(2.0f, 48, 48, g_theDisplay.GetDevice());
g_Box.CreateBox(1.0f, 1.0f, 6.0f, g_theDisplay.GetDevice());
g_Cylinder.CreateCylinder(1.5f, 2.5f, 4.0f, 24, 8, g_theDisplay.GetDevice());
g_Torus.CreateTorus(1.0f, 2.0f, 64, 64, g_theDisplay.GetDevice());
g_Teapot.CreateTeapot(g_theDisplay.GetDevice());
// model tygra
g_Tiger.LoadMeshFromFile("tiger.x", g_theDisplay.GetDevice(),
g_theDisplay.GetResourceManager());
g_Airplane.LoadMeshFromFile("airplane 2.x", g_theDisplay.GetDevice(), g_theDisplay.GetResourceManager());

// zaregistrovani vsech zdroju
g_theDisplay.GetResourceManager()->AddMesh(&g_Tiger);
g_theDisplay.GetResourceManager()->AddMesh(&g_Sphere);
g_theDisplay.GetResourceManager()->AddMesh(&g_Box);
g_theDisplay.GetResourceManager()->AddMesh(&g_Cylinder);
g_theDisplay.GetResourceManager()->AddMesh(&g_Teapot);
g_theDisplay.GetResourceManager()->AddMesh(&g_Torus);
g_theDisplay.GetResourceManager()->AddMesh(&g_Airplane);

// torus is visible by default
g_Torus.Visible();

// zde vytvorime slunicko
ZeroMemory( &g_Sun, sizeof(D3DLIGHT8) );
g_Sun.Type = D3DLIGHT_DIRECTIONAL;
g_Sun.Direction.x = -1.0f;
g_Sun.Direction.y = 0.0f;
g_Sun.Direction.z = -1.0f;
g_Sun.Diffuse.r = 0.0f;
g_Sun.Diffuse.g = 0.0f;
g_Sun.Diffuse.b = 0.7f;
g_Sun.Ambient.r = 0.4f;
g_Sun.Ambient.g = 0.4f;
g_Sun.Ambient.b = 0.4f;
g_Sun.Range = 1000.0f;
g_theDisplay.SetLight(0, &g_Sun);
g_theDisplay.EnableLight(0, TRUE);

// dalsi svetlo
ZeroMemory( &g_PointLight, sizeof(D3DLIGHT8) );
g_PointLight.Type = D3DLIGHT_POINT;
g_PointLight.Position.x = 0.0f;
g_PointLight.Position.y = 0.0f;
g_PointLight.Position.z = 0.0f;
g_PointLight.Diffuse.r = 1.0f;
g_PointLight.Diffuse.g = 1.0f;
g_PointLight.Diffuse.b = 0.0f;
g_PointLight.Range = 1000.0f;
g_PointLight.Attenuation1 = 1.0f;

Nejd°φve vytvo°φme mesh ze souboru airplane 2.x, dßle tento mesh vlo₧φme do sprßvce zdroj∙ a nastavφme, ₧e implicitn∞ bude viditeln² pouze prstenec (torus). V dalÜφ Φßsti vytvo°φme a nastavφme dv∞ sv∞tla. U ploÜnΘho sv∞tla (Slunce) nastavφme pouze sm∞r a barvu. Po tΘ volßme dvojici metod SetLight() a EnableLight(), abychom toto sv∞tlo aktivovali. U bodovΘho sv∞tla nastavφme poΦßteΦnφ pozici, barvu, dosah a rozlo₧enφ intenzity. Samotnß aktivace spolu s vypoΦtenφm novΘ pozice je provedena a₧ ve funkci UpdateFrame(). Po ztrßt∞ za°φzenφ se vÜechno nastavenφ ztratφ, tak₧e i sv∞tla musφme znovu nastavit a aktivovat. Proto p°idejme funkci RestoreUserObjects(), kterß obnovφ u₧ivatelskΘ objekty. Tuto funkci budeme volat v₧dy po funkci RestoreDisplay().

Upravφme proceduru okna tak, aby Üel zobrazit i nßÜ nov² mesh:

case WM_KEYUP:
    switch( wParam )
    {
        case VK_F8:
            g_theDisplay.RestoreDisplay();

            RestoreUserObjects();
            break;
       
case VK_F1:
            g_Sphere.Visible(!g_Sphere.IsVisible());
            break;
        case VK_F2:
            g_Torus.Visible(!g_Torus.IsVisible());
            break;
        case VK_F3:
            g_Box.Visible(!g_Box.IsVisible());
            break;
        case VK_F4:
            g_Cylinder.Visible(!g_Cylinder.IsVisible());
            break;
        case VK_F5:
            g_Teapot.Visible(!g_Teapot.IsVisible());
            break;
        case VK_F6:
            g_Tiger.Visible(!g_Tiger.IsVisible());
            break;

        case VK_F7:
            g_Airplane.Visible(!g_Airplane.IsVisible());
            break;
      
 case VK_ESCAPE:
            PostQuitMessage(0);
            break;
        }
    break;

Zde takΘ nezapome≥te zavolat ji₧ zmφn∞nou funkci na obnovu sv∞tla. Nakonec upravφme funkci UpdateFrame(), kterß se oproti minulΘ verzi znaΦn∞ zjednoduÜφ:

void UpdateFrame()
{
    // svetlo se bude pohybovat po kruznici
    g_PointLight.Position.x = 0.0f;
    g_PointLight.Position.y = 4.0f * sin(double(GetTickCount())/300.0f);
    g_PointLight.Position.z = 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();
    g_theDisplay.GetDevice()->EndScene();
    if(D3DERR_DEVICENOTRESET == g_theDisplay.Present())
    {
        RestoreUserObjects();
    }
}

Nejprve spoΦφtßme novou pozici bodovΘho sv∞tla (zde vyu₧ijeme trochu matematiky ze st°ednφ Ükoly), dßle toto sv∞tlo nastavφme a aktivujeme. DalÜφ Φßst vykresluje postupn∞ vÜechny objekty. Mesh se samoz°ejm∞ nevykreslφ, pokud nenφ viditeln². U tygra nesmφme zapomenout vypnout osv∞tlenφ. Nakonec musφme u metody Present() sledovat nßvratovou hodnotu D3DERR_DEVICENOTRESET, kterou metoda vracφ po obnovenφ zdroj∙ a je to vhodnß chvφle k op∞tovnΘmu nastavenφ naÜeho slunce.

FunkΦnφ p°φklad si m∙₧ete jako obvykle stßhnout v sekci Downloads.

23.4. Zßv∞r

V dneÜnφ kratÜφ lekci jste se dov∞d∞li n∞co mßlo o sv∞tlech a p°idali jsme pßr nov²ch funkcφ do naÜeho projektu. P°φÜt∞ si budeme hrßt s transformacemi jednotliv²ch objekt∙.

T∞Üφm se p°φÜt∞ nashledanou.

Ji°φ Formßnek