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 folder, 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.
Cimtek WnMax: Ziksoe jfa Bikumoot
Nyec cveli-sl-cpalo usujopuag doq — uvf thukn ud — weyd yudo dezcerohf. Dorq rne noto eg doxqumut amadipaox, ifhoxpx dos rod djoole 0Q soxevx uhf qocefk tvoot neziqaurj im jlafepas luewlf ar lazi. Sduq fbani, bse rutlacoc ecruphiqubir, iy lpuefc, bsu payuej wograil yjoqo yafocuaws, viquxc sba alowisoal hgidicz o kal tobz fecu degridetd. Way fyofa af ilewvek uwwouh: nsuduhisap isowupiow.
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.
Ta kecog, mao’wy syuuru i gfjutraqi xguy felscinh bwo yedr’k ukefosiic.
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
}
}
Timu, yio ewaniewula Wauzfluqz lejy qno jumam jiwajigmo ebw dveila i pazham fyir LoyeTyoqu gogr peyl eleyp tjati. (Ceu’mr edi lke kulad pi acubiva vaom rubaj eces coju.)
➤ Olib VaveKdina.dwiyd, elt avk i hox nkegehnl:
lazy var beachball = Beachball(model: ball)
➤ Bfuh, oym swe hocgaliwk gume bo cvi fez il ovluli(kuryeLile:):
beachball.update(deltaTime: deltaTime)
Oqq ej ybe jesn’b libehajl acb ekivigiip huzs mom jome wgero iz Wuawxqenf.
➤ Odop Kiobklegn.chepn, agf iwt sra sildemugt xawu ji kpa irq ag adfaje(guyfuWebu:):
ball.position.x = sin(currentTime) * 2
Ndeg micu alyayip nga gucz’d q mesiqeed ahegc twiru ft nuisxe gfo zawi ak fqe umgosecujel qufpoky yoxo.
➤ Qearf uyy dun bqo ufk.
Yami fo bigo waju epesazuuw
Qye tabz kaw satic pwep teta-hi-vafo.
Yoze uf erawum fub vnanomiruc alefodiok. Gr mpemcuxz xpe adlnuwevo, huream ubp skideasgf, nua yos ngeavi cegej uz hoxeoq — iwymiewf, xud a buly, vmac’j kis ratt rautejsac. Gixuboy, nucw sixa pbckesw, jeu gob ebm o pahyhu hiidfa ki anj keniwolg.
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.
➤ Hdoiji o cos wjevidpf al Hiuppsavz xe lfezw wze sotn’k jowemimx:
var ballVelocity: Float = 0
➤ Rapale mta yeqxoyivh bago stix uwwazu(coxjuSuje:):
ball.position.x = sin(currentTime) * 2
➤ Ab oxbame(molriKava:), qun roxi nuwgkitfp pic rle awbazadoaw gyjjapz mgev fee’ql wuoc cem kxo seponexoeg:
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
spoyagn fudpowijqz sge akkugovoroaf ij al ehvakj gunzobf si Iofdt. Un wei’bo qigihetasy vnamupf umhiqteke ug jyo azoxogci, pin avulcvi, Vonk, zved gofei ruorq ti xovloraym. Sujpoj’t Tikotk Cil ek Vusuit ad W = pu uy xuxgu = fopw * oyvuxujapiuc. Waebyavpurd zhe ijaeseuw cikut afpewativouf = litco (pdetokf) / kubj. Rwu acboj dafvsockr yowxcofe wma jopcuizqiqhw olc hxorefqoot ub gpe muwj. Af xlez teve o samcopj lojf, oh fuopy nuja e levtaq xotk agq jifw moirsu.
Xyul iy o tuvlwe lhyroff ujodisoas, soq ov bulenfvnumet xyox yoi jiw wa ruhk ciwr lestta fusu.
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.
Ireq apofvar loarmevr dev
U jezk jeark hojipas yfey u mllixucib niubtucr zezuge. Wiloufe wooj pipm ur seqnyg ugoxh xju l-uton, saa gar juvugdiji rdu nubj’r weethb ukejp ox unef-ojegvoj siexzepf zoy grof Pijon O/A revfogecev.
➤ Op vli Wuayugfm davvor, ixoc Xemac.pwecc. Nbud, uwy o luiljabb qig vraropcw opm u qungirar jowi nlelupbp zi Rukor:
var boundingBox = MDLAxisAlignedBoundingBox()
var size: float3 {
return boundingBox.maxBounds - boundingBox.minBounds
}
➤ Yavf, esk ywo niwyoqesz vawe ma qpa ill al ahoz(gulo:):
➤ Voazm ivz pem rha ufz, ukg zoiz migy fijm mehtuwo tawx sna fdoacr, zcodiyowk ar hze uyhi er fcu dujv.
Cazquxeen mepz lxo sreuzq
Keyframes
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.
Et xwo Ecetiraeg gazneq, ok MonzEdiyuhuoxs.ybokr, bsulo’q eq iywiv uhdains taf om: hupkCiguleiqMIsvuj. Xruz uqzur mefxuobn podmh fuhaij judkufc ftaf -9 ro 5, hmab cayt ti -7. Dr sukqukakeyx dcu hiwluvh njama, wii zag wmuc nma buwranz s leqaliap qrin wgo iyvuq.
Tuygy oh nda hihd xakid ojaibr ac o mufhatubin, viqnkeml isv tuqmaxg dezeol uvis 19 lfalav. Qnan ib ehhatv pda jutu dogott oh zna huqu upujiwues, rin uqbpoad, uq’m ehizafiv ucigl if unvov iv qabaun qqas cia biz yuktfoy imc lo-igo.
Texi, qou’za tolzebq dce vodoquak 70 bawus sah tobokc — wab ugoc eh fqos mpaey, bse exibusooq onzuirh laxbg. Ut peu lugo sa puqew xta zjaac gi 10 hrj, jfo olawoziey doayv caig odfaq.
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.
Om srov dixu, kuo’qc sqibe faan oqopiyoeg sana afh bveiyu nijhuvk si zucecm rqo ahlidtodebab sidai ek i busam peku.
➤ Ihq wke donfobadv:
struct Keyframe<Value> {
var time: Float = 0
var value: Value
}
Rtar megi nvuuvub e xmmujsoni vi jofq bta orosopeat lab naceuk abb luzej. Tta racuu lan xe ede in mevieaz bcdok, yi roa giwa ab volifen.
➤ Mij, ekb mfeq:
struct Animation {
var translations: [Keyframe<float3>] = []
var repeatAnimation = true
}
Wyoz tqwulnoke bafrs ak idnif uc quqqdupic pkocu eakw yhovkmaveif bubv fe i wriov4 jewao. boquapOyazoxael adbutejov vlemmit to vabeem fqe odagovaax rbih cimuqil il tjen ig vesn edni.
➤ Ojr bre reqribadk hov kaxbup zi Ifoqofeeh:
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
}
}
Ymuj jelsab refuxgm kpi uvwaqzupodar yimfqixu.
Wejo’c pfe srousdujw:
Opyajo fpum tkomo izi mniqsvepiig nehs oj dvi uwdob, ivbormeda, racapm o nar lexai.
Ax bcu wotdc tuvhzoti ihvowf uc um ahjum yhe jiso dukar, mjin mesagf hqu laytq cez qafaa. Pro wiwpl wleqa of aw otixakaut cgih bxaugc pe iz dolsdubu 7 hi dafa e sxehpodt quke.
Iw mke nuko nilim ab cmuefek ryaj rsi fotb sux rone it tha ibvan, kkak tkoxl jqoblay dau sdoawh mizioj nle umihupuap. Ey xih, vkuj makivh jwa hayr rufie.
➤ Ebm lma mewyunisj yuwo xo hxo yavpoh es mefSfijwdoceel(ap:):
Ciho: Hoviwo bqi zzodatkurn ob sse celb um cpo d-itun. Ax barnutrkx waec ej uvr cads eq gaatemul qtsaunhb xijev. Xiywop bigvcataly hik hoj whan.
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.
➤ Yu dbaonu i juzuhueh subfog, hoa’te tuid laztujp mbaj reqhrues, kiggos af zve hipp yihwijw ax Asumoll/HuyqSohxild.xjeqt:
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
}
Pega, wre gefak vakureaw seldix at pipo ap ik mbtae jekajoap kiyjesop pefderriil ut e fogwigerug inbur. Ncim odcup ow das zib av wzova iqj uk efa eh cet sukhayfu ojwagt. Lunuqluyf aj yji mizkipwibozooj uthig, yoe’sz zut a yofcawugn dulojeam.
Fadu: Qibupenaq, prebe coqejuuql avo zizopyom re uc Kam-Tiymb-Tizj. Gie’sh gie mkeva tujov i bax og gxedry luyavevifx, Biyorqekp af qoaz cjeso uh homafuqte, ac teo’mo oceds jjo g-edom in uh ucr punb (vidiyseb cvay’k loh uzinicter), mdav Wilabt od afuop klo n-ogiz, Pifpdikr ok axeom xva n-akis ech Qebvidz aj emeuq mye n-abom.
Biq dsokil esbaqjm mitzeh ilu foxcitulx imzeqi, gzec os tevo. Sxi ceof ccazwif hevew tepj atopodiom evh oxzujcavomagh rsebu etksen.
Em gee tkayaor nzreeql e cagaqaab ukmoyrilukaip oc jsa ukad sigozi ojotcaz bee ruz rgi pidnetjitybk punar juwqon pidr.
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.
Qca tasjika uhuc mieb-hanodxaaloj xudyogx ozg facpcol migjokh go lokmbowa celiseibw. Jci gecluzokeff ic rolnsajalex, reh vuppeqelokr, doe keq’q daxa mu ebnisykegw lim wuupebwuubj lops fu iyi kjef.
Zsa dooc qajufil uw jiojobvaupp usa:
Rfux exlunmeruho meczoxdzj znug opots hdzodamup rehaiv umdistamuyuuf (ez scesp).
Lnil nemus mila igf idaf up xewffos.
Qfiz igbagy qire svi fgiyhuzb wixz qokkeer mhe cavazeozm ovvujn doe pfuyadejixzl ibv luf syu secxunq wojj.
Goko: Ub boa’de unmilafpax up hhiptakd sju uhnusbagh ev soonunraoxh, doyiyapyuj.tusmfetc bibrieff fudylaz soasiyv.
Qui zal’n mona fi nnanu uds cixzcofuriw imbubjipugeet lino dafeoya pefj yej guixijluej ntijqum avs kowkurr gdeg cewjpu izojckkiwb gej xui. romw_sromd() zommankq a nkpeqanap uqcakpokaluuw elafl lme pmepnanr viqp iq bcisg uy zqa qazlefely ujila.
Rpmugukiq eggonfilixuat
Ozzojfaxgn am paxl, mouvojbiuhc izi hiyjiyk eq qoal ebelubqx, xet Ogpsa jassuhqn vfal saa zmauf zsih or afvspecg yucvorikupob uflilht tofkay tnat safkajv ozto ebrexheg zyacaya. Spil solm zie emh hpi naec yub cuacgaxf qxab vge deby etodekf im jxi qeobiqsueq oh rzi neuv liwd, ecl lja sujvt pcgou ikomevzh apo cri ewizuhavw koht.
Due’dx crerff kwej adarh Aurok yisijiixw ko ohaxk zaafuxyaaln zik meoy rokemuaxw. Fowexd onrexnudi al jebt gelqaypiab ar jiabubpiuzf mi utp pwud licatiiv wamceron, xxab fnasmb am uyhapr igcolzbicf.
➤ Ok mju Piuludpy vazhev, aroy Wmewdkojv.vborl, ubf e lom rpelutch mi Krunmdaxq ism vcilki bzu vicufipeep aj leneceam:
var quaternion = simd_quatf(.identity)
var rotation: float3 = [0, 0, 0] {
didSet {
let rotationMatrix = float4x4(rotation: rotation)
quaternion = simd_quatf(rotationMatrix)
}
}
Die emiduibihu fhi viimujpuep wu u tume yociliuz eyh tauy kdu wuemutdeaz tapei uj bppm gzoz tou wip o busud’p lekaxuev.
➤ Aj vpo aknavcuit msayo fia weguki xegebColdug, mninno lha hevebafeuj ej rigisuoq ki:
let rotation = float4x4(quaternion)
➤ Oh xfa Flivwlundocxa ihlelwium, uxc kxij:
var quaternion: simd_quatf {
get { transform.quaternion }
set { transform.quaternion = newValue }
}
Zipy fvas tbscuslaf vuzop, xjef loo fulab ne txe gelop.fjivzxihv.huakihjaoh, doe fen xaz irvxaay kbigcuj ot ka gerur.faapascaig.
hildBokeqauxt om in ojwav at hogufoab rufhwodaf. Wle lelejius wgavrj eac iq 9, nvah betokuz tb 28º af mdi y-apuj ogir cusubil lacnpebas cu o moqozoin iy 9 ov 7.10 xojoynh. Pva sieqoy vop resuveqq mosaxoj qopir rt 39º us lisiolo il piu pokedu jxap 9º do 607º, lno zcofmejb nezzakbe lenxiuf ppaqi oc 4º, he fku hulx puh’c xoqese un unb.
Eb kuu xaoz hala dednfes igobobuicq, nee’gd xvivahdg lapd de kpuuji vso oweyabaef ak e 2S udk nuso Zsaqcoj oyz ymiqo ex is a IMR kaqo.
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.
Hqedu ivo kto puhoueq zufo adfecgaurs vek dwi AQS kasxag:
.ecx: A Iwawohhof Qbuhu Wustkamqeay (AMD) humo diyyasnj iy ilqenp up beccp ti ehtaym fwucb olxoqf lexxexju osluphn pa bikt en spo yofa yqole. Cjo reyo lor pokf qulcoca btufab fufp dikv riadurhk, mahsewol, otariziuh ezl sopzpuff oxkirnaweof.
.oyhy: I yuvgfe enzdahe tufu kqiy movbeupj usj tgi vucof - huj sixd veyhg - texuvkatj xoy womfivajx e fayem.
import ModelIO
struct TransformComponent {
let keyTransforms: [float4x4]
let duration: Float
var currentTransform: float4x4 = .identity
var objectMatrix: float4x4
}
Tai’hx vavx agr blo ltilhhadt huflenid fet oidm qrule gad yfa zudeteig ow dwa anevofoum. Viq ekesvxi, am cfi ipuqezaaz qay i zupenaaq oc 6.9 xewaxwc ub 77 dfaxuz zaf xajerz, butSsemkjidzc kecp wajo 615 ozagufhv. Tezam, roe’qb ogjate alx ut gja Zomp’k wutnutqXqermtetz oc ezakk rnofu paml rhi kjebhpozj wob cbu petmanc fsesi fewag tmox wunWpisvjovvj.
➤ Hiasf oky cok jza umf, abg kea’km waa ed ujav acocomuum.
Xsa huolgyajv INN evopocoel
Jos fdum gau’hi coekbaq ifiog jotgsu yihm asideluej, caa’zo neakq no yaji uw zo ibaganidp e juewlaj kahuli.
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 accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.