teppo soininen & antti puhakka - tuni.fipeliohj/kalvot-rajapinnat2006.pdf · 2007. 8. 30. ·...

32
Peliohjelmointi: Peliohjelmointirajapinnoista Teppo Soininen & Antti Puhakka Lähteet: www.opengl.org, OpenGL-spesifikaatio, Tietokonegrafiikka –luentomoniste, MSDN, Introduction to 3D Game Programming with DirectX 9.0

Upload: others

Post on 28-Jan-2021

1 views

Category:

Documents


0 download

TRANSCRIPT

  • Peliohjelmointi:

    Peliohjelmointirajapinnoista Teppo Soininen & Antti Puhakka

    Lähteet: www.opengl.org, OpenGL-spesifikaatio,

    Tietokonegrafiikka –luentomoniste, MSDN, Introduction to 3D

    Game Programming with DirectX 9.0

  • 2

    Open Graphics Library • Open Graphics Library (OpenGL) sai alkunsa 1992 SGI:n

    esittelemästä 3D rajapinnasta nimeltä IRIS GL

    • OpenGL oli alkuaikoina tähdätty ammattikäyttöön

    tehovaatimustensa takia − Windows NT 4.0:ssa oli OpenGL jo mukana (muistanette screensaverit

    joissa pyöri esim. kellonaika?)

    − Grafiikkaraudan kehittyessä myös halvemmat viihdekäyttöön tarkoitetut

    laitteet kykenivät vastaamaan OpenGL:n tehovaatimuksiin

    − Nykyään yksi eniten käytetty grafiikka API

  • 3

    • OpenGL on alustariippumaton grafiikka API − Sisältää ~150 funktiota

    − Ei sisällä mitään toiminnallisuutta ikkunoinin tai syötteidenkäsittelyn

    toteuttamiseksi

    • OpenGL:ää standardoi OpenGL Architecture Review Board

    (ARB) − 3DLabs, Apple, ATI, NVIDIA, IBM, Intel, SGI, Sun Microsystems, HP…

    • OpenGL rajapinta löytyy muutamalle eri kielelle (C/C++, ADA,

    Fortran ja Java)

    • OpenGL on käytännössä iso tilakone − Yli sata globaalia tilamuuttujaa (on/off)

  • 4

    OpenGL 1.1:n tilakone

  • 5

    • Ohjelmointinäkökulmasta OpenGL on kokoelma funktiota

    joiden avulla voi: − Määritellä geometrisia 2D/3D objekteja jotka koostuvat kymmenestä

    perusprimitiivistä

    GL_POINTS

    GL_LINES, GL_LINESTRIP, GL_LINE_LOOP

    GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN

    GL_QUADS, GL_QUAD_STRIP

    GL_POLYGON

    − Hallita määriteltyjen objektien piirtämistä frame bufferiin

    (transforamaatiot, valaistukset jne)

    glRotate(), glTranslate(), glScale()...

  • 6

    • OpenGL:stä ei löydy funktioita monimutkaisten primitiivien

    (pallot, kuutiot jne) piirtämiseen − Monimutkaisempien primitiivien piirtämiseen tehdään usein omat

    ”Mesh” –luokat

    − Jotkut korkeammantason rajapinnat tarjoavat apuja monimutkaisempien

    muotojen piirtämiseen (yleensä hyödyttömiä testaamisen ulkopuolella)

  • 7

    • OpenGL hoitaa piirtämisen moniosaisella pipelinella − Jokaisessa osassa tehdään yksi primitiivien esittämiseen tarvittava

    vaihe

    OpenGL Visualization Programming Pipeline

  • 8

    • OpenGL v1.5 (29.7.2003) − Yksi merkittävimmistä uudistuksista tässä versiossa olivat BufferObjektit

    • OpenGL v2.0 (7.9.2004) − OpenGL Shader Language vakiona (aikaisemmin erillinen)

    − Textuureja, joiden koko ei ole 2:n potenssissa, voidaan käyttää

    (virheettömästi!)

  • 9

    OpenGL tukikirjastot • SGI pitää kirjaa OpenGL:ään tehdyistä kirjastoista

    − ARB:n speksaamia kirjastoja n. 40

    − Muita kirjastoja tässä listassa on 300+

    • Käyttöjärjestelmien mukanan tulee kirjastoja ikkunoinnin

    hoitamiseen OpenGL:n kanssa − GLX (Unix)

    − WGL (Windows)

    − AGL (Apple)

  • 10

    • GL Utility Toolkit (GLUT) − Tarjoaa tominnallisuutta mm. ikkunoinnille, menuille, syöttölaitteille ja

    joillekkin perus muodoille (esim. pallo ja kuutio)

    − Soveltuu lähinnä pieniin OpenGL sovelluksiin

    − Rutiinit cross-platform ominaisuuksiensa takia liian hitaita todelliseen

    tehokäytöön (esim. peleihin) -> yleensä käytetetään käyttöjärjestelmän

    omia ikkunointi menetelmiä (GLX, WGL)

    − GLUT ei ole avointa lähdekoodia (Mark Kilgard omistaa oikeudet

    GLUT:iin)

    − Uusin versio 2.7

  • 11

    Simple Directmedia Layer (SDL) • Alustariippumaton grafiikka- ja multimediarajapinta, toimii

    Windowsissa, Linuxissa, Macissa, Solariksessa jne. jne.

    • Toiminnallisuutta mm. 2D- ja 3D-grafiikka, audio, syötelaitteet

    (hiiri, näppis ja joystick), tapahtumat, timerit, ...

    • SDL on ohut wrapperikerros, joka kutsuu esim. OpenGL-

    rutiineja

    • Kirjoitettu alunperin C:llä

    • Bindingeja löytyy ainakin seuraaville kielille: Ada, Eiffel, Java,

    Lua, ML, Perl, PHP, Pike, Python, Ruby

  • 12

    ⇒ Bindingit lisäävät käytännössä kuitenkin yhden kerroksen lisää

    raudan ja koodin väliin josta seuraa hidastaa koodia (ei usein

    käytetä tehoa vaativissa sovelluksissa, kuten peleissä)

    • Käytännössä SDL on (kuuleman mukaan) melko hyvä ja

    yksinkertainen

    • Suosiota lisännyt SDL:n open source -lisenssi − Uusin versio 1.2

  • 13

    Microsoft DirectX • DirectX-rajapinnan kehittäminen aloitettiin Microsoftilla joskus

    90-luvun alussa − OpenGL:n tehovaatimuksiin pystyttiin vastaamaan ainoastaan kallilla

    ammattilais laitteistoilla

    − Ideana kehittää viihdekäyttöön tarkoitettu vatine OpenGL:lle

    • Microsoftin aloitti DOS:in hyllyttämisen − Piti saada pelien kehittäjät siirtymään Windows ympäristöön

    − Tarvittiin rajapinta jonka avulla pelejä voitiin tehdä

  • 14

    • Pelikoodaajat olivat aluksi haluttomia siirtymään Windowsiin − DOS:ssa koodaajat pääsivät käsiksi suoraan "rautaan" ja tämän

    ansiosta saatiin aikaan tehokasta koodia

    − Windowsissa pääsi "rautaan" käsiksi vain WinAPI:n kautta (ei

    tehokasta)

    • Microsoft yritti korjata tämän ongelman WinG rajapinnan avulla − Rajapinta oli vaikea käyttää ja melko tehoton

    − Civilization ja Civilization 2 tiettävästi kuitenkin käyttivät WinG API:a

    • DirectX:n ensimmäisen verion kehittely aloitettiin 1994 ja sitä

    tuettiin Windows 95:stä eteenpäin

  • 15

    • DirectX:n ensimmäiset versiot olivat erittäin kokeellisia ja

    hankalia käyttää − OpenGL:n tehovaatimuksiin pystyttiin nyt vastaamaan kuluttajille

    sopivan hintaisilla 3D kalustolla ja tämä aiheutti vastarintaa; "miksi

    käyttää DX:ää kun hyvä vaihtoehto on jo olemassa?"

    • DirectX 5 oli ensimmäinen joka saavutti enemmän

    hyväksyntää

    • Nykyään DirectX:ää käytetään erittäin paljon viihteeseen

    suunnattujen sovellusten ohjelmoinnissa − Laitteistovalmistajat tukevat todella hyvin

    − XBox käyttää modifioitua DirectX 8 rajapintaa

    − Pelejä: FarCry, Doom 3

  • 16

    • Viimeisin versio on DirectX 9.0

    • DirectX on kokoelma ohjelmointirajapintoja pelien ja

    multimedian ohjelmointiin 1) DirectGraphics - 2D/3D piirtämiseen (yhdistetty DirectDraw ja Direct3D)

    2) DirectInput - syöttölaitteiden käsittelyyn (tuki mm. force feedbackille)

    3) DirectPlay - rajapinta verkkopelaamista varten

    o Ei saavuttanut koskaan erityisen suurta suosiota

    4) DirectSound - äänenkäsittelyyn (waveform)

    5) DirectMusic - pakatun musiikin toistamiseen (MIDI, DMusic Producer)

    o Toimii DirectSound:in päällä

    6) DirectShow - multimedian toistoon, tallentamiseen ja käsittelyyn (mm.

    videostreamit)

  • 17

    o Perustuu erilaisten ”filtterien” yhdistelemiseen

    7) DirectSetup - DirectX:n asentamisen hoitava API

    8) DirectX Media Objects - streamattavat mediaobjektit (enkooderit,

    dekooderit ja efektit)

    o Yksinkertaisempi käyttää kuin DirectShow

    • DirectX:stä käytetään eniten Direct3D:tä

    • Useimmat em. rajapinnoista aiotaan korvata Windows Vistan

    julkaisemisen jälkeen − XInput, XACT, Media Foundation... − Lisää tukea suojatulle sisällölle jne.

  • 18

    Direct3D • Direct3D toiminta perustuu Hardware Abstraction Layeriin

    (HAL) − Grafiikkakorttien valmistajat toteuttavat oman HAL:n DirectX:ää varten

    Direct3D Hardware Abstraction Layer

  • 19

    • Kaikki mitä on nahdollista tehdä, tehdään "raudalla" − Mikäli grafiikkakortti ei tue jotain toiminnallisuutta, sitä voidaan

    mahdollisesti simuloida ohjelmistollisesti

    − Direct3D:n kautta voidaan kysellä tukea eri toiminnallisuuksille (erityisen

    tärkeää silloin jos jotain toiminnallisuutte ei voi simuloida

    ohjelmistollisesti)

    • Direct3D on toimintaperiaatteeltaan hyvin samantapainen kuin

    OpenGL − Piirrellään vertexeistä koottuja perusprimitiivejä ruudulle (TriangleFan,

    TriangleStrip, TriangleList, LineStrip, LineList, PointList)

  • 20

    Direct3D Fixed Function and Programmable Transformation and Lighting Pipeline

    • Direct3D ei ole alustariippumaton joten sen rutiinit on tehty

    ainoastaan Winows mielessä − Tästä johtuen Direct3D:ssä on joitain erikoisen tuntuisia piirteitä

  • 21

    Windows-ohjelmoinnista • Käytettäessä suoraan Windows API:a grafiikkaohjelmointiin

    täytyy huolehtia itse ikkunoiden luomisesta, viestien

    käsittelystä jne.

    ⇒ Jo pelkän ”Hello World”-tyyppisen sovelluksen aikaansaamiseksi tarvitaan paljon koodia

    • Perus-Windows-sovellus sisältää WinMain-pääohjelman, joka

    on muotoa int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR

    lpCmdLine, int nCmdShow )

  • 22

    • Pääohjelma tekee yleensä ainakin seuraavat asiat:

    1. Rekisteröi ikkunaluokan

    2. Luo tähän luokkaan kuuluvan ikkunan

    3. Tekee ikkunan näkyväksi ja asettaa sen päivittymään

    4. Pyörii silmukassa, joka lukee viestejä sovelluksen

    viestijonosta, ja ohjaa viestit eteenpäin ikkunoiden

    viestinkäsittelijöille

    5. Lopettaa ohjelman saatuaan WM_QUIT-viestin

    • Ikkunaluokan ominaisuudet määrätään sijoittamalla arvoja

    WNDCLASS- tai WNDCLASSEX-tyyppisen struktin kenttiin

  • 23

    ⇒ Strukti annetaan parametriksi RegisterClass- tai RegisterClassEx-funktiolle, joka ”rekisteröi” luokan:

    // Create a WNDCLASSEX struct and fill its memory area with zeros WNDCLASSEX wc; ZeroMemory( &wc, sizeof( WNDCLASSEX ) ); // Fill in the needed members of the struct created above wc.cbSize = sizeof( WNDCLASSEX ); // size of the window struct in bytes wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // window styles to use wc.lpfnWndProc = MsgProc; // function name of event handler wc.hInstance = hInstance; // handle to this apps instance wc.hbrBackground = ( HBRUSH )GetStockObject( GRAY_BRUSH ); // background colour of window wc.hIcon = LoadIcon( NULL, IDI_APPLICATION ); // icon for the app window wc.hIconSm = LoadIcon( NULL, IDI_APPLICATION ); // icon when minimized to taskbar wc.hCursor = LoadCursor( NULL, NULL ); wc.lpszClassName = strAppname; // name for this class // Register the window class

    RegisterClassEx( &wc );

    • Itse ikkuna luodaan CreateWindow tai CreateWindowEx-

    funktiolla, jolle annetaan ikkunaluokan nimi g_hWnd = CreateWindow( strAppname, strAppname, WS_OVERLAPPEDWINDOW, 10, 10, g_D3DSettings.m_nDeviceWidth, g_D3DSettings.m_nDeviceHeight, NULL, NULL, wc.hInstance, NULL ); ShowWindow( g_hWnd, nCmdShow ); UpdateWindow( g_hWnd );

  • 24

    • Funktio palauttaa HWND-tyyppisen ”kahvan” luotuun ikkunaan

    o Samasta luokasta voi halutessaan luoda useamman ikkunan

    • Pääsilmukka lukee viestejä PeekMessage-funktiolla

    o Vastaava GetMessage-funktio jää odottamaan että viestejä on jonossa

    // Create a MSG struct for the widows messages MSG msg; ZeroMemory( &msg, sizeof( msg ) ); // The windows message loop while ( msg.message != WM_QUIT ) { // If messages need to be processed do it, otherwise enter game loop if ( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { GameLoop(); } }

  • 25

    • DispatchMessage-funktio välittää viestit asianmukaisille

    ikkunoille

    o TranslateMessage muuttaa mm. ASCII-merkkeihin liittyviä näppäintapahtumaviestejä WM_CHAR-viesteiksi

    • Jokaiselle ikkunaluokalle määritellään oma

    viestinkäsittelyfunktio, joka käsittelee ko. luokan ikkunoita

    koskevat viestit: LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )

    • Viesti voi olla esimerkiksi näppäimistöviesti tai WM_PAINT, joka

    tarkoittaa että ikkuna kaipaa päivittämistä

  • 26

    • Käytettäessä perinteistä Windows GDI:tä (Graphics Device

    Interface) piirto ikkunaan tapahtuu siihen liittyvän Device

    Context:in (DC) kautta

    • Device context sisältää tiedon kyseiseen ikkunaan tai

    laitteeseen liittyvistä parametreistä:

    o käytettävissä olevat grafiikkaobjektit, kuten kynät, bittikartat, fontit, värit

    o tausta, skaalaaminen, koordinaatistomuunnokset, leikkausalue (clipping region) jne.

    • Kutsumalla BeginPaint-funktiota ikkunafunktio saa ikkunaan

    liittyvän device context:in sekä PAINTSTRUCT-tyyppisen struktin

  • 27

    ⇒ tämän yksi kenttä on RECT-tyyppinen strukti, joka sisältää päivitettävän alueen vasemman yläkulman ja oikean alakulman koordinaatit

    hDC = BeginPaint( hWnd, &PaintStruct );

    ...

    EndPaint( hWnd, &PaintStruct );

    ⇒ DC:n koko ikkunaan saa myös GetDC-kutsulla, ja piirtoalueen GetClientRect-kutsulla

    • OpenGL-ohjelmoinnissa tarvitaan lisäksi DC:hen läheisesti

    liittyvä Rendering Context, johon piirtäminen tapahtuu

    o Tämän saa wglCreateContext(hDC) -kutsulla, ja se aktivoidaan wglMakeCurrent(hDC,hRC) -kutsulla

    • DirectX toimii kuitenkin hieman eri tavalla, koska se perustuu

    Microsoftin COM-komponenttimalliin

  • 28

    DirectX ja COM • DirectX perustuu Microsoftin Component Object Model:iin

    (COM)

    • COM komponenteissa kantava idea on luoda komponentteja

    (olioita) jolta komponenttien käyttäjä pyytää jotain tiettyä

    interfacea käyttöönsä − Yksi komponentti sisältää usein monta erillistä interfacea

    − Komponenttien erilliset interfacet eivät pääse toistensa sisältämään

    tietoon tai toiminnallisuuteen käsiksi (muuten kuin normaaleja reittejä)

    − Interfacet eivät muutu niiden julkaisun jälkeen

  • 29

    • Kaikki COM komponenttien interfacet periytetään IUnknown

    interfacesta jolla on ainoastaan metodit: AddRef(),

    QueryInterface() ja Release()

    • ”Object” ja ”Interface” käsitteet sekavia MS:n omassa jopa

    dokumentaatiossa − In casual usage, an object may sometimes be referred to by the name

    of its principle interface. However, strictly speaking, the two terms are

    not interchangeable

    COM Object

    IUnknown

    Interface1

    Interface2

  • 30

    Toimintaperiaate:

    1) Käyttäjä pyytää interfacen joltain COM komponentilta

    2) Komponentti antaa pyydetyn interfacen käyttäjälle ja lisää omaa reference

    counttia AddRef() -metodilla jotta tietää montako interfacea siitä on tehty

    3) Käyttäjä tekee saamallaan interfacella mitä haluaa

    4) Käyttäjä ei tarvitse interfacea ja tuhoaa sen kaikille COM interfaceille

    yhteisellä metodilla Release()

    5) Release() -metodin seurauksenä COM komponentti (jolta interface oli

    pyydetty) vähentää reference counttiaan, mikäli interface oli viimeinen

    käytössä oleva interface tästä komponentista, komponentti tuhotaan.

    Muuten siltä voi edelleen käyttää olemassaolevien osoittimien kautta.

  • 31

    • Release() ja AddRef() metodien taustalla on muistinkulutuksen

    tehostaminen ja hallittavuuden parantaminen − Tavallisimpia ongelmia peleissä on muistin vuotamisesta aiheutuva

    pelin kaatuminen (peleissä toistetaan usein samoja rutiineja erittäin

    usein)

    • COM interfacen metodien paluuarvot ovat usein HREF

    tyyppisiä − Kertovat boolean tyyppisesti (tosin moniarvoisesti) tuloksen laadusta

    − Tyypillisiä arvoja ovat: S_OK, E_FAIL (S -> Success, E -> Error)

    • DirectX:n funktiot ottavat tyypillisesti parametrikseen jonkin

    DX:n määrittelemän struktin, jonka jäseniä täytetään tarpeen

    mukaan

  • 32

    Esimerkki: luodaan IDirect3D9 interface ja pyydetään siltä IDirect3DDevice9 g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );

    ...

    result = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT,

    D3DDEVTYPE_HAL,

    hWndTarget,

    D3DCREATE_HARDWARE_VERTEXPROCESSING,

    &d3dpp,

    g_pDevice );

    LPDIRECT3D9 g_pD3DCopy = g_pD3D;

    g_pD3DCopy->AddRef();

    ...

    g_pDevice->Release();

    g_pD3DCopy->Release();

    ...

    g_pD3D->Release();