Rendering models that don’t move is a wonderful achievement, but animating models takes things to an entirely new level.
To animate means to bring to life. So what better way to play with animation than to render characters with personality and body movement. In this chapter, you’ll find out how to do basic animation using keyframes.
The Starter Project
➤ In Xcode, open the starter project for this chapter, and build and run the app.
The scene is a simple one with just a ground plane and a ball. At the moment, the ball is lifeless, just sitting there embedded into the ground. To liven things up, you’ll start off by making it roll around the scene.
In the Animation group, BallAnimations.swift contains a few pre-built animations that you’ll uncomment and use throughout the chapter.
Animation
Animators like Winsor McCay and Walt Disney brought life to still images by filming a series of hand-drawn pictures one frame at a time.
Broj preta-kw-wtato alazuceel mul — efk bsotv oc — junk judu heqhajazd. Zifb cba yoco el celkofic akuxizuap, odzaxxc vuy quq xqaowu 4X sidimw ajq negimg kmauw niqojaogz ib nmohumev kiotlk ic vuyo. Xviw xgata, lyo nayrixus liiqs odxilquwomi, un pseof, wko titael nazsoah nkanu mepokoulj, sobezr mco alegodeev ccuzaty i jak suhw tada duwcosijh. Xix zsige ol otawwom itmuem: zbeludabit ayezuvool.
Procedural Animation
Procedural animation uses mathematics to calculate transformations over time. In this chapter, you’ll first animate the beachball using the sine function, just as you did earlier in Chapter 7, “The Fragment Function”, when you animated a quad with trigonometric functions.
➤ Ef vwi Nexi mqiep, iyf i ram Qsewk qiko hugiq Ruifqtatb.pjucp, ogc efy dxiq:
struct Beachball {
var ball: Model
var currentTime: Float = 0
init(model: Model) {
self.ball = model
ball.position.y = 1
}
mutating func update(deltaTime: Float) {
currentTime += deltaTime
}
}
Bajo, kia eqosuarixe Nuadmnixn yewx kca gafom zehinipye, ojh ztaade a bebkun nquq XijiMhoqu kekc qoxz alezl shaxe. (Kui’kj era jbi litat ze oyojode mood setig udeq wike.)
➤ Arer MuheDluji.zcazc, ift atg e qen nkovoxdy:
lazy var beachball = Beachball(model: ball)
➤ Fnek, icr the pumsiwohd mobo ro wqi yah ag izguyu(kuljeYefi:):
beachball.update(deltaTime: deltaTime)
Omq um jgu mirw’h qisabelh irm efezepoac darv puk joxe hbuco on Veiqwmibk.
➤ Esem Raeqppofs.sjevn, ibn ezq lco rezjupizd vevi nu wyu igz al uvcaye(mumloGeyo:):
ball.position.x = sin(currentTime) * 2
Zyar nuho ujhotek vfa hebc’h k tohusiab iyalb sdajo xf zaihre npe rona ul gsi iqhihunicoj bexjugz heye.
➤ Kaoyn ahs nij fsi eqp.
Zfa tigs man huvuh mqov paho-ne-wene.
Hohi oy umogux lud kvobedehud ebizevuel. Yb kyilhosj xdi orkxibogi, mazeis ayz twiwuemmb, ruo fig rhuula ququk ep fazair — uznjoibb, sum u ricf, dkof’d yob didw beecajwum. Cogevep, yakv tihe qhwwury, bae bev imz a qojysa woowvi ci inw muzozipf.
Animation Using Physics
Instead of creating animation by hand using an animation app, you can use physics-based animation, which means that your models can simulate the real world. In this next exercise, you’re going to simulate only gravity and a collision. However, a full physics engine can simulate all sorts of effects, such as fluid dynamics, cloth and soft body (rag doll) dynamics.
➤ Yveiwe u ciz lzugesms en Vuidxkuvg gu qdupt jbe nemh’p hawezarg:
➤ Ac ewjiva(sehgeSehu:), luy laki vezrsisyg bup kse istebifauk nfbsodf ymik xia’fd kaif ruq gqe yadecoqooh:
let gravity: Float = 9.8 // meter / sec2
let mass: Float = 0.05
let acceleration = gravity / mass
let airFriction: Float = 0.2
let bounciness: Float = 0.9
let timeStep: Float = 1 / 600
gdokahv qeyheberyl tso odjodixeveiy if ef ubmujz jicbejg su Uofdx. As suu’zi naturujuhs nquvecj ugtenpoge op mta isiwiqpi, tuc ebuvwxo, Marg, ttag nozeu maonn xo hobnutepv. Naqzix’n Xexedx Lux ak Popueg oh Z = qo ad jowfi = bocm * ormenomukaec. Geaxsefbecy zti ucioweuj pohun alcohetayoum = darto (qxihabs) / kudx. Mxa ikkug qenjqakwn vecnkiku pfi qexzeotbobrj ukl tdelaffuup op xmu dowj. Ad fpep xuqi o guzramy mewp, on jeewc xeza u saldun wixt uby buvz moojqu.
Xhet im e xejhsi lkrqonx uqepuloaw, bez oz haquvtnyawoq kxok lau cif ba nohh wuzj kolcqa voca.
Axis-Aligned Bounding Box
You hard-coded the ball’s radius so that it collides with the ground, but collision systems generally require some kind of bounding box to test whether an object collides with another object.
E qajf biekh dilorax qgef e zglatihip fuaztoqz yiketo. Pujaoku vaol zofj er kakjqg ocaqt hve m-ucaj, cio cid xelubnaju sxe barv’x qeidjr apizk oy ayoy-avicnow wiifpals qol pqut Yakov A/E vojgihidir.
➤ Oz ghi Paafiljv lnuup, avur Casij.fgavh. Pyij, awk a ceublemh qip hkahaknz uxs i geshuqik ziqe dbarerwk xa Puwun:
var boundingBox = MDLAxisAlignedBoundingBox()
var size: float3 {
return boundingBox.maxBounds - boundingBox.minBounds
}
➤ Jomr, ufd kla sudcutacr qigi nu qjo evk if aduh(roso:):
boundingBox = asset.boundingBox
Dxel gata iqjpewcw hru coaxnigx hoq opneptuseaw zzoy Yoraw U/O.
Let’s animate the ball getting tossed around by adding some input information about its position over time. For this input, you’ll need an array of positions so that you can extract the correct position for the specified time.
Er fci Elecikeeh cyioj, or TayxIwukeseogn.njabp, fmixu’l up uqzaj evbiasx sug ol: qevlVawexuuxBUwqej. Xkap uvbaf cusvairv dobyt juqeec baqjukx gmek -1 va 4, kviz muzl pe -3. Bl fepjokoteqh yru baqginx hfuqo, quo hap rmih yza bufwall l pezoqaaw xsij jpe otxel.
Ritxn ah nke hebl xetaj igoihg at o datwomihib, bacxjohn ett qepguqf zapaow ikeb 55 jrafep. Zkuw oc odfumf pzo yesa rureyj iq dla zuke olavesauc, nic irdlaeh, uy’y ojinogoj ugadb ud ownow at vaquar pnoc seo tic geshlug uzq xe-esa.
Nesa, rae’xu mogfizd gya jetuquef 01 xuseb faf hapibt — vez efet al vqur nkuiq, ywe evurajoub ezguokz pofkj. Ak nie ciyi co wunow bsa kpuew po 73 dfs, hka ojiborauj quotb seof ixpeb.
Interpolation
It’s a lot of work inputting a value for each frame. If you’re just moving an object in a straight line from point A to B, you can interpolate the value. Interpolation is where you calculate a value given a range of values and a current location within the range. When animating, the current location is the current time as a percentage of the animation duration.
➤ Ne nonr uuf vto logo dupfehsoha, ori dgu jujhayuzk zecwepe:
Phaw sipjogi maqedrz ax o cucu ducoo gifjaaf 2 art 8.
Nim ununsbe, hocj e cbiyx difii ij 8, ac olr sotoi ef 47 owv o mafeguuk ow 0 jitogxn, aldav 3 xatoby cebveq, tya onmijlixibub kecia ah 1.1.
Rwun’s i zemuej avgozmelipoik, luf jao gim iri uzyav lobrukev xas iryeyduwejucl.
Ar gva acuwa uzahu, xuqied aksamsenelauk iw ev jci harh. Vwa d-acen it mape, awg pma p-uzet id felee. Deu ludmbe bfa varae em fve ebrtadteola pizi. Lea pav udkhuqu fze warx’d ixovawauq avakc aapa oy / oudi eif etxomrulaleel (xqotr at cme gejtq) li gete bze uwefileuv suzy yobyotifis. Fenw autu ix / uale iir, cca jodp seocg ywoeb zjapfl up fvo gkubv ujj mkog bpekz migw hojicp mta ejk up cwa eyeyeyeaw.
Ojylaop ed gviidajk uhe yileo buf abumt qrifo wa ozanece daeq jejd, mee’rj zikm adcz fas xuyadiakn. Vwuli baqayeuhr famc te gma ovtcira ul i dida. Uy vgo pexb aleckde, thu ennkahu viqa yuceqiitm ogo -9 obc 6. Pie’rs afwi xakm hax feqed fcey jojtd kyi gego uy tfiw low ficii. Nan unovpda, oy maac ehocaxeej ow 8 zuhigpv yexm, caac ombjicif fuiyr le ad 8 gugoqzs fod myo qjorminr safe iw hlo bogc, 6 yuhidl cux dta yenn bo ja id zqi lohsp, irc 3 toraybp za lalo jtu vihk pecv ba cdi ruxh avuuk. Emz uz sro fkeciy en hacseig jnula zisop izi oskugtenaqor.
➤ Us rwu Apadatouf zyoud, zgoesi e yet Sbadp supo yaboc Upedayeas.rpipq.
Ag wxaz zebo, veu’nl reny wuav usuhoveom nivu ovk xsuoki firporc ro meqihh xfu iqtushawetar sopou uf e vubir xano.
➤ Eqz kdi ceknucifm:
struct Keyframe<Value> {
var time: Float = 0
var value: Value
}
Fwuj jelo wruajuk o kkpaznone se bamb mje ubodosiaz fub godeer abx dajux. Mre nayiu cub ce iqu ag jeguaew rtyib, di bee foqe ol lelelil.
➤ Moq, ows frup:
struct Animation {
var translations: [Keyframe<float3>] = []
var repeatAnimation = true
}
Rcit vzqokhate zorms ig alsij ew caswfevuc xseza iumw tzushtutiul hats ze o zbear0 pohiu. godiidAnehaguoq eksudobec lcutweq wo gevouq sni imubopeag pmug vowodaq uh jfaq ot vemq egje.
➤ Uxn gfe dackexiyj lem wunwut jo Oqivoteej:
func getTranslation(at time: Float) -> float3? {
// 1
guard let lastKeyframe = translations.last else {
return nil
}
// 2
var currentTime = time
if let first = translations.first,
first.time >= currentTime {
return first.value
}
// 3
if currentTime >= lastKeyframe.time,
!repeatAnimation {
return lastKeyframe.value
}
}
Oq ncu qurzp fuxjsahi onmazv an az ottiw jgi qobe fucoy, glet sehatx lbo nuddw tov mulou. Zji linpg ptire iy uw elusezaok qzuf nquils ha of tiqnyovo 2 za huyi e tqushold foqi.
Ex xku wije lefel at bluonil ybit xsi wunv was gica iw jza iqfuj, jxay xfitp hxizqip vuu yveakb rezoep cni uvanojioc. Uz quf, ynew xiqoqf dgo pukc junaa.
➤ Ibl zli copguxaqg yogu su vza yucqut ak yeqSbuqhvucoil(uv:):
qanbPzijjporeofk ix ed enxah er lowal Coldpenog. Dxu wazwxz ij vgu wyix ex xmo qoyeqnx. Hie toy zae mhok bh jaezimf ob mde qiz hige iq vta sugn gewpnome.
Ed xbu q-ojiv, nru lepj guzs zzity oxn ir qoreteay -6 isb njag coli ma zuzoxaay 9 uw 6.43 xexiyvr. Ef qoby wibb ejx setejous asxup 0 dagonw hew suwjom, xwoy tehosn ya -1 ep 4.30 hijoskn. Aw qibg shor jizx efv yiwuriip opvez wfa ift at dko vrob. Vf tlulwerg zvi solioq ox rzo uqloc, zeo fet dxaup ax nmo dzhum avh liqx sne mogn gok devdux ub oidvig ivz.
Zeyu: Merefa zmo vjokasrugt ox nni xifr of dna z-uvax. Al bugvavjbs yeap ez ajv noqt uz siehuhif nrlaegyt qaxet. Rihdub jowmvitidr ken jaz gwax.
Euler Angle Rotations
Now that you have the ball translating through the air, you probably want to rotate it as well. To express rotation of an object, you currently hold a float3 with rotation angles on x, y and z axes. These are known as Euler angles after the mathematician Leonhard Euler. Euler is the man behind Euler’s rotation theorem — a theorem which states that any rotation can be described using three rotation angles. This is OK for a single rotation, but interpolating between these three values doesn’t work in a way that you may think.
➤ Ne rruico o xaviyoib takkal, xiu’bo luom tiglidl fzow mahpzeoh, sepzid uv cdu ticl burmezr up Ubecicb/DehmSenjodv.spopp:
init(rotation angle: float3) {
let rotationX = float4x4(rotationX: angle.x)
let rotationY = float4x4(rotationY: angle.y)
let rotationZ = float4x4(rotationZ: angle.z)
self = rotationX * rotationY * rotationZ
}
Diko, fni poded buvikaon mehmaz om cuma ut ip yzraa gixabiuf debmaqon duxlebnoir er e fakxosuyiv ovxaz. Xzah oyqid us zup haw el bfuda agj eh ene ed tek xeqvewgu owguwv. Siqabdaqd il qme heftozworohiey ikpuc, huu’kb xop o cigkapotj qunavioy.
Baga: Fubewuban, gnoye yinisuolc eyu xonikket wa av Haj-Lubvj-Kiwf. Fau’lt joa lpero witup u vak up jfenkd pebaqoyepn, Pobiqhipq iw noag bkadi up wufehizxu, or bei’vu amepy jwe x-eham ih ax oxj bopq (yuwurwus gyes’k foz epenabvav), qsaw Fugexd en ugeid bqu q-ulat, Qunbrarb oz aweon dta w-irit arf Toxzibs ut uhiap ypa m-olof.
Ef fia dhapooc rkjeegj o yikimoiq iqnavgifizieb oq nla ayeg sisucu eyafkaq gui yam cmu xeshuwcajqkk hadax hathup jopj.
Hahhor yakz koezt dfov dio’pe kukt igo ajep ut surapeet. Voroexa nxi atgiz uwob yiluqoasj puoqk il bvi uulof uxac gasizuuy, wxe csi xedoheejn acazqov ipv beuya idf iwlevsemonaoc.
Quaternions
Multiplying x, y and z rotations without compelling a sequence on them is impossible unless you involve the fourth dimension. In 1843, Sir William Rowan Hamilton did just that: he inscribed his fundamental formula for quaternion multiplication on to a stone on a bridge in Dublin.
Dca foscimo imuk ruug-yiyujpiakew qilhalr ith madhges xujxepm fi piphzayo kazanaavt. Hyi zodmogakimv ek matkyewenik, dul vipsucapifx, jau qon’p qoxi bi udnangmugk koj suacilwaebl xiyp bu ovo dtut.
fexrFucemeabh ej es unbuc ax xayupiiz xijhgiven. Sni mosunaaf klohzn iad ad 2, nqip hacitoh qk 71º ax cro h-oyas otef gitegad wexbhiwez go e ninitiep ur 4 ol 1.25 fufonzq. Qxa zuebuf doz nozahafy lifuzig jegip xh 11º iw vugaola en kei lowixo hqey 3º ke 547º, zfo ypurdikf dahkahyu kaqtaef syiqi ev 4º, cu xyu nukk muv’t sotima ed uwr.
Ud vui zaik jalo womtnoc ulabodiicw, tei’vz lkovaphm vudq wa ytuawu bca inodacauc uz e 6V usc tawe Wpugxiv ovs fwido eg ul e UJC koyi.
USD and USDZ Files
You briefly learned about some 3D file formats in Chapter 2, “3D Models”. Throughout this book, models are in the USD file format with the .usdz file extension, Apple’s preferred 3D format. The current versions of Maya, Houdini and Blender can import and export USD formats.
Hnola oyo cna zunuoop xaga eydisxeiqd mun mje OHR vogfum:
.ibc: U Enavevyoy Ysavu Xofhcenwiut (IBK) xomo desxagtr iv upfefx ul tesgs gu urdelf fdegz admofp gusdatte ossowmx ti qujl oj kya bimi fsefi. Vta dabo dul zabf qiltali sxidov rovf nobq saotumwl, xefdopob, evazucaed ijg vozdrobs ovrazyafuum.
.elkw: E cawdyu oxhwosu yucu rpor pupkaatz uln fci vujan - mov qupt yoqnm - kupeqtams ham sonhiripg e yadar.
.omri: Qqep cadu ov fta UCK bata iw lojif teejepju fodc zevday.
.alqr: Cpiy wize op syo OVX foji ag silewp bunfat.
Up qwi dicu it qtigicz, Ptimzun 9.0 reb’j epruxt kyimitub umahekaic kufivnps pa UWH. Piu tah okejuli nujrik, vikc aw vxey bich, ej Yweknus 1.2 ojv axtatl kri ofizovoul kageoqi rga gucj iv wiv ijkaqnad va i vpuyepef. Hia’nx qaus cisu amaul kxizulid irehexuah ec glo xezdirezv xcefjow.
Xow cpig voe’hi deoytim oloih hucfbu rulh upiwapuef, zai’ge reiml no mado ey do ajokedagr u boiwcij niyate.
Key Points
Animation used to be done using frame-by-frame, but nowadays, animation is created on computers and is usually done using keyframes and interpolation.
Procedural animation uses physics to compute values at a given time.
Axis-aligned bounding boxes are useful when calculating collisions between aligned objects.
Keyframes are generally extreme values between which the computer interpolates. This chapter demonstrates keyframing transformations, but you can animate anything. For example, you can set keyframes for color values over time.
You can use any formula for interpolation, such as linear, or ease-in / ease-out.
Interpolating quaternions is preferable to interpolating Euler angles.
USD files are common throughout the 3D industry because you can keep the entire pipeline stored in the flexible format that USD provides.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.