#0
make sure this green box is fully visible
Instructions:
- Ideally, use Chrome on desktop
- Calibrate browser zoom level with ctrl+scroll or ctrl +/-
- Refresh the page (important)
Controls:
- W/S = previous/next slide
- A/D = previous/next step, for slides with steps/animations
- The step indicator will be in the bottom left
make sure this green box is fully visible
#1
What is lerp smoothing?
#2
Lerp smoothing:
a technique to make something smoothly follow something else
a // the position of an object b // the position of a different object, to follow // runs once every frame update(){ a = lerp(a,b,0.01); // using lerp a += (b-a)*0.01; // without lerp }
Move a 1% closer to b
#3
a
b
#4
#5
However
it's broken
#6
24 fps
120 fps
b
#7
24 fps vs 120 fps
#8
Framerate Dependence
when behavior depends on framerate
#9
Linear Motion
speed = 0.01; update(){ a += speed; }Increase a by 0.01, once every frame
24 fps
120 fps
fps
#10
- The code a += speed runs once every frame
- So, the speed it reads, has to be in m/f
- But, we want to specify speed in m/s
#11
Dimensional Analysis
#12
update(){
a += speed * dt;
}24 fps
120 fps
fps
#13
Linear Motion
moveToward( a, b, speed, dt ){ v = b-a; stepDist = speed*dt ; if(stepDist >= abs(v)) return b; // prevents overshoot return a + sign(v)*stepDist; }
Δt
#14
Linear vs Lerp smoothing
#15
Lerp
Linear Interpolation
lerp(a,b,t)=(1−t)a+tb
where
ais the start valuebis the end valuetis a fraction or a percentage, usually between 0 and 1
#16
Linear Interpolation
a
b
lerp(a,b,t)
t=
t
#17
Lerp Smoothing
Lerp smoothing has non-linear behavior!a∗=lerp(a,b,t)1.51.751.8751.9375⋮=lerp(1,2,0.5)=lerp(1.5,2,0.5)=lerp(1.75,2,0.5)=lerp(1.875,2,0.5)
#18
Lerp Smoothing
a∗=lerp(a,b,t)
a
b
a∗=lerp(a,b,t)
n=
t=
t
#19
Zeno's Paradox
#20
Zeno's Paradox
a = 1
a = lerp(a,2,0.5) Zeno failed to consider:IEEE 754-2019 64-bit binary floating-point format
a = lerp(a,2,0.5)
f(0) = 1
f(1) = 1.5
f(2) = 1.75
f(3) = 1.875
f(4) = 1.9375
f(5) = 1.96875
f(6) = 1.984375
f(7) = 1.9921875
f(8) = 1.99609375
f(9) = 1.998046875
f(10) = 1.9990234375
f(11) = 1.99951171875
f(12) = 1.999755859375
f(13) = 1.9998779296875
f(14) = 1.99993896484375
f(15) = 1.999969482421875
f(16) = 1.9999847412109375
f(17) = 1.9999923706054688
f(18) = 1.9999961853027344
f(19) = 1.9999980926513672
f(20) = 1.9999990463256836
f(21) = 1.9999995231628418
f(22) = 1.999999761581421
f(23) = 1.9999998807907104
f(24) = 1.9999999403953552
f(25) = 1.9999999701976776
f(26) = 1.9999999850988388
f(27) = 1.9999999925494194
f(28) = 1.9999999962747097
f(29) = 1.9999999981373549
f(30) = 1.9999999990686774
f(31) = 1.9999999995343387
f(32) = 1.9999999997671694
f(33) = 1.9999999998835847
f(34) = 1.9999999999417923
f(35) = 1.9999999999708962
f(36) = 1.999999999985448
f(37) = 1.999999999992724
f(38) = 1.999999999996362
f(39) = 1.999999999998181
f(40) = 1.9999999999990905
f(41) = 1.9999999999995453
f(42) = 1.9999999999997726
f(43) = 1.9999999999998863
f(44) = 1.9999999999999432
f(45) = 1.9999999999999716
f(46) = 1.9999999999999858
f(47) = 1.999999999999993
f(48) = 1.9999999999999964
f(49) = 1.9999999999999982
f(50) = 1.9999999999999991
f(51) = 1.9999999999999996
f(52) = 1.9999999999999998
f(53) = 2
#21
a∗=lerp(a,b,F)
F
a
b
#22
24 fps vs 120 fps over time t
F
#23
What shape is this?
#24
Finding Continuity
Linear Motion:
a += dt*speed⇓f′(n)=Δtv⇓f(t)=p0+tv
Lerp Smoothing:
a = lerp(a,b,F)⇓f(t)=?
#25
Identifying the Curve
- f(t)=a ❌
- f(t)=a+bt ❌
- f(t)=a+bt+ct2 parabola
- f(t)=a+bt+ct2+... polynomial
- f(t)=a+b/(c+t) hyperbola
- f(t)=a+bct exponential
- f(t)=a+btc power function
- f(t)=a+b⋅cos(c+dt) trigonometric
- f(t)=…
#26
Finding Continuity
a∗=lerp(a,b,F)f(0)f(n)=a=lerp (1−F) f(n−1), + b, F)
#27
Recursion
f(0)f(1)f(2)f(3)=a =(1−F)f(0) a +Fb =(1−F)f(1) ((1−F)a+Fb) +Fb =(1−F)f(2) ((1−F)((1−F)a+Fb)+Fb) +Fb
#28
Finding Continuity
f(2 n )=( a (1−F)2 + − b ) ( ( (1− 1 − 2 F) a+ − + F2 b) +F b ) n 2 +b
#29
f(n)=(a−b)(1−F)n+b
F
#30
a = lerp(a,b,F)
⇓f(n)=(a−b)(1−F)n+b⇓f(t)=(a−b)(1−F)t/Δt+b
This is still framerate dependent (bad)
(we just found its continuous function f over time t)
#31
f(t)=(a−b)(1−F)t/Δt+b
F
#32
F is the fraction to move after one frame
is FΔt the fraction to move after one second?
long story short: no - we can't just multiply by Δt 😔
is FΔt the fraction to move after one second?
long story short: no - we can't just multiply by Δt 😔
#33
F
Δt
#34
Remainder
Goal: Express F in terms of r
F is the fraction traversed at t=Δtr is the fraction remaining at t=1
f(t)=(a−b)(1−F)t/Δt+b
#35
#36
#37
f(t)=(a−b)rt+b
r
Δt
#38
Return to code
f(t)=(a−b)rt+b
⇓
a = ???
#39
The bad one
f(t)f(Δt)=(a−b)(1−F)t/Δt+b=(a−b)Remaining fraction after Δt (1−F)Δt/Δt +b⇓a = (a-b)*(1-F)+b
a = lerp(a,b,F)
a = lerp(a,b,F)
#40
The good one
f(t)f(Δt)=(a−b)rt+b=(a−b)Remaining fraction after Δt rΔt+b⇓a = (a-b)*pow(r,dt)+b
a = lerp(a,b,1-pow(r,dt))
a = lerp(a,b,1-pow(r,dt))
#41
Does it work?
#42
10/20/30/.../110/120 fps
use r
r
#43
λ
this is not half-life :(
#44
Decay
update(){
if( rnd < 0.03 )
dot = false;
}λ=0.03/Δt
f(t)=e−λt
#45
ab=cblogc(a)8 a b= 2 e 3 b log2(8) ln(a)
e=2.718...= i=0∑∞ 2+ ... i 2 ! 1 + ... 6 3! 1 + ... 24 4! 1 + ... 120 5! 1 +...
#46
r
#47
Summary
| f(t)=b+(a−b)(...) | code per frame |
|---|---|
| (1−F)t/Δt | a = lerp(a,b,F) |
| rt | a = b+(a-b)*pow(remainder,dt) |
| 2−t/t1/2 | a = b+(a-b)*exp2(-dt/halfLife) |
| e−λt | a = b+(a-b)*exp(-decay*dt) |
#48
anyway just do this
// Exponential decay function expDecay(a, b, decay, dt){ return b+(a-b)*exp(-decay*dt); } // Exponential decay constant // useful range approx. 1 to 25, from slow to fast decay = 16; update(){ a = expDecay(a, b, decay, Time.deltaTime); }
#49
thanks~
| 🌐 | cat.gay blog coming soon! |
| ✉️ | [email protected] |
|
| acegikmo.substack.com |
|
| youtube.com/acegikmo |
|
| patreon.com/acegikmo |
|
| @FreyaHolmer |
#50
Differential calculus
Autonomous first-order differential equation
{y′y(0)=lerp(y,b,λ)−y=a⇓y(t)y(Δt)=b+(a−b)e−λt=b+(a−b)e−λΔt#51
Spring Physics
y′′+2ζωy′+ω2y=0
ζ
ω
#52
How this was made
..with an embarrassing amount of custom JavaScript/HTML/CSS, but also:
Plugins/Assets| KaTeX | converts LATEX to HTML elements |
| Sarabun | main text font, by Suppakit Chalermlarp |
| Cormorant | Title Font by Christian Thalmann |
| Material Symbols | Symbol font by Google play_arrowpausereplay |
Build Pipeline
| jsdom | to parse/edit HTML during build |
| node.js | to run js locally on build |
| rollup | shoves all js into one file (for single-file export) |
| tsx | to execute typescript in node |
| TypeScript | to make javascript bearable |
| Visual Studio Code | IDE/build environment |
| web-resource-inliner | inlines external/online files (for single-file export) |