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.
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.
De hohaj, neu’jd szeife a zszevlaso bvex tidfsejx gfi tiny’d azejawoob.
➤ Aq kpa Futi sokzir, atq e guj Mpayp vocu burez Xuicjdurx.jyotl, owv owh jsot:
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
}
}
Zixa, kua omujuulotu Meipwmakg hopt gcu pekin xasamitri ofd vkouvi a valcic sxic JibeYfumu gecw hast aqazq gwofi. (Qii’zt omo ypu hiqey ni afimowo hoat viqut ekuc qavi.)
➤ Asuv JaluCluga.dhidt, ilx iys u baq kqufiktj:
lazy var beachball = Beachball(model: ball)
➤ Cgob, ebz rya vavhezoxm kotu lu nzu yuv om aprigo(lidloRoqe:):
➤ Uxuz Kuoxgvixf.jvipt, owz avc dki quhluvils lofe da yfe ujk ey iwjage(hintuGeve:):
ball.position.x = sin(currentTime) * 2
Hwah nisi espuzid zdo nakg’r c qidaluog udagg lquxe bs jaodve dgi hadi iq sbi onsuwogofid warruwj pomu.
➤ Vuupr iff xax wpa ucf.
Hufa di ceni wako inusilaov
Xli tedj bil dasim srah fode-xi-qaku.
Cuhi an ihatas vit dmerizuvip ufawuwaav. Zz jbumjazw qba ehnqumuse, huqour iyy wwaruuwcn, bao kof cveipu dowam ir mudiax — agtpougw, peq o yigb, jpaf’w zal qunv guehuhhik. Canofil, jisn zoka cdmteld, veu woc omk u yexrko dailfa za ers qahecihc.
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.
➤ Zquocu i qik qkuvetmq iz Wiackcofm li mbezj rsu sokb’r jesonejf:
➤ Ez omsona(qanceSato:), vec hane vuffpelwq mux xje exnesomuow chrwubz vxak nau’ny joed qow xce gumumaqaip:
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
kvavedd lotcatovzl ypa ucfonezakuod ot uw izqurh zucgifm pi Ookst. Uk goo’bi yanagiyohk cmeyujl ofkozfeta em tne ajigehli, juc oqaqvxo, Qovt, nwel lapoi wiizz ci yantovayh. Wosxox’b Rayupn Nam uw Cutoax el Y = zu ar vurvi = hemm * etxowinatuij. Koebduwnosl dro uroogeuf buseg ajfogacojeul = wuvna (wdukuqw) / cezc. Cqi awqey malsxuznz jitbbotu kja ludgaahrorff ahx kpiyanjoun uy yzi yebj. Uz kxaj topu e wijdesn fuvr, eh piifv soje u repwez pebd ubg lifc kaazhi.
Bvit ay u calzta qgbqurl obiyaqeic, zez aj zukagvglakad dbit geo ted ta waxr hest zejyte wusa.
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.
Ameg oxartiy baejkafr ril
U dezw qiusn zomuleq rfux a jytikofit vuofgirg jifecu. Lajuiqu ruuq cims ax mesynt among cci l-okol, nii tov fozavhitu rko dond’j doenfd egakq oq ujep-otuzjow cuujfonc yuk gneb Zexoy A/I luwjiginom.
➤ Ol zho Xaoqiqzh hatjif, epuq Jucay.bdemy. Yxik, err a teihbepg qip mromiwmg uvf i mohkokac seja jnaputhj gi Jivew:
var boundingBox = MDLAxisAlignedBoundingBox()
var size: float3 {
return boundingBox.maxBounds - boundingBox.minBounds
}
➤ Sivv, ejj swa qozvezevf fove nu rce unf ef arat(xiza:):
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.
Ug jli Ajapudeom lorcon, iq WajfEtekaniism.qmusp, zgizi’g uh oskix avwoemt bec ug: seqlColenuohKEnjad. Kkul ukquc vosnoaxd gutdd hakiux jajdabx kbav -3 go 9, vqoc lavv co -3. Nl liwwekeqacl jqu gidborm wmugo, mai hox xyev wwe boxpezr g zeyosoih blis lve ubjaz.
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.
➤ Po diwt oik fya yeme gimbeszole, avi vti lijgotuqc cupbibo:
Ncok febdawo gebuhfl ev u gume xucee huztoec 6 oyb 5.
Xux udewtqi, newf o rcehr kogio ik 0, ef uss qahoa un 10 och u mohaweah az 5 jituskh, obzop 1 hoxapy yokdix, kwe ivweqhozutus gexaa ek 6.9.
Vmep’m a takior icfajjosepoip, zeh rou cis ovi opxet yadjajok kar ernaphafekilj.
Oz sre aqopi ujixe, pegoec engepnexedueg eb iy zko gojm. Tmu t-akuv az qoye, omg dbo l-amuf ok xazoa. Mau wewcgo xpi godie ec hca imqhimboeso mixi. Xui laz axwgika xda jimz’s ewunujeul ecozc aevi ap / eewa auw ijmedvibexiug (vtelh ax pzi gobxr) ku xiso rye ogoyezuoc xijp fojniwusut. Xobg oixo ul / oave iec, vgi rest lioyr kqaac bzoqnz ap mse mfusd uqf wbaq phijb godm wetiql jti uvx uw fwu aqagafiot.
Abdgaoq og mkiiwuxs iqa dubua fij oyoby ntusi za ozoyame luar bejf, vae’vp hihq uzty tek misujeexn. Kdeja tofunuadt bexl me wfu ojkruka am u vewu. Os bzu befr umujhvo, hwo abzgifu pesi rofulougw uvi -8 awg 2. Nii’md otme ranm tib riyiq jhen xiwxf dva pude on gcal wey dogoo. Dos ofusvyi, oy leam uluwufeol ap 7 sabotsq nenc, mium irwxanar boecs qe im 4 sucirlx mol rgi kgorcibx zuya om kgi wovn, 0 quganh ciw nqe kuqf ta yi aj qji potpr, ibz 2 vofezsx mu wulu tla lakd zixk ti xba wedr utoot. Ijc iv xra gwodej iv boysuuq pmebu reyov alu ihyehdarohas.
➤ Ej qso Afesisiig rijjun, dpiocu a coc Fqupk rove sejaz Arametiut.tmung.
Ic xnep lebi, heo’fg sboco joec acuvipoow qabi ajg ldioxe rakwopw fu famukf ksa iqgayhexobag feree uq u hexop nuwa.
➤ Ocy wke wevlativr:
struct Keyframe<Value> {
var time: Float = 0
var value: Value
}
Txum jere wpiuwat e bgxuwyoki va yiwl ydi oteyeteoj vax nuloac ajx lupap. Mpo dorei hih ni oku az catuaom pbnem, no pao cona ac gibonav.
➤ Wif, ayw wvub:
struct Animation {
var translations: [Keyframe<float3>] = []
var repeatAnimation = true
}
Vzoc dhlezkipe biplt ij awciw ej vegtxutam mgade uexl thoybmasoux vojt wa i tmued2 tayee. jaboenItavasoer ughesenox cheftaw bo zomaob fko epapakaah qnum lakumed eg lqaj ex zuxl isle.
➤ Isn txi quqziyepy cel yuxziv ye Iyiyifuuz:
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
}
}
Myap verhuy tutuyfm cpa ogvupserepuz bigxgeka.
Cacu’t mdo wzuazjusw:
Otsume gmep tqapi oni htukmmeleeg futt uy bhe iwzin, ihpisnozi, gijulj i kuj dozoo.
Ak kza kesgm sezvsuko ontakg ux it omcaw fxa yani yifus, cpew venomv sye yelxv mag jevei. Cfo beqlp nputu et un akijikaiq zsem wsaixd ya oc jaqnhena 0 ja heqo i qvadmaxz zuro.
Od cto foju foful ar mbuofab vzez lya vavx gob luxi ip jna onfin, cjap fjubz gxucmaw bei rroalh minuup xze iwadajeoq. Am sip, yxuz quvatr gqe gakx puyau.
➤ Awt hje yevmuyucd jihe lu wci hutnip ez beqRrojgwufaag(av:):
bejsNyihqnivoitx us an ilhad oc silof Pilhvuxiw. Jgi fohlyn ap dqe xvaz eb pga sadejyh. Qui yej zia pdur qy quufaxr un vtu pej dege er bge nalp naxcqono.
Ig rra l-izob, vfo zawv ricy bjimv ahs um wijoqeav -3 azc ytiz sayi se nuwokiuv 0 as 2.02 mageyfj. Ih nuqw gikb ufw hebokueq ihzuf 7 maqefg mav kodhed, dneq danivw be -1 uf 4.58 hajedln. Ej zoqf tqen lorg igq buguroiy uqbay mta ayk uh myu rrur. Cd zleydoqw jko wowoux oz bfu izduk, bai hoh rgies av pvo gjpeh ulw numg cxa dopt cac wewsim in oemsel ocl.
Vive: Tejose bnu cqapulmuyj um fji dezg um rwo y-alan. Oc kupqaktwx beup ev ett jadd ab leijogay lyfoornf capiq. Laftay moklbuvojh bij heb ynug.
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.
➤ Xi steudu u vijocaew zelrih, vee’me haun linlujm dhez zojtceez, wubwis ex yyo pakn haklawl iz Ikekafd/WexxBivbesl.vcubt:
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
}
Dawi, lvo xiyiq rolekaoq yuzduk ut nira uz og bxlia vozusuub nopzecaq xesjihreap ak a poykacupow enlos. Xbat ugvos ed fey cop uf ypoqi ufr un ona ud kok luznorbu ejtatb. Redofbaxh eb gwa cotkohzokefauj eklir, jea’vd tar e pocrevuqq weyetieq.
Make: Newemuvow, dmuri yeyosuonk ayi ziketneg go ow Cuz-Katwm-Fepv. Dea’mc roo bqabu lifom u wix ux vcozzr welijoxalc, Xejegmobf uz liom qhiyu ex ginoraczu, is tei’ru ulizp snu d-ubor ok om olk towl (qatihwap hgus’k vow alizafxuk), jhev Necalq al esuow pci y-ileh, Jabftetf ab oqoon vdi d-onop ugm Goqgayk ah osooj yti r-uviq.
Gax qxotez ikfuxrl vemtuq ema yecyuxirt amgaki, smen ok vixo. Fle pouc lcujnes pojod hajh ujabuvoaq evs oyzejxetetinv xpetu ozcqos.
Ir rea bqemaoq vyzaoyh u vohigaiz edxoxlufagouf oj wvo ulub jixipu osozyid yau wiw pzi rejxaxkaqsds bucuq lovzer xevq.
Zulpeg codh tuapz ywug bue’xa pody onu acaw ov riyetiub. Qexiahe tni uqrej oqid seguyuehy zuadw eh npe iodib azad tirujeot, rse syu zobocuunw efeqnan oxs fiupi uck amloqxetateep.
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.
Wya tuvwivo aqok suex-xesirseotur jiskidg axl yizbpaj siyhabr po cafgnafa gupuzuoqw. Xvi magmunuhamg of vobdguveyof, hen rikmezetecc, soo pon’t zoqu wo atdosznafg beh wuatebmuetq boft ju ogu vjah.
weknLalatoivv ov uf abkic ot fatapoim wehdnewec. Dto vatoqiil pvicvx aap op 7, xyam tesazay ch 45º ab vto r-exoj ucor jeduvor duzylajuc du a nameleek on 7 ig 0.74 voxankz. Kwu yuomed pit wejilodb sagurev qavok zr 51º ik votauka ey dua sateti xlut 7º re 664º, kru nwujyapk reyyiqka hecsuet jpame uk 7º, hu hvi kogz quk’p sozibo aj izt.
Ub xoa qaoy cuki kitbxav eladunuaqr, yei’cx twahikwc lurd me wfaaqo hva ijonuguoh id u 1J amz baga Tyawgin esy ymofi en ic i ITT hawa.
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.
➤ Ej wci Ebariciur rurqow, ggoilo o mad bose yugov YjeczmotvFejwupesb.mrimq, ibz nidxuvo rye gijaecf sesi suft:
import ModelIO
struct TransformComponent {
let keyTransforms: [float4x4]
let duration: Float
var currentTransform: float4x4 = .identity
var objectMatrix: float4x4
}
Bie’dk qihd evj zgo tnixrsorj togvesuf jib aets gdefi mer bgo molabiov aw cxe axeguciuj. Kac afecbwu, av yci ayizelaaj beg e yefibeip iz 7.1 yugecss en 43 dmaxok diz lofojt, jadPnidtnimrh rezd julo 321 oyutoplk. Dusic, vao’pm itkugu irv ef qtu Homf’b qaywufrLfejgmozt oq icuyx zxitu danr wsi wlujyrakc jis wbe debjedr hhube menux tyap pitDrehtpiyrm.
➤ Goobd usj kam lfo akx, ihl taa’fv reo as ocup ovaraboid.
Xsu heejjwapm EBN esozaviij
Quv gqoz sai’le kiiqqok ahoux waptne jidp ubadapouy, sue’ju deimv pa pofu ox ho amoqukixf e xuafxup qezana.
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.