Kuvaaja sskennel.
Tämän päivän kysymys- ja vastausistunto tulee meihin SuperUserin ansiosta. Tämä on Stack Exchange -jako, joka on Q & A-sivustojen yhteisöjoukkoyhtymä.
Kysymys
SuperUser-lukija Sathya esitti kysymyksen:
Täältä näet kuvakaappauksen pienestä C ++ -ohjelmasta nimeltä Triangle.exe, jossa on pyörivä kolmio, joka perustuu OpenGL API: iin.
Olin vain utelias ja halusin tietää koko prosessin kaksoisnapsauttamalla Triangle.exe -ohjelmaa Windows XP: ssä, kunnes näen kolmion, joka pyörii näytössä. Mitä tapahtuu, miten vuorovaikutuksessa suoritetaan CPU (joka käsittelee ensin.exe) ja GPU: n (joka lopulta tuottaa kolmiota näytöllä)?
Luulen, että tämä pyörivä kolmio näytetään pääasiassa seuraavista laitteistoista / ohjelmista muun muassa:
Laitteisto
- HDD
- Järjestelmämuisti (RAM)
- prosessori
- Videomuisti
- GPU
- LCD-näyttö
Ohjelmisto
- Käyttöjärjestelmä
- DirectX / OpenGL API
- Nvidia-ohjain
Voiko kukaan selittää prosessi, ehkä jonkinlaisella vuokaavalla havainnollistamiseksi?
Sen ei pitäisi olla monimutkainen selitys, joka kattaa jokaisen askeleen (arvaus, joka ylittäisi soveltamisalaa), mutta selitys, jolla välittäjä IT-kaveri voi seurata.
Olen melko varma, että monet ihmiset, jotka jopa kutsuisivat itseään IT-ammattilaiset, eivät pystyneet kuvaamaan tätä prosessia oikein.
Vastaus
Kuva JasonC, saatavilla taustakuvana tässä.
Hän kirjoittaa:
Päätin kirjoittaa hieman ohjelmoinnin näkökulmasta ja miten osat puhuvat toisilleen. Ehkä se tuo valoa tietyille alueille.
Esitelmä
Mitä se tarvitsee edes siihen yksittäiseen kuvaan, joka lähetit kysymykseesi, piirretään näytölle?
Kolmio voidaan piirtää näytöllä monella tapaa. Yksinkertaisuuden vuoksi oletetaan, ettei vertex -puskuria käytetä. (A kärkipuskurion muistipaikka, jossa tallennat koordinaatit.) Oletetaan, että ohjelma yksinkertaisesti kertoi grafiikkaprosessin jokaisesta yksittäisestä kärkestä (vertex on vain koordinaatti avaruudessa) peräkkäin.
Mutta, ennen kuin voimme tehdä mitään, meidän on ensin ajettava rakennustelineitä. Katsotaan miksi myöhemmin:
// Clear The Screen And The Depth Buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Reset The Current Modelview Matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Drawing Using Triangles glBegin(GL_TRIANGLES); // Red glColor3f(1.0f,0.0f,0.0f); // Top Of Triangle (Front) glVertex3f( 0.0f, 1.0f, 0.0f); // Green glColor3f(0.0f,1.0f,0.0f); // Left Of Triangle (Front) glVertex3f(-1.0f,-1.0f, 1.0f); // Blue glColor3f(0.0f,0.0f,1.0f); // Right Of Triangle (Front) glVertex3f( 1.0f,-1.0f, 1.0f); // Done Drawing glEnd();
Mitä sitten teki?
Kun kirjoitat ohjelmaa, joka haluaa käyttää näytönohjainta, valitset yleensä jonkinlaisen käyttöliittymän kuljettajalle. Jotkut tunnetut liitännät kuljettajalle ovat:
- OpenGL
- Direct3D
- CUDA
Tässä esimerkissä pidämme kiinni OpenGL: stä. Nyt sinun käyttöliittymä antaa sinulle kaikki tarvittavat työkalut ohjelmasi tekemiseen puhua näytönohjain (tai kuljettaja, joka sitten neuvottelut kortille).
Tämä käyttöliittymä on varmasti varma Työkalut. Nämä työkalut muodostavat sovellusliittymän, jonka voit soittaa ohjelmasta.
Tämä sovellusliittymä on sellainen, jota voimme nähdä yllä olevassa esimerkissä. Katsotaanpa tarkemmin.
Rakennustelineet
Ennen kuin voit todella tehdä mitään todellista piirrosta, sinun on tehtävä a perustaa. Sinun on määritettävä näkymäsi (alue, joka todella tehdään), perspektiivi ( kamera osaksi maailmaasi), mitä anti-aliasingia käytät (tasoitat kolmiota reunasta) …
Mutta emme tarkastele mitään siitä. Me vain katsomme tavaroista, joita sinun täytyy tehdä jokainen kehys. Kuten:
Näytön tyhjentäminen
Grafiikkaputkijohto ei aio tyhjentää näyttöä jokaiselle kehykselle. Sinun täytyy kertoa se. Miksi? Tämän vuoksi:
Jos et poista näyttöä, voit yksinkertaisesti vetää pois se kaikki kehykset. Siksi kutsumme
glClear
kanssa GL_COLOR_BUFFER_BIT
sarja. Toinen bitti (
GL_DEPTH_BUFFER_BIT
) kertoo OpenGL: lle tyhjentää syvyyspuskuri. Tätä puskuria käytetään määrittämään, mitkä pikselit ovat muiden pikselien edessä (tai takana).
muutos
Transformointi on osa, jossa otamme kaikki syöttökohdat (kolmiomme pisteet) ja käytämme ModelView-matriisiamme. Tämä on matriisi, joka selittää miten meidän malli- (vertikaalit) pyöritetään, skaalataan ja käännetään (siirretään).
Seuraavaksi sovellamme projektiomatriisiamme. Tämä siirtää kaikki koordinaatit, jotta ne kohtaavat kameramme oikein.
Nyt muutamme jälleen Viewport-matriisiamme. Teemme tämän mittakaavassa malli- monitorimme kokoon. Nyt meillä on joukko huippupisteitä, jotka ovat valmiita tekemään!
Palataan muutokseen hieman myöhemmin.
Piirustus
Piirrä kolmio, voimme yksinkertaisesti kertoa OpenGL: lle aloittaa uusi luettelo kolmioista soittamalla
glBegin
kanssa
GL_TRIANGLES
vakio. Voit myös piirtää muita lomakkeita. Kuten kolmio-nauha tai kolmio-tuuletin.Nämä ovat ensisijaisesti optimointeja, koska ne edellyttävät vähemmän kommunikaatiota suorittimen ja GPU: n välillä, jotta saadaan sama määrä kolmioita.
Sen jälkeen voimme tarjota luettelon kolmesta huippupisteestä, joiden pitäisi muodostaa jokainen kolmio. Jokainen kolmio käyttää 3 koordinaattia (kuten 3D-tilassa). Lisäksi annan myös a väri- jokaiselle huippupisteelle, soittamalla glColor3f
ennen kutsumus
glVertex3f
Kolmen pisteen (kolmiomaisen kolmion kulmat) välinen sävy lasketaan OpenGL: llä automaattisesti. Se interpoloi värin monikulmion koko pinnan päälle.
vuorovaikutus
Nyt, kun napsautat ikkunaa. Sovelluksen on vain kaapattava ikkunaviesti, joka ilmoittaa napsautuksesta. Sitten voit suorittaa mitä tahansa haluamaasi ohjelmaa.
Tämä saa a erä vaikeampi, kun haluat aloittaa vuorovaikutuksen 3D-kohtauksen kanssa.
Sinun on ensin tiedettävä, missä pikselissä käyttäjä napsautti ikkunaa. Sitten, otat teidän näkökulmahuomioon, voit laskea säteen suuntaan hiiren napsautuksesta pisteestä kohtaasi. Tämän jälkeen voit laskea mikä tahansa esine kohtaasi leikkaa tuon säteen kanssa. Nyt tiedät, onko käyttäjä napsauttanut objektia.
Joten, miten voit kiertää sitä?
muutos
Tiedän kahdenlaisia muutoksia, joita yleensä sovelletaan:
- Matriisi-pohjainen muunnos
- Luuton muutos
Ero on se luut vaikuttaa yksin kärkipisteet. Matriisit vaikuttavat aina kaikkiin vedettyihin pisteisiin samalla tavalla. Katsotaanpa esimerkkiä.
esimerkki
Aiemmin ladattiin meidän identiteettimatriisi ennen kuin piirimme kolmiomme. Identiteettimatriisi on yksi, joka yksinkertaisesti tarjoaa ei muutosta ollenkaan. Joten mitä minä vetän, vaikuttaa vain perspektiini. Joten kolmioa ei pyöritä ollenkaan.
Jos haluan kiertää sitä nyt, voisin joko tehdä itse matematiikan (suorittimella) ja soittaa
glVertex3f
kanssamuut koordinaatit (jotka pyöritetään). Tai voisin antaa GPU: lle tehdä kaiken työn kutsumalla
glRotatef
ennen piirustusta:
// Rotate The Triangle On The Y axis glRotatef(amount,0.0f,1.0f,0.0f);
amount
on tietysti vain kiinteä arvo. Jos haluat elävöittää, sinun pitää seurata
amount
ja lisää sitä jokaisella kehyksellä.
Joten, odota, mitä tapahtui kaiken matriisipuheen aiemmin?
Tässä yksinkertaisessa esimerkissä emme tarvitse huolehtia matriiseista. Me vain soitamme
glRotatef
ja se hoitaa kaiken meidän puolestamme.
glRotate
tuottaa pyörimisen
angle
asteet vektorin x y z ympärillä. Nykyinen matriisi (seeglMatrixMode) kerrotaan pyörimismatriisilla nykyisen matriisin korvaavalla tuotteella, koska ifglMultMatrix kutsuttiin seuraavalla matriisilla argumenttinaan:
x-1-c-zx-x-1-c-zx-x-1-c + 1-c-x-0-x-1-c-x-syy-1-c + x 2z 1 -c + c 0 0 0 0 1
No, kiitos siitä!
johtopäätös
Mikä ilmeinen on, on paljon puhetta että OpenGL. Mutta se ei kerro meille mitä vain. Missä viestintä on?
Ainoa asia, jota OpenGL kertoo tässä esimerkissä, on kun se on tehty. Jokainen toiminta vie jonkin verran aikaa. Jotkut toiminnot ovat uskomattoman pitkät, toiset ovat uskomattoman nopeasti.
Sumteen lähettäminen GPU on niin nopea, en edes tiedä miten ilmaista sitä. Lähettämällä tuhansia huippupisteitä suorittimesta GPU: han, jokainen yksittäinen kehys, on todennäköisesti ongelmaton.
Näytön tyhjentäminen voi kestää jopa millisekuntia tai huonompi (muista, että sinulla on yleensä vain noin 16 millisekuntia aikaa piirtää kutakin kehystä) riippuen siitä, kuinka suuri näkymäsi on. Poistaaksesi sen, OpenGL: n on piirrettävä jokainen yksittäinen pikseli väriä, jonka haluat tyhjentää, joka voi olla miljoonia pikseleitä.
Muutoin voimme vain kysyä OpenGL: stä grafiikkasovittimemme ominaisuuksista (maksimaalinen tarkkuus, maksimaalinen aliaksennus, maksimaalinen värien syvyys …).
Mutta voimme myös täyttää tekstuurin, jossa on pikseleitä, joilla kaikilla on tietty väri. Jokainen pikseli siis pitää arvossa ja tekstuuri on jättiläinen "tiedosto", joka on täynnä tietoja. Voimme ladata sen grafiikkakorttiin (luomalla tekstuuripuskuri), sitten ladata shaderin, kertoa, että shader käyttää tekstuuria panoksena ja suorittaa erittäin suuria laskelmia "tiedostossamme".
Sitten voimme laskea laskentamme tuloksen (uuden värin muodossa) uuteen tekstuuriin.
Näin voit tehdä GPU: n toimivan sinulle muillakin tavoilla. Oletan, että CUDA suorittaa samanlaisia kuin tämä näkökohta, mutta minulla ei koskaan ollut mahdollisuutta työskennellä sen kanssa.
Olemme todella koskettaneet vain koko aiheen. 3D-grafiikan ohjelmointi on helvetin peto.
Onko jokin asia lisättävä selitykseen? Kuulkaa kommentit. Haluatko lukea lisää vastauksia muilta tech-tajuilta Stack Exchange-käyttäjiltä? Katso koko keskusteluketju täältä.