Fysiikkamoottori Katri Roos Seminaariraportti HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos Helsinki, 7. joulukuuta 2017
HELSINGIN YLIOPISTO HELSINGFORS UNIVERSITET UNIVERSITY OF HELSINKI Tiedekunta Fakultet Faculty Laitos Institution Department Matemaattis-luonnontieteellinen Tekijä Författare Author Katri Roos Työn nimi Arbetets titel Title Tietojenkäsittelytieteen laitos Fysiikkamoottori Oppiaine Läroämne Subject Tietojenkäsittelytiede Työn laji Arbetets art Level Aika Datum Month and year Sivumäärä Sidoantal Number of pages Seminaariraportti 7. joulukuuta 2017 9 sivua Tiivistelmä Referat Abstract Fysiikkamoottori on osa pelimoottoria. Sen avulla mallinnetaan fysiikan ilmiöitä pelimaailmassa ja hoidetaan törmäyksen tunnistus ja reagointi siihen. Laskennan on oltava riittävän tehokasta ja hyvin optimoitua, jotta peli toimisi sujuvasti, realistisesti ja pätkimättä. Fysiikkamoottoreita on useita, niin kaupallisia kuin avoimeen lähdekoodiinkiin perustuvia. Tässä seminaariraportissa olen esitellyt Unity pelimoottorin fysiikkamoottoria PhysX ja Unityn fysiikkamoottorin perusominaisuuksia. The ACM Computing Classification System (CCS rev.2012): Software and its engineering Software creation and management Designing software Software design engineering Avainsanat Nyckelord Keywords Fysiikkamoottori; Pelikehitys; Pelimoottori; Törmäyksentunnistus Säilytyspaikka Förvaringsställe Where deposited Muita tietoja Övriga uppgifter Additional information
Sisältö 1 Johdanto 1 2 Kappaleiden fysiikka 2 3 Törmäyksen tunnistus 4 4 Törmäykseen reagointi 6 5 Yhteenveto 8 Lähteet 9 ii
Kuva 1: InXile Entertainmentin Wasteland 3 on tekeillä Unity pelimoottorilla. Kaikki peliobjektit, joihin halutaan kohdistaa painovoiman vaikutus, käyttävät jäykän kappaleen mekaniikkaa [1]. Lähde: https://www.fig.co/campaigns/wasteland-3 1 Johdanto Fysiikan simulointi tietokonepeleissä on oleellinen osa pelikokemusta. Lähes kaikki pelit tarvitsevat jonkinlaista fysiikkasimulaattoria toimiakseen järkevästi. Fysiikan simuloinnin on oltava tasaisen toimivaa, eikä se saa hidastua tai kaatua. Fysiikan simuloinnin hoitaa pelimoottorin fysiikkamoottori. Pelien fyysiikkamoottorien ei tarvitse simuloida fysiikkaa kuten tieteelliseen tutkimukseen tarkoitetut simulaattorit. Fysiikkamoottorit yksinkertaistavat Newtonin mekaniikkaa, jotta simuloinnista saadaan tarpeeksi nopeaa ja sujuvaa pelien tarpeisiin. Pelikokemus ei kuitenkaan huonone, sillä se, miten ihmiset ajattelevat fysiikkaa ja odottavat asioiden tapahtuvan, on kuin yksinkertaistettua Newtonin mekaniikkaa [6]. Monien pelien fysiikkamoottorien tärkein osa on jäykkien kappaleiden mekaniikan käsittely. Tosi maailmassa suurimman osan kappaleista voidaan ajatella käyttäytyvän kuten jäykät kappaleet eli kappaleet, joiden koko ja muoto eivät muutu, vaikka todellisuudessa kappaleet koostuvat atomeista ja molekyyleistä, joiden sidokset ovat joustavia. Tämän takia peleistä saadaan todellisen tuntuisia ja viihdyttäviä. Jäykän kappaleen mekaniikka on myös melko suoraviivaista toteuttaa. Kuva 1 on vuonna 2019 julkaistavasta Wasteland 3 pelistä, mikä toteutetaan Unity pelimoottorilla. Unityn 1
fysiikkamoottori käyttää jäykän kappaleen mekaniikkaa lähes kaikkien peliobjektien toteutukseen. Jäykkien kappaleiden lisäksi Unity-pelimoottorin fysiikkamoottorista löytyy esimerkiksi kangaskappaleiden käsittelylle oma luokkansa. Tässä seminaarityössä käyn läpi Unityn fysiikkamoottorin perusominaisuudet. Luvussa kaksi käsittelen miten peliobjektit toteutetaan Unityssä ja miten fysiikkaa käytetään niihin. Luvussa kolme on törmäyksen tunnistuksesta ja viimeisenä luvussa neljä, on siitä miten peliobjektit käyttäytyvät törmäyksen tapahtuessa. Pelimoottoreita on monia esimerkiksi Unreal ja Unity. Unreal- ja Unitypelimoottorit käyttävät fysiikanmallinnukseen PhysX fysiikkamottoria [2] [1]. PhysX on vapaan lähdekoodin fysiikkamoottori. Unity sisältää kaksi fysiikkamoottoria, 2D-fysiikalle ja toinen 3D-fysiikalle. Molemmille ulottuvuuksille on omat metodinsa. 2 Kappaleiden fysiikka Unityn fysiikkamoottori perustuu jäykkien kappaleiden (Rigidbody) mekaniikkaan. Tämä peruskappale mahdollistaa fysiikan käyttämisen pelin toiminnallisuudessa. Näiden kappaleiden liikettä ei määritellä muuttamalla niiden liikekoordinaatteja suoraan, vaan fysiikkamoottori laskee ne pelin aikana vaikuttavista voimista. Esimerkiksi biljardipelin pallo on paikoillaan kunnes toinen pallo osuu siihen, vaikuttava voima siirtyy ensimmäiseen palloon ja liikuttaa sitä. Voi olla tapauksia, missä halutaan kappaleen reagoivan painovoimaan ja törmäyksiin, kuten jäykkä kappale ja silti hallita sen liikkeitä koodista käsin. Unityssa Rigidbody-kappaleelle voidaan määrittää boolean arvo IsKinematic, mikä kertoo käytetäänkö fysiikkaa liikkeeseen vai ei [1]. Unityn fysiikkamoottori käyttää Newtonin mekaniikkaa liikeradan ja nopeuden laskemiseen. F = ma (1) Yhtälössä 1 on dynamiikan peruslaki eli voima (F) antaa kappaleelle sen kiihtyvyyden (a) ja yhtälöön vaikuttaa myös massa m. Tämä on pohjana fysiikkamoottorien laskennassa. Suureita käsitellään vektoreina ja ne voidaan laskea jokaiselle koordinaatille erikseen; kolmiulotteisessa pelimaailmassa siis X, Y ja Z koordinaateille. Dynamiikan peruslakia hyväksi käyttäen saadaan laskettua kappaleen kiihtyvyys, kun tiedetään massa ja siihen vaikuttava voima. Kiihtyvyydestä voidaan integroida nopeus v ja nopeudesta saadaan edelleen integroimalla kappaleen sijainti S. Fysiikkamoottorissa integrointi tapahtuu numeerisella analyysillä. Numeerisista menetelmistä voi lukea lisää esimerkiksi John Butcherin Numerical methods for ordinary differential equations -kirjasta [4]. Unity pelimoottorin 2
Kuva 2: Eulerin menetelmällä voidaan approksimoida integraalifunktio. käyttämän PhysX fysiikkamoottorin numeerista integrointimenetelmää ei ole kerrottu, koska moottori on kaupallinen [3]. Eulerin menetelmä on ehkä yksinkertaisin näistä menetelmistä (mutta sinällään ei kovin tarkka) ja monet edistyneemmät menetelmät myös perustuvat siihen. Perusajatus on se, että koska tiedämme pelissä olevan kappaleen massan ja voiman, mikä vaikuttaa kappaleeseen, voidaan niistä laskea kappaleen kiihtyvyys kaavalla 1. Kiihtyvyys integroidaan numeerisella menetelmällä ja tulokseksi saadaan nopeus. Koska kiihtyvyys on nopeuden derivaatta eli tangentin kulmakerroin tietyssä pisteessä, voidaan riittävän pienellä askeleella approksimoida nopeuden funktio käyttäen tangenttiviivoja. Olkoon kuvan 2 funktio y = f(x) kiihtyvyyden funktio. Koska tiedämme sen arvon eli nopeuden derivaatan pisteessä x 0, voidaan piirtää tangentti pisteestä x 0 pisteeseen x 0 + h, missä h on haluttu askelpituus. Peliohjelmoinnissa se on loopin pituus. Näin saamme arvion integraalista. Mitä pienempi askelpituus, sitä tarkempi approksimaatio. Jäykkien kappaleiden liikkeen hallintaa voidaan Unityssä helpottaa erilaisilla nivelillä (Joints). Kun on kaksi Rigidbody-objektia, joiden liikettä fysiikkamoottori hallitsee, mutta halutaan kuitenkin jonkinlaista kontrollia kappaleiden yhteiseen liikkeeseen, voidaan liittää ne yhteen nivelellä. Niveliä on erityyppisiä. Heilurinivel (Hinge Joint) sallii kiertoliikkeen tietyn pisteen ympäri ja sarananivel (Spring Joint) pitää kaksi kappaletta irti toisistaan, mutta pitää etäisyyden joustavana. Näitä rakenteita voi käyttää heilureissa, ketjuissa ja muissa vastaavissa rakenteissa [1]. Usein pelihahmo on ensimmäisessä tai kolmannessa persoonassa ja pelihahmon odotetaan liikkuvan ripeämmin kuin fysiikanlait sallisivat tosi maailmassa. Hahmo liikkuu nopeammin kuin oikeassa maailmassa olisi mahdollista ja pysähtyy kuin seinään, kun hahmon ohjaus lopetetaan. Hahmo myös pystyy kääntymään suoraan kovasta vauhdista. Jos pelihahmo olisi fysiikanlakien mukaan liikkuva jäykkä kappale, mihin vaikuttaa nopeus ja kitka, sen ohjaaminen hankaloituisi huomattavasti. Pelihahmoa varten Uni- 3
Kuva 3: Pelihahmon kontrolli-ikkuna. Lähde: https://https://docs.unity3d.com/500/documentation tyssä on oma Character Controller -luokka. Se ei reagoi fysiikkaan vaan sille tehdään omat määritykset. Jäykät kappaleet voidaan laittaa reagoimaan hahmoon törmätessään, mutta hahmo itse ei reagoi. Tämä luokka määrittelee hahmolle kapselin muotoisen törmäyttimen (näistä lisää luvussa 3) (Collider) kuten kuvassa 3. Hahmo reagoi staattisiin taustalla oleviin kappaleisiin, kuten lattiat ja rappuset, eikä putoa niistä läpi. Fysiikkamoottoreissa käytetään optimointina unitilaa. Myös Unityn fysiikkamoottorissa on sleep -tila [1]. Fysiikkamoottorissa on määritelty kynnysarvo lineaariselle nopeudelle ja kulmanopeudelle. Kun kappaleen nopeus alittaa kynnysarvon, se menee unitilaan, eikä kappaleen tilan päivittämiseen enää käytetä prosessointiaikaa. Kappale herää kun siihen kohdistuu törmäys. Kappale voidaan herättää myös tarkoitukseen tehdyllä funktiolla. Tämä voi olla aiheellista, jos esimerkiksi pelissä olevan kappaleen alta hajoaa lattia ja kappaleen on tarkoitus pudota lattian mukana eikä jäädä roikkumaan ilmaan. 3 Törmäyksen tunnistus Törmäyksen tunnistusta (Collision detection) varten peliobjektit kääritään yhteen tai useampaan törmäytin (Collider)-objektiin. Näitä objekteja on kolmea alkeistyyppiä (primitive collider): pallo (sphere), kapseli (capsule) ja laatikko (box). 2D-grafiikkaa käytettäessä alkeistörmäyttimiä ovat laatikko ja ympyrä. Monet peliobjektit saadaan luontevasti kuorrutettua näillä alkeistyypeillä, kuten kuvassa 4. Tämä vähentää prosessointia ja optimoi törmäyksen tunnistusta [1]. Unityssa on myös mahdollista käyttää verkkotörmäytintä (Mesh colli- 4
Kuva 4: Alkeistyypin törmäyttimiä (primitive collider) käyttämällä voidaan optimoida ja vähentää prosessointiaikaa. Lähde: https://https://docs.unity3d.com/500/documentation der). Tämä muotoutuu nimensä mukaisesti peliobjektin ympäri kuin verkko. Verkkotörmäyttimellä saadaan yksityiskohtaisempi törmäyksentunnistus monimutkaisille peliobjekteille, mutta verkkotörmäyttimen käyttö lisää myös prosessorin käyttöä. Unityn dokumentaatiossa kehoitetaankin käyttämään verkkotörmäytintä pelikohtauksen taustalla oleviin staattisiin liikkumattomiin objekteihin. Nämä staattiset objektit eivät itse reagoi kun niihin törmätään. Alkeistörmäyttimiä suositellaan käytettäväksi objekteihin, jotka reagoivat törmäykseen [1]. Törmäyttimeen voi myös liittää Trigger-ominaisuuden. Silloin törmäytin ei käyttäydy törmäyksessä kuten jäykkä kappale, ei esimerkiksi kimpoa toisesta esineestä, vaan toimii vain tapahtumanlaukaisimena kun toinen objekti siirtyy sen läheisyyteen. Verkkotörmäyttimen asetuksissa on vakiona, ettei se reagoi toisiin verkkotörmäyttimiin. Jos kuitenkin kaikesta huolimatta halutaan käyttää tätä ominaisuutta esimerkiksi yksityiskohtaisessa pelihahmo objektissa, voidaan valita tälle ominaisuus Convex eli kupera. Tämä ominaisuus muotoilee verkkotörmäyttimestä kuperan, jolloin se ei sisällä yhtään koveraa kohtaa ja silloin objekti voi reagoida törmäyksiin. Tämä perustuu erottavan akselin teoreemaan (Separating Axis Theorem), mikä tekee törmäyksen helpommin laskettavaksi. Kuvassa 5, näkyy kuinka kaksi kaksiulotteista kappaletta projisoidaan suoralle ja tarkistetaan löytyykö projektioiden välistä aukko. Jos löytyy, niin kappaleet eivät törmää. Kolmiulotteisessa avaruudessa kappaleet projisoidaan tasoihin. Erottavan akselin teoreema pätee vain kuperiin kappaleisiin. 5
Kuva 5: Erottavan akselin teoreema [5]. 4 Törmäykseen reagointi Kahden törmäyttimiin liitetyn peliobjektin törmätessä, kutsutaan OnCollisionEnter-funktiota. Peliobjektien ollessa kosketuksissa, kutsutaan OnCollisionStay- ja objektien irtaantuessa, OnCollisionExit-funktioita. Näihin fuktioihin voidaan ohjelmoida mitä tahansa tapahtumia, vaikka tietty musiikki tai ääniefekti. Jos törmäytin on tyypiltään Trigger, kutsutaan fuktioita OnTriggerEnter, OnTriggerStay ja OnTriggerExit. Törmäyttimeen voidaan myös määrittää Physic Material luokan avulla, miten peliobjekti reagoi törmäykseen. Luokan avulla voidaan määrittää kappaleelle esimerkiksi kitka ja kimmoisuus (bounciness). Normaaleissa törmäyksissä on otettava huomioon, että ainakin yhden törmäyttimen on oltava ei-kinemaattinen (Is Kinematic -ominaisuus pois päältä) eli fysiikkamoottori laskee kyseisen objektin liikeradan. Jos näin ei ole, funktiota OnCollisionEnter ei kutsuta. Trigger-törmäyksissä ei ole tätä rajoitetta [1]. Unityssä on useita sääntöjä peliobjekteille, riippuen siitä miten niiden halutaan reagoivan. Staattinen törmäytin (Static Collider) on objekti, mihin 6
Kuva 6: Peliobjektien reagointi törmäyksessä. Lähde: https://https://docs.unity3d.com/500/documentation ei ole liitetty Rigidbody-komponenttia. Näitä ovat pelin taustalla olevat rakenteet, mihin törmätessä halutaan reaktio, mutta ei haluta liikuttaa kyseistä objektia. Jäykkä kappale ja törmäytin (Rigidbody Collider) on peliobjekti, jonka liikettä fysiikkamoottori hallitsee ja joka reagoi törmäyksiin ja koodista käsin tehtäviin muutoksiin. Kinemaattinen jäykkä kappale ja törmäytin (Kinematic Rigidbody Collider) on liikuteltavissa koodista käsin muuttamalla sen koordinaatteja. Se toimii kuten staattinen törmäytin, se ei reagoi toisen kappaleen törmätessä siihen. Tästä esimerkkinä liukuovi; sitä liikutetaan tarvittaessa, mutta se ei reagoi törmäykseen. Rigidbody-elementin kinemaattisuus voidaan laittaa päälle ja pois pelin aikana koodista käsin. Tämä on hyödyllistä silloin, kun halutaan Ragdoll-efekti. Ragdoll-efekti tarkoittaa sitä, kun esimerkiksi pelihahmon raajat ovat omat peliobjektinsa. Normaali tilanteessa hahmo on kinemaattinen ja sitä liikutetaan pelaajan toimesta, mutta räjähdyksen tai rajun törmäyksen ansiosta hahmon raajojen kinemaattisuus otetaan pois päältä, jotta ne heilahtavat iskun voimasta fysiikkamoottorin laskemiin suuntiin kuten räsynukella [1]. Kuvassa 6 on taulukoitu erilaisia peliobjektityyppeja ja ne ovat merkattu Y-kirjaimella, jos kumpikin tai ainakin toinen reagoi törmäyksessä. Perusajatuksena on, että jos haluaa fysiikkamoottorin tekevän objektille jotain, sen on oltava jäykkä kappale eli Riginbody-objekti. 7
5 Yhteenveto Unity pelimoottorin käyttämä PhysX on avoimen lähdekoodin fyysikkamoottori. Niin Unityn, kuin monen muunkin pelimoottorin fysiikkamoottorin toiminta perustuu Newtonin mekaniikkaan ja tosi maailman fysiikan ilmiöiden yksinkertaistamiseen. Tämä tekee laskennasta tarpeeksi yksinkertaista ja nopeaa, jotta peli toimisi juohevasti. Pelikokemus ei häiriinny, jos kumista palloa käsitellään fysiikan näkökulmasta törmäyksissä samalla tavalla kuin esimerkiksi lentävää lehmää, sillä ihminen olettaa fysiikan ilmiöiden, kuten törmäyksen, kimpoamisen, kaatumisen ja niin edelleen, tapahtuvan melko samalla tavalla käsiteltävästä kappaleesta riippumatta. Jäykkien kappaleiden mekaniikan lisäksi peliin saadaan fysiikalta vaikuttavia tehosteita magnetismillä, kangasmateriaaleilla ja muilla erikoisuuksilla. Näiden liike ja toiminta ei kuitenkaan varsinaisesti liity fysiikkamoottorin laskentaan kuten jäykkien kappaleiden mekaniikka. Esimerkiksi Unityssä kangaskappaleisiin törmäyksellä ei ole mitään vaikutusta ja magneettisen kappaleen saa ohjelmoimalla magneettiselle kappaleelle sitä kohden vetävän voiman, mikä vaikuttaa fysiikkamoottorin laskentaan jäykän kappaleen lähestyessä sitä. Fysiikkamoottorit sisältävät algoritmit kappaleiden nopeuden ja liikeratojen laskemiseen, törmäyksen tunnistamiseen ja siihen reagoimiseen. Fysiikkamoottorien suurimmat erot ovatkin näiden perusalgoritmien optimoinnissa ja erillaisissa versioissa. 8
Lähteet [1] Unity Documents. https://docs.unity3d.com/manual/ class-rigidbody.html. Accessed: 2017-11-09. [2] Unreal Engine Documents. https://docs.unrealengine.com. Accessed: 2017-11-08. [3] Boeing, Adrian ja Bräunl, Thomas: Evaluation of real-time physics simulation systems. Teoksessa Proceedings of the 5th international conference on Computer graphics and interactive techniques in Australia and Southeast Asia, sivut 281 288. ACM, 2007. [4] Butcher, John Charles: Numerical methods for ordinary differential equations. John Wiley & Sons, 2016. [5] Huynh, Johnny: Separating Axis Theorem for Oriented Bounding Boxes. URL: jkh. me/files/tutorials/separating% 20Axis% 20Theorem% 20for% 20Oriented% 20Bounding% 20Boxes. pdf, 2008. [6] Ullman, Tomer D., Spelke, Elizabeth, Battaglia, Peter ja Tenenbaum, Joshua B.: Mind Games: Game Engines as an Architecture for Intuitive Physics. Trends in Cognitive Sciences, 21(9):649 665, 2017, ISSN 1364-6613. http://www.sciencedirect.com/science/article/ pii/s1364661317301134. 9