T: tema · Z: kodu büyüt · S: konuşmacı notları · F: tam ekran · Esc: genel bakış · ⌂ ders haritası
OYUN GEOMETRİSİ VE FİZİĞİ · G6
Eğriler ve Ara Değerleme
Lerp, yumuşatma, kare hızından bağımsız takip, Bézier, Catmull–Rom, sabit hızla yol izleme — “buradan oraya nasıl gidilir?”
PRESS ▶ TO START

Bu derste oyunun haritası 🗺️

  1. Lerp — iki değerin arası: oyun programcılığının en çok kullanılan tek satırı; ters lerp ve aralık eşleme
  2. Yumuşatma (easing) — aynı yol, aynı süre, bambaşka his: t’yi eğmek
  3. Hareketli hedefi izlemek — kamera takibi; herkesin yazdığı satır neden kare hızına bağlı ve doğrusu ne?
  4. Bézier eğrileri — birkaç kontrol noktasından kavisli yol: lerp’lerin lerp’i
  5. Catmull–Rom ve sabit hız — verilen noktalardan geçen yol; üzerinde sabit hızla gitmek için yay uzunluğu tablosu
  6. Her adımda — elle izleme → canlı demo → kod (JavaScript / Python / C#) → motor kaynak kodu
🎮 Bu dersin sonunda…

bir değeri, bir nesneyi ya da kamerayı A’dan B’ye “iyi hissettirerek” götürmenin beş aracını yazabilecek; kare hızından bağımsız yumuşak takip kurabilecek; pist, devriye yolu ve kamera rayı gibi eğri yolları tanımlayıp üzerlerinde sabit hızla hareket ettirebileceksiniz.

🤔 ISINMA: İKİ MENÜ, AYNI SÜRE

İki oyunda da duraklat tuşuna basınca menü ekrana 0,3 saniyede kayarak geliyor. Birinde menü sabit hızla gelip aniden duruyor; öbüründe hızlı fırlayıp hedefi azıcık geçiyor ve yerine oturuyor. Oyuncular ikincisine “daha kaliteli” diyor. Kod farkı ne kadar?

  • Tek bir fonksiyon çağrısı. İkisi de aynı satırı çalıştırıyor: konum = lerp(başlangıç, hedef, t). İkincisi t’yi önce küçük bir fonksiyondan geçiriyor.
  • Oyun geliştiriciler buna “juice” (meyve suyu: oyunun sulu, canlı olması) diyor: aynı mekanik, daha çok tepki.
  • Aynı araçlar daha ciddi işlerde de var: kameranın karakteri izlemesi, merminin yay çizmesi, düşmanın devriye yolu, yarış pisti, ağ üzerinden gelen rakibin ekranda akıcı görünmesi.
  • Hepsinin altında tek bir işlem yatıyor: iki değerin arasını bulmak. Bu sunum o işlemi adım adım büyütüyor: sayıdan zamana, zamandan eğriye, eğriden yola.

🎯 Bu konu için bilmeniz gerekenler

Yeşil = gerekli · kesikli = faydalı ama şart değil. Tıklayınca ilgili sunuma gider.

Neden?G1’de doğru parçası üzerindeki noktayı P + t·(Q − P) diye yazdık; G5’te çizimi iki fizik durumunun “alfa” kadar arasından yaptık. İkisi de aynı işlemdi: lerp. Şimdi ona bir ad verip üzerine inşa ediyoruz.
🧰 Kodlamadan korkuyorsanızBu sunumun tamamı tek bir formülün (a + (b − a)·t) tekrar tekrar kullanılmasıdır. Bézier ve Catmull–Rom formülleri kalabalık görünür; ama birincisi altı lerp’ten ibarettir, ikincisini ezberlemeniz gerekmez (her motorda hazır).

Mini sözlük

lerp (linear interpolation)doğrusal ara değerlemeİki değer arasında, yolun t kadarındaki değer: a + (b − a)·t
inverse lerp · remapters lerp · aralık eşlemeBir değerin aralıktaki oranını bulma · bir aralıktaki değeri başka aralığa taşıma
easing · tweenyumuşatma · ara animasyont’yi bir eğriden geçirerek hareketin hızlanıp yavaşlamasını ayarlama · iki değer arasında süreli geçiş
smoothstep—3t² − 2t³: iki ucu da yumuşak standart yumuşatma eğrisi
exponential smoothing · half-lifeüstel yaklaşma · yarı ömürHer an kalan yolun sabit bir oranını kapatma · kalan yolun yarıya inme süresi
Bézier curve · control pointBézier eğrisi · kontrol noktasıKontrol noktalarının “çektiği” kavisli eğri; yalnızca ilk ve son noktadan geçer
De Casteljau—Bézier noktasını iç içe lerp’lerle bulan algoritma
spline · Catmull–Romparçalı eğri · —Uç uca eklenmiş eğri parçaları · verilen noktaların içinden geçen bir türü
arc length · bakingyay uzunluğu · pişirmeEğri boyunca ölçülen gerçek yol · eğriyi önceden örnekleyip tabloya yazma
LEVEL 0
Lerp
iki değerin arası

Problem: “arası” her yerde

🎮 Bir oyunda “A’dan B’ye”
  • Konum: kapı açılıyor, asansör çıkıyor, kart ele uçuyor.
  • Renk: hasar alan düşman kırmızıya dönüp eski rengine geliyor; gün batımı.
  • Sayı: can çubuğu, ses düzeyi, kamera yakınlığı, puanın “sayarak” artması.
  • Açı: taret hedefe dönüyor.
  • Zaman: ağ üzerinden saniyede 20 kez gelen rakip konumlarının arası (ekranınız 144 kez çiziyor).
İlk akla gelen: her karede biraz ekle

if (x < hedef) x += 5;

  • Ne kadar sürecek? Belli değil: yol uzunsa uzun, kısaysa kısa. İki animasyonu eş zamanlı bitiremezsiniz.
  • Tam hedefte durmaz: 5’er 5’er giderken 298’den 303’e atlar; ya taşar ya titrer.
  • Kare hızına bağlı (G5): 144 Hz ekranda 2,4 kat hızlı.
  • Renk için? Üç kanalın üçü de farklı miktarda değişmeli. Her biri için ayrı if…

Soruyu ters çevirin: “bu kare ne kadar ekleyeyim?” değil, “yolun yüzde kaçındayım?”

Çizimle: lerp, sayı doğrusunda

t = 0100t = 0,25150t = 0,5200t = 0,75250t = 1300a (başlangıç)b (bitiş)100 + (300 − 100) · 0,25 = 150lerp(100, 300, t): “100’den başla; aradaki farkın (200) t kadarını ekle”

t bir orandır: 0 başlangıç, 1 bitiş, 0,5 tam orta. “Arası” gereken her şey (konum, renk, ses, açı) bu tek işlemle yapılır; bu sunumdaki bütün eğriler de lerp’in üst üste uygulanmasıdır.

Fikir: yolun t kadarı

$$\text{lerp}(a, b, t) = a + (b - a) \cdot t$$

  • a: başlangıç, b: bitiş, t: yolun oranı. t = 0 → a; t = 1 → b; t = 0,5 → tam orta.
  • Okunuşu: “a’dan başla; aradaki farkın t kadarını ekle.”
  • t’yi zamandan üretin: t = geçen süre / toplam süre. Süre artık sizin elinizde; hedefte tam durur.
  • Ters lerp: değeri verip oranı sormak: t = (v − a) / (b − a).
  • Aralık eşleme (remap): önce ters lerp, sonra başka aralıkta lerp. “Can 0–100 arasında; çubuk 0–200 piksel.”
  • Sayı olan her şeye uygulanır: vektörde her bileşene, renkte her kanala ayrı ayrı.
Elle hesap
işlemhesapsonuç
lerp(100, 300, 0,25)100 + 200 · 0,25150
lerp(100, 300, 1)100 + 200 · 1300 (tam hedef)
lerp(50, 20, 0,5)50 + (−30) · 0,535 (geriye de çalışır)
lerp(0, 10, 1,5)0 + 10 · 1,515 (b’nin ötesi)
ters lerp(0, 100, 30)(30 − 0) / 1000,3
eşle(30; 0–100 → 0–200)lerp(0, 200, 0,3)60 piksel
renk: kırmızı → mavi, t = 0,5(255, 0, 0) → (0, 0, 255)(128, 0, 128) mor

t 0–1 dışına çıkarsa lerp bozulmaz: doğruyu aynı eğimle uzatır (dış değerleme). Bunu birazdan bilerek kullanacağız.

Kod: lerp, ters lerp, aralık eşleme

🎒 Kodu okuyalım

ifadene demekneden böyle
a + (b - a) * ta’dan başla, farkın t kadarını ekleÖbür yazım a * (1 - t) + b * t aynı sonucu verir: “a’nın ağırlığı 1 − t, b’nin ağırlığı t”. Ağırlıkların toplamı hep 1.
constrain(gecen / 0.5, 0, 1)geçen sürenin oranı; 1’i aşmasınSıkıştırmazsanız animasyon bittikten sonra nesne aynı hızla yoluna devam eder.
tersLerp(a, b, v)v, a–b aralığının neresinde?a = b ise sıfıra bölme: aralık boşsa 0 döndürün.
esle(can, 0, 100, 0, 200)aralıktan aralığap5.js’te map(). Her “şu sayıyı şu ölçeğe çevir” işi: joystick → hız, uzaklık → ses, yükseklik → renk.
Unity: Mathf.Lerpt’yi kendisi 0–1’e sıkıştırırGüvenli ama taşan yumuşatmaları keser. Onlar için LerpUnclamped.
Unity: Quaternion.Slerpdönüşler için “küresel” lerpAçıları düz lerp etmek 350° → 10° geçişinde uzun yoldan döner. Açıda en kısa farkı alın; dönüşte Slerp kullanın.
Önermelerp, t’ye göre doğrusaldır: t’deki eşit artışlar sonuçta eşit artış verir (sabit hız). t = geçen / süre ile kullanıldığında hareket tam süre kadar sürer ve sonucu kare hızından bağımsızdır (sonuç yalnızca geçen toplam süreye bağlı; adım sayısına değil).

Oyunlarda: lerp motorun içinde ve ağın üstünde

Kaynak: Unity Technologies, UnityCsReference (yalnızca başvuru amaçlı yayımlanan kaynak), Mathf.cs. Yorum satırları özgün koddan.

🎮 Aynı satır, dört yer
  • Motor: Unity’nin Lerp’i slayttaki formülün aynısı + sıkıştırma. Godot’nunki sıkıştırmasız tek satır: p_from + (p_to - p_from) * p_weight.
  • Çizim (G5): fizik 50–60 Hz, ekran 144 Hz. Çizilen konum = lerp(önceki fizik durumu, şimdiki, alfa).
  • Ağ: sunucu rakibin konumunu saniyede 20–60 kez yollar. İstemci rakibi kasıtlı olarak biraz geçmişte gösterir ve eldeki iki paket arasında lerp eder. Valve’ın Source motorunda bu gecikme varsayılan olarak 100 milisaniyedir: Counter-Strike’ta gördüğünüz rakip, onda bir saniye önceki rakiptir.
  • Animasyon: “yürüme” ile “koşma” arasındaki geçiş, her kemiğin iki pozu arasında lerp/slerp’tir (blend). Hız arttıkça t artar.
  • Doku ve ses: bir dokuyu büyütünce ekran kartı komşu dört pikseli lerp eder (“bilinear”); ses örnekleri arasında da aynısı.

🌱 Isınma kodu: lerp

Tek satır: return a + (b - a) * t;. Testlerde t = 1,5 de var: sonucu sıkıştırmayın; b’nin ötesine geçmeli (lerp(0, 10, 1,5) = 15). a > b iken de çalışmalı: lerp(50, 20, 0,5) = 35.

🌱 Isınma kodu: aralık eşleme

İki adım: const t = (v - a) / (b - a); (ters lerp) ve return c + (d - c) * t; (lerp). Hedef aralık ters de olabilir: remap(300, 200, 600, 1, 0) = 0,75 (“uzaklık 200’de ses tam, 600’de sıfır”).
LEVEL 1
Yumuşatma
aynı yol, aynı süre, bambaşka his

Problem: doğrusal hareket cansız

Sabit hız = robot
  • lerp ile giden nesne anında tam hıza çıkar, sabit hızla gider, anında durur.
  • Gerçek dünyada hiçbir şey böyle hareket etmez: kütlesi olan her şey hızlanır ve yavaşlar.
  • Göz bunu hemen fark eder: menüler “ucuz”, karakterler “mekanik” görünür.
  • Disney çizerleri bunu 1930’larda adlandırdı: canlandırmanın 12 ilkesinden biri “yavaş başla, yavaş bitir” (slow in, slow out).
🎮 Fikir: t’yi eğ

lerp’e dokunmuyoruz. Yalnızca t’yi önce bir fonksiyondan geçiriyoruz:

x = lerp(a, b, f(t))

  • f, 0’da 0 ve 1’de 1 vermeli: yolculuk yine a’da başlar, b’de biter, yine aynı sürer.
  • Arada ne yaptığı hissi belirler: f yavaş artıyorsa nesne yavaş, hızlı artıyorsa hızlıdır.
  • f’nin grafiği = hareketin “zaman çizelgesi”. Eğim = hız.
  • Bu fonksiyonlara yumuşatma (easing) fonksiyonu, süreli geçişe tween (in-between: ara) denir.

Çizimle: aynı yol, dört farklı his

doğrusal: tzaman (t) →yolmekanikyavaş başla: t²zaman (t) →yolağırca kalkaryavaş bitir: 1 − (1 − t)²zaman (t) →yolfırlar, yumuşak oturursmoothstep: 3t² − 2t³zaman (t) →yoliki ucu da yumuşakalttaki noktalar: eşit zaman aralıklarında nesnenin yeri. Noktalar sıkışıksa yavaş, seyrekse hızlı gidiyor.

Dördünde de nesne aynı sürede aynı yolu gidiyor. Fark, yolun zamana nasıl dağıtıldığında: grafik düzse hız sabit; grafiğin yatık olduğu yerde nesne yavaş, dik olduğu yerde hızlı.

Dört temel eğri ve elle hesap

adf(t)hisnerede
doğrusaltmekanik, sabitilerleme çubuğu, taşıma bandı
yavaş başla (ease-in)t²ağırca kalkar, hızlanarak çıkarekrandan çıkan şeyler; düşen nesne
yavaş bitir (ease-out)1 − (1 − t)²fırlar, yumuşakça otururekrana gelen şeyler: menü, bildirim. En çok kullanılan.
smoothstep3t² − 2t³iki ucu da yumuşakkapı, asansör, kamera geçişi: A’dan B’ye taşınan şeyler
taşıp dön (back)1’i %10 aşar, dönercanlı, “lastik” gibidüğme, ödül, vurgu

Kural: kullanıcının yaptığı işe hemen tepki verilmeli; bu yüzden ekrana gelen şeyler hızlı başlar (ease-out). Ağır ağır başlayan bir menü “donmuş” gibi hissettirir.

Elle hesap: A = 0, B = 100
tdoğrusalt²1 − (1 − t)²3t² − 2t³
00000
0,252564416
0,550257550
0,7575569484
1100100100100

Sürenin dörtte biri geçtiğinde: “yavaş başla” yolun %6’sında, “yavaş bitir” %44’ünde. İkisi de aynı anda varacak.

smoothstep(0,25) = 3·0,0625 − 2·0,015625 = 0,1875 − 0,03125 = 0,15625.

Canlı: yumuşatma yarışı 🏁

  1. Ekranı okuyun: sağda yedi şerit, yedi kutu; hepsi aynı anda çıkıp aynı anda varıyor. Solda seçili fonksiyonun grafiği: yatay eksen zamanın oranı, dikey eksen gidilen yolun oranı. Kırmızı nokta “şu an”.
  2. Tek tek kutulara bakın: hangisi robot gibi? Hangisi “ağır”? Hangisi “neşeli”? Sınıfça her birine bir sıfat bulun.
  3. Grafikte “yavaş bitir”i seçin: eğri başta dik (hızlı), sonda yatık (yavaş). “yavaş başla” bunun tersi.
  4. “taşıp dön” ve “yay gibi”: grafik 1 çizgisinin üstüne çıkıyor; kutu B’yi geçip geri geliyor. lerp’in t’yi sıkıştırmaması bu yüzden önemli.
  5. Süreyi 0,2 sn yapın: farklar kaybolmuyor, “çıt” diye bir his kalıyor. 3 sn yapın: “sekerek” ve “yay gibi” abartılı, yorucu. Arayüz animasyonlarının çoğu 0,15–0,5 saniyedir.
🔎 DEMODA DENEYİN
  1. Ekranı okuyun: sağda yedi şerit, yedi kutu; hepsi aynı anda çıkıp aynı anda varıyor. Solda seçili fonksiyonun grafiği: yatay eksen zamanın oranı, dikey eksen gidilen yolun oranı. Kırmızı nokta “şu an”.
  2. Tek tek kutulara bakın: hangisi robot gibi? Hangisi “ağır”? Hangisi “neşeli”? Sınıfça her birine bir sıfat bulun.
  3. Grafikte “yavaş bitir”i seçin: eğri başta dik (hızlı), sonda yatık (yavaş). “yavaş başla” bunun tersi.
  4. “taşıp dön” ve “yay gibi”: grafik 1 çizgisinin üstüne çıkıyor; kutu B’yi geçip geri geliyor. lerp’in t’yi sıkıştırmaması bu yüzden önemli.
  5. Süreyi 0,2 sn yapın: farklar kaybolmuyor, “çıt” diye bir his kalıyor. 3 sn yapın: “sekerek” ve “yay gibi” abartılı, yorucu. Arayüz animasyonlarının çoğu 0,15–0,5 saniyedir.

🔗 Başka gözle: etkileşimli anlatımlar ve yazılar

Aynı konuyu başka bir anlatımla, kendi elinizle oynayarak görmek çok işe yarar. Kartlar yeni sekmede açılır; çoğu İngilizce ama görsel ve etkileşimli.

Kod: yumuşatma fonksiyonları ve tween

🎒 Kodu okuyalım

ifadene demekneden böyle
t * tyavaş başlat küçükken t² çok daha küçük: 0,1 → 0,01. Sonlara doğru arayı kapatır.
1 - (1 - t) * (1 - t)yavaş bitir“Yavaş başla”nın aynadaki görüntüsü: t yerine (1 − t) koy, sonucu 1’den çıkar. Her ease-in bu numarayla ease-out’a çevrilir.
t * t * (3 - 2 * t)smoothstep0’da ve 1’de eğimi sıfır olan en basit polinom: durarak başlar, durarak biter.
lerp(-200, 40, yavasBitir(t))tween’in tamamıÜç parça: nereden, nereye, nasıl. Süre t’nin hesabında.
tasipDon ve LerpUnclampedilerleme 1’i aşabiliyorUnity’nin Lerp’i bunu keser ve efekt kaybolur.
Unity: Time.unscaledDeltaTimeoyun zamanı durmuşken de akarDuraklatma menüsü Time.timeScale = 0 iken açılır; normal deltaTime ile animasyon hiç ilerlemez.
ÖnermeBir yumuşatma fonksiyonu hareketin toplam süresini ve varış noktasını değiştirmez (f(0) = 0, f(1) = 1); yalnızca hızın zamana dağılımını değiştirir. Anlık hız, f’nin o andaki eğimi × (b − a) / süre’dir: smoothstep’te ortadaki hız doğrusal hareketin 1,5 katı, uçlarda sıfırdır.

Oyunlarda: “juice” ve yumuşatmanın kısa tarihi

🎮 Juice it or lose it (2012)
  • Martin Jonasson ve Petri Purho 15 dakikalık bir konuşmada sıradan bir tuğla kırma oyununu alıp kurallarına dokunmadan dönüştürdüler.
  • İlk ekledikleri şey: tween. Tuğlalar ekrana yumuşatmayla düşüyor, raket vurunca esneyip geri geliyor, top çarpınca büyüyüp küçülüyor.
  • Sonra sırasıyla: renk, ses, parçacıklar, ekran sarsıntısı. Her adımda oyun aynı, his farklı.
  • Konuşmanın adı bir slogana dönüştü. Bugün bağımsız oyunların çoğunda (Vlambeer’ın oyunları, Celeste, Dead Cells, Balatro) her etkileşimde birkaç tween aynı anda çalışır.
  • Videosu ve oynanabilir demosu Kaynaklar’da: derste 3 dakikasını izletmeye değer.
Bu eğriler nereden geldi?
  • 1930’lar, Disney: çizerler “yavaş başla, yavaş bitir” için ara kareleri uçlara sık, ortaya seyrek çiziyordu. İlke 1981’de The Illusion of Life kitabıyla yazıya geçti.
  • 2000’lerin başı, Robert Penner: Flash için yazdığı yumuşatma denklemleri (quad, cubic, back, elastic, bounce; her birinin in / out / in-out sürümü) açık lisansla yayıldı. Bugün CSS’teki, Unity eklentilerindeki, Godot’daki adlar onun adlarıdır.
  • smoothstep: grafik programcılığının standart fonksiyonu; gölgelendirici dillerinde (GLSL, HLSL) yerleşiktir. Y15’te Perlin gürültüsünde hücreler arasını yumuşatan da buydu.
  • Motor kodu: Godot’da s * s * (3.0 - 2.0 * s); Unity’de -2t³ + 3t² (az önceki alıntı). Aynı polinom.

Bütün eğrilerin grafikleri: easings.net (Kaynaklar).

🌱 Isınma kodu: smoothstep

İki satır: t = Math.max(0, Math.min(1, t)); ve return t * t * (3 - 2 * t);. Kontrol: 0,25 → 0,15625; 0,5 → 0,5; 0,75 → 0,84375. Testlerde −0,5 ve 1,7 de var: sonuç 0 ve 1 olmalı.
Quiz 1 · yumuşatma
Oyuncu envanter tuşuna bastığında panel ekranın dışından kayarak geliyor. Hangi yumuşatma en uygun ve neden?
Oyuncunun girdisine tepki hemen görünmeli. “Yavaş başla” ilk karelerde neredeyse hiç kıpırdamaz; panel donmuş gibi hissettirir (sürenin dörtte birinde yolun yalnızca %6’sı). “Yavaş bitir” aynı sürede yolun %44’ünü alır ve sert durmaz. Sekme, sık açılan bir panel için kısa sürede yorucu olur.
LEVEL 2
Hareketli hedefi izlemek
kamera takibi ve kare hızı tuzağı

Problem: hedef yerinde durmuyor

🎮 Tween’in yetmediği yer
  • Tween için başlangıç, bitiş ve süre önceden bilinmeli.
  • Kamera oyuncuyu izliyor: hedef her kare değişiyor. Bitiş yok, süre yok.
  • Kamerayı oyuncuya yapıştırırsanız: karakter her zıpladığında, her titrediğinde bütün dünya sarsılır.
  • İstenen: kamera oyuncuya doğru gitsin; uzaktaysa hızlı, yakındaysa yavaş.

Herkesin bulduğu tek satır:

kamera += (hedef − kamera) * 0.1

“Her karede kalan yolun %10’unu kapat.” Yani lerp(kamera, hedef, 0,1). Hedef kıpırdasa da çalışır, durum saklamaz, güzel görünür.

Tuzak: “her karede”

Her karede kalan yol 0,9 ile çarpılıyor. n kare sonra kalan: 0,9ⁿ.

makine1 saniyede kare1 sn sonra kalan yolyolun yarısı ne zaman?
30 FPS300,9³⁰ = %4,2219 ms
60 FPS600,9⁶⁰ = %0,18110 ms
144 FPS1440,9¹⁴⁴ ≈ %046 ms
  • Aynı kod, 144 Hz ekranda beş kat daha sert bir kamera.
  • Kare hızı oyun içinde düşünce kamera o an tembelleşir: tam da ekranın kalabalıklaştığı anda.
  • G5’teki dersin aynısı: “kare başına” yazılan her şey makineye bağlıdır.

Çizimle: yarı ömür

0¼½1kalan yol: 10kalan yol: ½hkalan yol: ¼2hkalan yol: ⅛3hzaman (h = yarı ömür: kalan yolun yarıya inmesi için geçen süre)hedefekalan yol

Kamera hedefe doğru gidiyor. Kalan yol her h saniyede yarıya iniyor: 1, ½, ¼, ⅛… Hiçbir zaman tam sıfır olmaz ama hızla görünmez olur. Tasarımcının ayarladığı tek sayı h’dir (“kamera 0,15 saniyede yolun yarısını alsın”).

Fikir: oranı kareden değil, süreden hesapla

  • Davranışın özü şu: kalan yol üstel olarak azalıyor (her eşit sürede aynı oranda).
  • Bunu kare sayısı yerine saniyeyle söyleyelim: “kalan yol her h saniyede yarıya insin.” h: yarı ömür.
  • t saniye sonra kalan yol: 2−t / h. (t = h → ½; t = 2h → ¼; t = 3h → ⅛.)
  • Bu kare dt sürdüyse kalan yol 2−dt / h ile çarpılmalı; yani kapatılacak oran:

$$\begin{aligned}\text{oran} &= 1 - 2^{-dt / h} \\ x &\leftarrow \text{lerp}(x, \text{hedef}, \text{oran})\end{aligned}$$

  • Tasarımcı için de daha iyi bir ayar: “0,1” ne demek belli değil; “yarı ömür 0,15 saniye” ölçülebilir bir his.
  • Kısa kareler küçük oran, uzun kareler büyük oran alır; sonuç aynı eğridir.
Elle hesap: h = 0,1 sn, yol 100 birim
makinedtoran = 1 − 2^(−dt/h)0,1 sn’deki adım0,1 sn sonra kalan
60 FPS16,7 ms1 − 2^(−0,167) = 0,1096 adım100 · 0,891⁶ = 50,0
30 FPS33,3 ms1 − 2^(−0,333) = 0,2063 adım100 · 0,794³ = 50,0
10 FPS100 ms1 − 2^(−1) = 0,51 adım100 · 0,5 = 50,0

Üç makine de 0,1 saniye sonra tam yarı yolda. Neden? Üsler toplanır: 2^(−a) · 2^(−b) = 2^(−(a + b)). Süreyi nasıl bölerseniz bölün, çarpımın sonucu yalnızca toplam süreye bağlıdır.

Aynı şeyin başka yazımı: oran = 1 − e^(−k·dt). k = 0,693 / h.

Canlı: aynı kod, iki makine 🎥

  1. Ekranı okuyun: üstte dört top aynı sarı hedefi (kesikli çizgi) kovalıyor; hedef 1,6 saniyede bir karşı tarafa atlıyor. Altta son 4,8 saniyenin konum–zaman grafiği: sarı kesikli = hedef, kırmızı / gri / yeşil / mor = toplar.
  2. 30 FPS (başlangıç): kırmızı (kare başına %10, bu makine) gri eğrinin (aynı kod, 60 FPS’lik makine) belirgin biçimde gerisinde. Aynı satır, iki farklı kamera.
  3. Kare hızını 144 yapın: kırmızı bu kez griden önde, neredeyse hedefe yapışık. 60 yapın: üst üste.
  4. Bütün bunlar olurken yeşile bakın: kare hızını ne yaparsanız yapın gri eğrinin üstünde. 10 FPS’te basamak basamak ilerler ama basamakların köşeleri hep aynı eğrinin üzerindedir.
  5. Mor (SmoothDamp) farklı bir şekil çizer: S harfi. Yeşil hedef atlar atlamaz en yüksek hızıyla fırlar; mor önce hızlanır. Kamera için mor daha “sinematik”, yeşil daha “atik”.
  6. Hedefi “fareyi izlesin” yapıp fareyi sağa sola sallayın: hangi top elinize en çok “bağlı” hissettiriyor?
🔎 DEMODA DENEYİN
  1. Ekranı okuyun: üstte dört top aynı sarı hedefi (kesikli çizgi) kovalıyor; hedef 1,6 saniyede bir karşı tarafa atlıyor. Altta son 4,8 saniyenin konum–zaman grafiği: sarı kesikli = hedef, kırmızı / gri / yeşil / mor = toplar.
  2. 30 FPS (başlangıç): kırmızı (kare başına %10, bu makine) gri eğrinin (aynı kod, 60 FPS’lik makine) belirgin biçimde gerisinde. Aynı satır, iki farklı kamera.
  3. Kare hızını 144 yapın: kırmızı bu kez griden önde, neredeyse hedefe yapışık. 60 yapın: üst üste.
  4. Bütün bunlar olurken yeşile bakın: kare hızını ne yaparsanız yapın gri eğrinin üstünde. 10 FPS’te basamak basamak ilerler ama basamakların köşeleri hep aynı eğrinin üzerindedir.
  5. Mor (SmoothDamp) farklı bir şekil çizer: S harfi. Yeşil hedef atlar atlamaz en yüksek hızıyla fırlar; mor önce hızlanır. Kamera için mor daha “sinematik”, yeşil daha “atik”.
  6. Hedefi “fareyi izlesin” yapıp fareyi sağa sola sallayın: hangi top elinize en çok “bağlı” hissettiriyor?

Kod: kare hızından bağımsız yaklaşma

🎒 Kodu okuyalım

ifadene demekneden böyle
pow(2, -dt / yariOmur)bu karenin sonunda kalan yolun oranıdt = yarı ömür ise tam 0,5. dt çok küçükse 1’e yakın (neredeyse hiç ilerleme), çok büyükse 0’a yakın (neredeyse varış). Asla eksi ya da 1’den büyük olmaz.
1 - …kapatılan oranlerp’in t’si. Her zaman 0 ile 1 arasında: kamera hedefi asla aşmaz.
lerp(x, hedef, oran)şimdiki yerden hedefe doğruDikkat: başlangıç noktası her kare değişiyor (x’in kendisi). Tween’de başlangıç sabitti; fark bu.
translate(width/2 - kamera.x, …)kamera = dünyayı ters yöne kaydırmakKamera sağa giderse dünya sola kayar. Kamera konumu ekranın ortasına gelir.
Python: altı adım / tek adımikisi de 50,0Önermenin deneyle kanıtı. Aynı deney sabit 0,1 ile 10,0 ve 46,9 verir.
C#: 5f * Time.deltaTimeyaygın “yarım” düzeltme1 − e^(−5·dt) ifadesinin küçük dt için yaklaşığıdır. dt = 0,25 sn’lik bir takılmada oran 1,25 olur: kamera hedefin öbür tarafına atlar.
Önermeyaklas fonksiyonunu toplam T süre boyunca hangi adımlarla çağırırsanız çağırın (sabit hedef için) kalan yol tam 2−T / h katına iner. Kare başına sabit oranla (r) ise kalan yol (1 − r)kare sayısı’dır ve kare hızına bağlıdır.

Oyunlarda: Unity’nin SmoothDamp’i

Kaynak: UnityCsReference, Mathf.cs. İlk yorum satırı özgün koddan: yöntem Game Programming Gems 4’teki (2004) “kritik sönümlü yay” bölümünden.

🎮 Satır satır
  • deltaTime bir parametre: fonksiyon geçen süreyi bilmeden çalışmıyor. Kare hızından bağımsızlık tasarımın içinde.
  • exp = 1 / (1 + x + 0,48x² + 0,235x³): e−x’in ucuz bir yaklaşığı. Yani içinde yine üstel azalma var; bizim 2−dt / h’ın akrabası.
  • Farkı: currentVelocity. Fonksiyon hızı da saklıyor ve yumuşatıyor; bu yüzden hareket aniden başlamaz (demodaki mor S eğrisi).
  • Fiziksel karşılığı: hedefe bir yayla bağlı, tam kararında sönümlenen bir kütle. Yay çeker, sönüm salınımı engeller: en hızlı “taşmadan varış”.
  • “Prevent overshooting”: büyük dt’de hedefi geçerse hedefe sabitle. G5’teki “dev kareyi kırp”ın kardeşi.
  • smoothTime ≈ hedefe varma süresi. Kamera için tipik 0,1–0,3 sn.

Unity’nin kamera sistemi Cinemachine’deki “Damping” ayarları ve Unreal’ın “Camera Lag” seçeneği aynı ailedendir.

🧪 Canlı laboratuvar: kare hızından bağımsız takip

Başlangıç kodunda mavi top (144 FPS) hedefe yapışır, kırmızı (20 FPS) geride kalır; üstteki “iki makine arasındaki fark” satırı büyük bir sayı gösterir. Düzeltme iki satır: const oran = 1 - Math.pow(2, -dt / yariOmur); ve return x + (hedef - x) * oran;. Kontrol: dt = yarı ömür ise oran tam 0,5.
Quiz 2 · takip
Kamera kodunuz kamera = lerp(kamera, oyuncu, 0.08); her karede çalışıyor. Bir oyuncu “240 Hz monitörde kamera çok sert, başım dönüyor” diye yazdı. Sebep?
Kalan yol her karede 0,92 ile çarpılıyor: 60 FPS’te saniyede 60 kez, 240 FPS’te 240 kez. Yarı ömür 139 ms’den 35 ms’ye iniyor. 0,02 yapmak yalnızca o oyuncunun sorununu çözer ve 60 Hz’teki herkesin kamerasını tembelleştirir. Doğrusu oranı dt’den hesaplamak: 1 − 2^(−dt / yarıÖmür).
LEVEL 3
Bézier eğrileri
lerp’lerin lerp’i

Problem: düz çizgi yetmez

🎮 Kavis isteyen işler
  • El bombası, ok, basketbol topu: yay çizen atışlar (fizik simüle etmeden).
  • Kart oyunu: kart yığından ele, elden masaya kavisle uçar (Hearthstone, Slay the Spire, Balatro).
  • Toplanan altınlar puan göstergesine doğru savrularak gider.
  • Hedef göstergesi: “bu büyü şuraya düşecek” oku.
  • Yollar, nehirler, raylar; yazı tipleri; arayüzdeki her yuvarlak köşe.
İlk akla gelen: çok sayıda nokta
  • Eğriyi 50 noktayla elle tarif et, aralarını lerp et.
  • Biraz değiştirmek istediniz: 50 noktayı tek tek oynatın.
  • Yakınlaşınca köşeler görünür; uzaklaşınca 50 nokta israf.
  • İki ucu oynak bir eğri (atıcı ve hedef her an değişiyor) için noktaları kim hesaplayacak?

İstenen: eğriyi birkaç noktayla tarif etmek; noktaları oynatınca eğrinin akıllıca uyması; istenen sıklıkta nokta üretebilmek.

1959’da Citroën’de Paul de Casteljau, birkaç yıl sonra Renault’da Pierre Bézier aynı çözümü buldu: otomobil kaportasının kıvrımlarını birkaç “kontrol noktası”yla tarif etmek.

Çizimle: üç lerp bir eğri çizer

t = 0,25P₀P₁P₂ABkırmızı nokta = lerp(A, B, t)t = 0,5P₀P₁P₂ABkırmızı nokta = lerp(A, B, t)t = 0,75P₀P₁P₂ABkırmızı nokta = lerp(A, B, t)A = lerp(P₀, P₁, t) · B = lerp(P₁, P₂, t) · t büyüdükçe A ve B kenarlarda ilerler, kırmızı nokta mavi eğriyi çizer

Üç kontrol noktası, üç farklı t. Önce iki kenarda t kadar ilerleyip A ve B bulunur; sonra A ile B arasında yine t kadar ilerlenir. Bulunan kırmızı nokta eğrinin üstündedir.

Fikir: De Casteljau — lerp et, sonuçları yine lerp et

  • Üç nokta (karesel Bézier): P₀, P₁, P₂ ve bir t.
  • A = lerp(P₀, P₁, t) ve B = lerp(P₁, P₂, t): iki kenarda t kadar ilerle.
  • Sonuç = lerp(A, B, t): A ile B’yi birleştiren doğruda yine t kadar.
  • t 0’dan 1’e giderken bu son nokta bir eğri çizer: P₀’da başlar, P₂’de biter, P₁’e doğru bükülür ama ona değmez.
  • Dört nokta (kübik Bézier): bir tur daha. 3 lerp → 2 lerp → 1 lerp. En yaygın tür: iki uç + her uca bir “tutamaç”.
  • Eğri P₀’dan P₁ yönüne doğru çıkar, P₃’e P₂ yönünden girer. Tutamaç uzadıkça eğri o yöne daha çok “asılır”.
Elle izleme: P₀ (0,0) · P₁ (0,4) · P₂ (4,4) · P₃ (4,0)
turt = 0,5t = 0,25
1. tur (3 lerp)A (0, 2) · B (2, 4) · C (4, 2)A (0, 1) · B (1, 4) · C (4, 3)
2. tur (2 lerp)D (1, 3) · E (3, 3)D (0,25, 1,75) · E (1,75, 3,75)
3. tur (1 lerp)(2, 3)(0,625, 2,25)

Örnek, 1. tur, t = 0,25: B = lerp(P₁, P₂, 0,25) = (0 + 4·0,25, 4) = (1, 4).

Eğri (0,0)’dan yukarı doğru çıkıyor (P₁ yönü), tepesi (2, 3)’te; kontrol noktalarının yüksekliği olan 4’e hiç ulaşmıyor.

Açık formül (aynı sonuç): (1−t)³·P₀ + 3(1−t)²t·P₁ + 3(1−t)t²·P₂ + t³·P₃. Dört ağırlığın toplamı hep 1: eğri, noktaların ağırlıklı ortalamasıdır.

Canlı: kontrol noktaları ve iskele ✏️

  1. Ekranı okuyun: siyah eğri Bézier; beyaz halkalar kontrol noktaları (sürüklenir). Gri kesikli çizgi kontrol çokgeni. Mavi noktalar 1. turun, yeşiller 2. turun lerp sonuçları; kırmızı nokta eğrinin t anındaki yeri.
  2. t sürgüsünü yavaşça 0’dan 1’e çekin: mavi noktalar gri kenarlarda, yeşiller mavi çizgide, kırmızı yeşil çizgide hep aynı oranda ilerliyor.
  3. P₁’i sürükleyin: eğrinin P₀’dan çıkış yönü değişiyor ama P₃’teki giriş yönü değişmiyor. Tutamacı uzatın: eğri o yöne daha çok asılıyor.
  4. P₁ ve P₂’yi çaprazlayın: eğri ilmek atar. Dördünü bir doğruya dizin: eğri düz çizgi olur.
  5. Eğri hiçbir zaman dört noktanın oluşturduğu çokgenin dışına çıkmaz (G1’deki dışbükey örtü): çarpışma ve ekran dışı testleri için ucuz bir sınır.
  6. “eşit t adımları”nı açın: mor noktalar t = 0, 0,05, 0,10… Uçlarda seyrek, kıvrımda sık ya da tersi: eşit t, eşit yol değildir. Bu sorunu son bölümde çözeceğiz.
🔎 DEMODA DENEYİN
  1. Ekranı okuyun: siyah eğri Bézier; beyaz halkalar kontrol noktaları (sürüklenir). Gri kesikli çizgi kontrol çokgeni. Mavi noktalar 1. turun, yeşiller 2. turun lerp sonuçları; kırmızı nokta eğrinin t anındaki yeri.
  2. t sürgüsünü yavaşça 0’dan 1’e çekin: mavi noktalar gri kenarlarda, yeşiller mavi çizgide, kırmızı yeşil çizgide hep aynı oranda ilerliyor.
  3. P₁’i sürükleyin: eğrinin P₀’dan çıkış yönü değişiyor ama P₃’teki giriş yönü değişmiyor. Tutamacı uzatın: eğri o yöne daha çok asılıyor.
  4. P₁ ve P₂’yi çaprazlayın: eğri ilmek atar. Dördünü bir doğruya dizin: eğri düz çizgi olur.
  5. Eğri hiçbir zaman dört noktanın oluşturduğu çokgenin dışına çıkmaz (G1’deki dışbükey örtü): çarpışma ve ekran dışı testleri için ucuz bir sınır.
  6. “eşit t adımları”nı açın: mor noktalar t = 0, 0,05, 0,10… Uçlarda seyrek, kıvrımda sık ya da tersi: eşit t, eşit yol değildir. Bu sorunu son bölümde çözeceğiz.

Kod: Bézier noktası

🎒 Kodu okuyalım

ifadene demekneden böyle
lerpN(p, q, t)noktalar için lerpx ve y ayrı ayrı. 3B’de z de eklenir; algoritma değişmez.
üç tur: 3 + 2 + 1kübik Bézier = 6 lerpn + 1 kontrol noktası için n(n + 1)/2 lerp. Derece büyüdükçe pahalılaşır ve kontrolü zorlaşır; pratikte hep kübik parçalar uç uca eklenir.
for (i = 0..30)eğriyi 30 doğru parçasıyla çizEkran kartı eğri çizmez; doğru çizer. Parça sayısı = kalite ayarı.
firlat(…)P₁ ve P₂ uçlardan hesaplanıyorAtıcı ve hedef her kare değişse de yay kendini yeniden kurar. yukseklik tek ayar.
Python: bezier_formulBernstein ağırlıklarıyla açık formülDe Casteljau daha anlaşılır ve sayısal olarak sağlam; açık formül biraz daha hızlı. Motorlar genelde açık formülü kullanır.
LerpUnclamped (C#)sıkıştırmasızt zaten 0–1 arasında; boşuna sıkıştırma maliyeti ödemeyelim.
ÖnermeKübik Bézier eğrisi: (1) P₀’da başlar, P₃’te biter; (2) P₀’daki teğeti P₁ − P₀, P₃’teki teğeti P₃ − P₂ yönündedir; (3) tamamı dört kontrol noktasının dışbükey örtüsünün içindedir. İki parçanın ek yeri köşesiz olsun istiyorsanız birleşme noktası ile iki yanındaki tutamaçlar aynı doğru üzerinde olmalıdır.

Oyunlarda: Godot’nun Bézier’si ve her yerdeki tutamaçlar

Kaynak: Godot Engine 4.3, core/math/math_funcs.h (MIT lisansı). Yorum satırı özgün koddan.

🎮 Nerede karşınıza çıkar
  • Godot: yukarıdaki fonksiyon, slayttaki açık formülün aynısı (omt = “one minus t”). Curve2D’deki her noktanın bir “in” ve bir “out” tutamacı vardır: komşu iki nokta + iki tutamaç = bir kübik parça. Path2D ile sahnede fareyle çizilir.
  • Unity: Inspector’daki AnimationCurve penceresi ve Splines paketi: sürüklediğiniz o küçük kollar P₁ ve P₂’dir.
  • Yazı tipleri: ekrandaki her harf Bézier parçalarından oluşur (TrueType’ta karesel, OpenType/PostScript’te kübik). Oyun motoru harfi büyütürken bu eğrileri yeniden örnekler.
  • Vektör çizim: Illustrator / Inkscape / Figma’daki “kalem” aracı = kübik Bézier düzenleyici. SVG’deki C komutu.
  • CSS: cubic-bezier(.17, .67, .83, .67): az önceki yumuşatma eğrilerinin kendisi de bir Bézier ile tarif edilir.
  • Yarış oyunları: pistin orta hattı spline’dır; yol ağı ve bariyerler ondan üretilir.

🐍 Laboratuvar: De Casteljau

Başlangıç kodu uçları düz çizgiyle birleştiriyor. Üç tur: a, b, c = lerp2(p0, p1, t), lerp2(p1, p2, t), lerp2(p2, p3, t); d, e = lerp2(a, b, t), lerp2(b, c, t); return lerp2(d, e, t). Kontrol: (0,0) (0,4) (4,4) (4,0), t = 0,5 → [2, 3].
Quiz 3 · Bézier
Bir kübik Bézier eğrisinin kontrol noktalarından P₁’i (ikinci nokta) fareyle uzağa sürüklüyorsunuz. Aşağıdakilerden hangisi değişmez?
Bézier eğrisi her zaman P₀’da başlar ve P₃’te biter; aradaki kontrol noktaları yalnızca “çeker”. P₁ oynayınca çıkış yönü (P₁ − P₀), eğrinin orta noktası ve uzunluğu değişir. P₃’e giriş yönü (P₃ − P₂) ise P₁’den etkilenmez.

🎬 Ara: Bézier eğrilerinin güzelliği

The Beauty of Bézier Curves
Freya Holmér · 24 dk 25 sn · YouTube’da aç

Az önceki “lerp’lerin lerp’i” iskelesinin en güzel anlatımlarından biri: de Casteljau, türevler, tutamaçlar ve oyun araçlarındaki yerleri. Görselleştirmeler slaytlardaki demoyla birebir aynı fikirde.

🤔 İzlerkenVideoda dört kontrol noktasından eğriye kaç lerp turuyla ulaşılıyor? Teğet (türev) neden tutamaçların yönünü veriyor? Eğri üzerinde sabit hızla gitmek neden zor; bir sonraki bölümdeki çözümle karşılaştırın.
LEVEL 4
Catmull–Rom ve sabit hız
noktalardan geçen yol, üzerinde düzgün hareket

Problem: “şu noktalardan geçsin”

🎮 Tasarımcının isteği
  • Devriye yolu: muhafız şu beş noktadan geçsin (Y19).
  • Kamera rayı: ara sahnede kamera şu konumlardan süzülerek geçsin.
  • Yarış pisti / tren rayı / uçuş rotası: haritaya noktalar koydum; yol hepsinden geçsin.
  • Kule savunma: düşmanlar şu kıvrımlı patikayı izlesin.
  • Yol bulma sonrası (Y8, Y9): A*’ın verdiği köşeli yolu yumuşat.
Eldeki araçlar neden yetmiyor?
  • Noktalar arası lerp: her noktada köşe. Araba aniden döner, kamera “tık” diye yön değiştirir.
  • Bézier: eğri kontrol noktalarından geçmez. Tasarımcı “buradan geçsin” dediği noktayı koyar, eğri oradan teğet geçer.
  • Bézier parçalarını uç uca eklemek mümkün; ama her nokta için iki tutamacı elle ayarlamak gerekir, yoksa ek yerleri köşeli olur.

İstenen: yalnızca noktaları ver; eğri hepsinin içinden geçsin ve köşesiz olsun. Tutamaçları eğri kendisi bulsun.

1974’te Edwin Catmull (sonradan Pixar’ın kurucularından) ve Raphael Rom tam bunu yapan eğriyi yayımladı.

Çizimle: noktalardan geçen eğri

P0P1P2P3P4P5P₂’deki yön (teğet)P₁–P₃ doğrusuna paralelmavi eğri bütün ara noktalardan geçer; her noktadaki yön, iki komşusunu birleştiren doğrudan alınır (ilk ve son nokta yalnızca yön verir)

Bézier eğrisi kontrol noktalarına yalnızca yaklaşır; Catmull–Rom eğrisi ise verilen noktaların içinden geçer. Yarış pisti, kamera rayı, devriye yolu gibi “şu noktalardan geçsin” denen her yerde bu kullanılır.

Fikir 1: Catmull–Rom — teğeti komşulardan al

  • Dört ardışık nokta al: p₀, p₁, p₂, p₃. Eğri parçası p₁ ile p₂ arasını çizer.
  • p₀ ve p₃’ten geçmez; onlar yalnızca yönü belirler.
  • Kural: eğrinin p₁’deki yönü, komşularını birleştiren doğruya paralel olsun: teğet = (p₂ − p₀) / 2. p₂’de: (p₃ − p₁) / 2.
  • Bir sonraki parça p₁, p₂, p₃, p₄ ile çizilir ve p₂’de aynı teğeti kullanır: ek yeri kendiliğinden köşesiz.
  • Aslında tutamaçları otomatik seçilmiş bir Bézier’dir: P₁ = p₁ + (p₂ − p₀)/6, P₂ = p₂ − (p₃ − p₁)/6.

$$\begin{aligned}P(t) = \tfrac{1}{2}\big(&2p_1 + (-p_0 + p_2)\,t \\ &+ (2p_0 - 5p_1 + 4p_2 - p_3)\,t^2 \\ &+ (-p_0 + 3p_1 - 3p_2 + p_3)\,t^3\big)\end{aligned}$$

Elle izleme (tek eksen): p₀ = 0, p₁ = 1, p₂ = 3, p₃ = 4
terimkatsayıt = 0,5 için
sabit2·p₁ = 22
t−p₀ + p₂ = 33 · 0,5 = 1,5
t²2·0 − 5·1 + 4·3 − 4 = 33 · 0,25 = 0,75
t³−0 + 3·1 − 3·3 + 4 = −2−2 · 0,125 = −0,25
toplam × ½4 · ½ = 2

Kontrol: t = 0 → ½·2 = 1 = p₁ ✓. t = 1 → ½·(2 + 3 + 3 − 2) = 3 = p₂ ✓. Eğri iki noktadan da geçiyor; t = 0,5’te tam ortada (2).

Vektörler için: aynı formül x’e ve y’ye ayrı ayrı. Formülü ezberlemeyin; her motorda bir satırla çağrılır.

Fikir 2: sabit hız — yay uzunluğu tablosu

Sorun: t eşit artıyor, yol eşit artmıyor

Az önceki Bézier’yi (0,0)…(4,0) dört eşit t aralığıyla örnekleyelim:

tnoktabu aralıkta gidilen yol
0(0, 0)—
0,25(0,63, 2,25)2,34
0,5(2, 3)1,57
0,75(3,38, 2,25)1,57
1(4, 0)2,34

Aynı sürede uçlarda 2,34, ortada 1,57 birim: nesne uçlarda 1,5 kat hızlı. Catmull–Rom’da durum daha kötü: noktalar arası uzaklık farklıysa her parça aynı sürede geçilir; uzun parçada araba fırlar, kısa parçada sürünür.

Çözüm: tabloyu bir kez kur, her kare ara
  • Eğriyi sık aralıklarla örnekle; noktalar arası uzaklıkları biriktir: tablo[k] = baştan k. örneğe kadar yol.
  • Yukarıdaki örnekte tablo: 0 · 2,34 · 3,90 · 5,47 · 7,80. Toplam yol 7,80.
  • Her kare: yol += hız · dt. Soru: “yolun 3. birimi hangi t’de?”
  • Tablo sıralı → ikili arama: 3, 2,34 ile 3,90 arasında (1. ve 2. satır).
  • İki satırın arasında ters lerp: (3 − 2,34) / (3,90 − 2,34) = 0,42 → t = lerp(0,25, 0,5, 0,42) = 0,36.
  • Gerçekte 5 değil 100–1.000 örnek alınır; hata gözle görülmez.

Bu sunumun bütün araçları bir arada: örnekleme (lerp’ler), biriktirme, ikili arama (Arama Algoritmaları sunumu), ters lerp, lerp.

Canlı: pist çiz, araba sür 🏎️

  1. Ekranı okuyun: gri şerit pist; numaralı halkalar yol noktaları. Kırmızı araba pisti dolanıyor. Mor noktalar pist üzerinde örnekler. Alt satırda pistin uzunluğu, tur sayısı, anlık hız ve son turdaki en az / en çok hız.
  2. W gaz, S fren. Bir halkayı sürükleyin: pist her noktanın içinden geçmeye devam ediyor ve hiç köşe yapmıyor. Boş bir yere tıklayın: yeni nokta eklenir.
  3. Yolu “doğrusal” yapın: araba her noktada aniden dönüyor. Geri alın.
  4. “sabit hız” kutusunu kapatın: mor noktalar artık eşit t adımlarında. İki halkayı birbirine yaklaştırıp ikisini uzaklaştırın: araba uzun parçada fırlıyor, kısa parçada sürünüyor. Alttaki en az / en çok hız arasındaki fark birkaç katına çıkar.
  5. Kutuyu yeniden açın: mor noktalar eşit aralıklı; en az ve en çok hız neredeyse aynı. Araba virajda da düzlükte de aynı hızda.
  6. Bir halkayı komşusunun çok yakınına getirin: eğri orada küçük bir ilmek atabilir. Catmull–Rom’un bilinen kusuru; çaresi Kaynaklar’da (“centripetal” sürüm).
🔎 DEMODA DENEYİN
  1. Ekranı okuyun: gri şerit pist; numaralı halkalar yol noktaları. Kırmızı araba pisti dolanıyor. Mor noktalar pist üzerinde örnekler. Alt satırda pistin uzunluğu, tur sayısı, anlık hız ve son turdaki en az / en çok hız.
  2. W gaz, S fren. Bir halkayı sürükleyin: pist her noktanın içinden geçmeye devam ediyor ve hiç köşe yapmıyor. Boş bir yere tıklayın: yeni nokta eklenir.
  3. Yolu “doğrusal” yapın: araba her noktada aniden dönüyor. Geri alın.
  4. “sabit hız” kutusunu kapatın: mor noktalar artık eşit t adımlarında. İki halkayı birbirine yaklaştırıp ikisini uzaklaştırın: araba uzun parçada fırlıyor, kısa parçada sürünüyor. Alttaki en az / en çok hız arasındaki fark birkaç katına çıkar.
  5. Kutuyu yeniden açın: mor noktalar eşit aralıklı; en az ve en çok hız neredeyse aynı. Araba virajda da düzlükte de aynı hızda.
  6. Bir halkayı komşusunun çok yakınına getirin: eğri orada küçük bir ilmek atabilir. Catmull–Rom’un bilinen kusuru; çaresi Kaynaklar’da (“centripetal” sürüm).

Kod: Catmull–Rom yolu ve yay uzunluğu tablosu (1/2)

Kod: Catmull–Rom yolu ve yay uzunluğu tablosu (2/2)

🎒 Kodu okuyalım

ifadene demekneden böyle
floor(u) ve u - floor(u)hangi parça · parçanın neresindeTek bir sayı (u) bütün yolu dolaşır: 3,25 = “3. parçanın dörtte biri”.
(i + k + n) % nsarmalayan indisKapalı pistte 0. noktanın “önceki”si son noktadır. + n: JavaScript’te eksi sayının kalanı eksi çıkar.
tablo.push(tablo[k-1] + dist(…))birikimli toplamTablo kendiliğinden sıralıdır (uzunluklar eksi olamaz): ikili aramanın ön koşulu bedavaya sağlanır.
while (ust - alt > 1)ikili aramaSonunda tablo[alt] ≤ s < tablo[ust] ve ikisi komşu. 264 satırlık tabloda en çok 9 adım.
(s - tablo[alt]) / (tablo[ust] - tablo[alt])ters lerpİki örnek arasında düz çizgi varsayıyoruz. Örnek sayısı arttıkça varsayımın hatası küçülür.
yol % toplamtur atınca başa dönAçık yolda (devriye) bunun yerine uçta yön değiştirin ya da durun.
ÖnermeN örnekli yay uzunluğu tablosu N adımda kurulur (yol değişmedikçe bir kez) ve her sorgu log₂ N karşılaştırma ister. Tabloyla gidilen hız, örnekler arasındaki doğrusal yaklaşımın hatası kadar sapar: demodaki pistte (512 örnek) en hızlı ve en yavaş an arasındaki fark yaklaşık %3’tür; tablo olmadan (eşit t adımlarıyla) aynı pistte 2,7 kat.

Oyunlarda: Godot’nun yol izleyicisi

Kaynak: Godot Engine 4.3, math_funcs.h ve curve.cpp (MIT lisansı). “Binary search…” yorumu özgün koddan.

🎮 Satır satır
  • cubic_interpolate: slayttaki Catmull–Rom formülünün aynısı (p_pre = p₀, p_from = p₁, p_to = p₂, p_post = p₃). GDScript’te a.cubic_interpolate(b, pre, post, t).
  • “Baked” (pişirilmiş): Godot eğriyi önceden küçük parçalara böler; baked_dist_cache bizim yay uzunluğu tablomuz. 2B’de örnekler arası varsayılan aralık 5 piksel (bake_interval).
  • _find_interval: tabloda ikili arama; ardından frac = ters lerp. Bizim mesafedenU fonksiyonumuzun motor sürümü.
  • PathFollow2D.progress piksel cinsinden yoldur: progress += hiz * delta yazdığınızda nesne sabit hızla gider, çünkü arkada bu arama çalışır.
  • Pişirilmiş noktalar arasında cubic seçeneğiyle yine Catmull–Rom, yoksa düz lerp kullanılır.

Unity’nin Splines paketi, Unreal’ın Spline bileşeni (“distance along spline”) aynı tabloyu tutar. Yarış oyunlarında rakip YZ’nin “ideal çizgisi” ve oyuncunun pistin yüzde kaçında olduğu bu tabloyla ölçülür (Y17).

🐍 Laboratuvar: Catmull–Rom (tek eksen)

Formülü yorum satırından aynen yazın; Python’da üs t ** 2 ya da t * t. Kontrol: (0, 1, 3, 4; t = 0,5) → 2; t = 0 → p1; t = 1 → p2. Başlangıç kodu uçlarda doğru sonuç verir ama (0, 10, 0, 10; t = 0,25) gibi “zikzak” örneklerde tutmaz: eğri komşulara bakarak şişer.
Quiz 4 · yol izleme
Kule savunma oyununuzda düşmanlar bir Catmull–Rom yolunu u += 0.5 * dt ile izliyor. Oyuncular “düşmanlar bazı yerlerde hızlanıyor, kulelerim ıskalıyor” diyor. Sebep ve çözüm?
Her parça u’da 1 birimdir ve aynı sürede geçilir; uzun parçada düşman hızlı, kısa parçada yavaştır. Çözüm: yolu bir kez örnekleyip birikimli uzunluk tablosu kurmak, her kare yol += hız * dt yapıp tablodan (ikili arama + ters lerp) u’yu bulmak. Bézier’de de aynı sorun vardır.
LEVEL 5
Hepsi bir arada
tam kod, araçlar, kapanış

📦 Tam kod: p5.js ile pist, araba ve kamera

Döngünün iskeleti (çizim sırası sadeleştirildi). Dört araç dört satırda: tablo, eğri, takip, yumuşatma.

🎮 Çalıştırın, kopyalayın, bozun

▶ Eksiksiz örneği aç — yaklaşık 70 satır: W / S gaz ve fren; K kamerayı yumuşak / sert yapar; H sabit hızı açar / kapatır.

Deneyin:

  • NOKTALAR’ı değiştirip kendi pistinizi çizin.
  • Kameranın yarı ömrünü 0,05 ve 0,6 yapın.
  • Kamerayı arabanın biraz önüne baktırın: hedef = araba + yön × hız × 0,3.
  • Tur yazısının yumuşatmasını “sekerek” ile değiştirin.
  • İkinci bir araba ekleyin: aynı pist, farklı yol ve hiz.

🧰 Motorlarda ve kütüphanelerde

p5.jslerp · map · norm · lerpColor · bezier / bezierPoint · curve / curvePointcurve ailesi Catmull–Rom’dur. Yumuşatma fonksiyonları hazır değil: bu sunumdaki tek satırlıkları kopyalayın.
UnityMathf.Lerp / LerpUnclamped / InverseLerp / SmoothStep / SmoothDamp · AnimationCurveTween için DOTween, LeanTween ya da PrimeTween eklentileri. Yollar için Splines paketi; kamera için Cinemachine.
Godotlerp · inverse_lerp · remap · smoothstep · Tween · Curve2D / Path2D / PathFollow2DTween motorun içinde: create_tween().tween_property(…); geçiş türleri Penner adlarıyla.
UnrealFMath::Lerp · FInterpTo · Timeline · Spline Component · Spring Arm (“Camera Lag”)FInterpTo dt alan hazır yaklaşma fonksiyonu.
Web / CSStransition: transform .3s ease-out · cubic-bezier(…)Oyun arayüzlerini HTML ile yapıyorsanız yumuşatma tarayıcıda hazır.
Görerek seçineasings.netBütün Penner eğrilerinin grafiği ve canlı önizlemesi.

Pratik kural: süresi belli geçiş → tween + yumuşatma. Hareketli hedef → üstel yaklaşma ya da SmoothDamp. Kontrol edilebilir kavis → Bézier. Noktalardan geçen yol → Catmull–Rom + yay uzunluğu tablosu.

🤖 Bu konuyu bir YZ kod asistanıyla yazarken

Sık yapılan hatalar — kontrol edin
  • x = lerp(x, hedef, 0.1) (kare hızına bağlı takip)
  • lerp(a, b, hiz * dt): büyük dt’de oran 1’i aşar
  • Tween’de başlangıç değerini saklamamak: lerp(x, hedef, t) yazıp x’i her kare güncellemek (hareket baştan hızlı, sona doğru tuhaf)
  • Unity’de taşan yumuşatmayı Lerp ile kullanmak (keser)
  • Açıları düz lerp etmek (350° → 10° uzun yoldan döner)
  • Eğri üzerinde t += hiz * dt ile “sabit hız” beklemek
  • Yay uzunluğu tablosunu her kare yeniden kurmak
İyi bir istek (prompt) örneği

“p5.js, kütüphane yok. (1) yumusatma nesnesi: linear, easeInQuad, easeOutQuad, smoothstep, easeOutBack; hepsi 0–1 alır. (2) tween(a, b, gecen, sure, f). (3) yaklas(x, hedef, yariOmur, dt): 1 − 2^(−dt/yariOmur) oranıyla; kare hızından bağımsız. (4) Kapalı Catmull–Rom yolu: yolNoktasi(u); birikimli yay uzunluğu tablosu ve ikili aramayla mesafedenU(s). (5) Araba yolu sabit hızla izlesin; kamera yaklas ile takip etsin. (6) Hata ayıklama: bir tuşla eşit mesafeli noktaları çiz; ekrana anlık hızı yaz. (7) Test: yaklas 20 ve 144 adımda 1 saniye sonunda aynı sonucu vermeli; arabanın ölçülen hızı tur boyunca %2’den fazla oynamamalı.”

  • “Smooth” demeyin; hangi yöntemi istediğinizi söyleyin.
  • Kare hızı testini mutlaka isteyin: asistanların en sık ürettiği hata budur.

💬 Tartışma soruları

Yanınızdakiyle 2 dakika konuşun, sonra sınıfça tartışalım
  1. Sevdiğiniz bir oyunun menülerini, vuruş efektlerini ya da puan sayaçlarını gözünüzün önüne getirin. Hangi yumuşatmalar kullanılmış olabilir? Hepsi doğrusal olsaydı oyun nasıl hissettirirdi?
  2. “Juice” ne zaman fazla gelir? Her şeyin sektiği, sarsıldığı, parladığı bir oyun düşünün. Okunabilirlik, erişilebilirlik (hareket hassasiyeti olan oyuncular) ve rekabetçi oyunlar açısından tartışın.
  3. Kamera oyuncuya sıkı sıkıya mı yapışmalı, yumuşakça mı izlemeli? Bir platform oyunu, bir yarış oyunu ve bir nişancı oyunu için ayrı ayrı düşünün.
  4. Ağ oyununda rakibi 100 ms geçmişte görüyorsunuz ama akıcı; ya da “şimdiki” yerinde ama kesik kesik. Hangisini seçerdiniz? Vurduğunuzu sandığınız rakibi ıskalamanızla bunun ilgisi ne? (Ağ senkronizasyonunun ana sorusu.)
  5. Kule savunmada düşmanların virajda yavaşlaması bir hata mı, yoksa bilerek kullanılabilecek bir tasarım öğesi mi?

🚀 Proje ve araştırma önerileri

  1. [kolay] Sulu tuğla kırma — Basit bir tuğla kırma oyununa sırayla ekleyin: tuğlaların yumuşatmayla gelişi, raketin esnemesi, topun çarpınca büyümesi, puanın sayarak artması. Her adımı tuşla açılıp kapanır yapın (Juice it or lose it).
  2. [kolay] Yumuşatma seçici — Bu sunumdaki yarış demosunu kendi 10 fonksiyonunuzla yeniden yazın; her biri için bir kullanım yeri önerin.
  3. [orta] İyi bir 2B kamera — Platform karakteri için: üstel takip + ileriye bakma (hız yönünde ofset) + ölü bölge (küçük hareketlerde kıpırdama) + seviye sınırlarına sıkıştırma. Her biri tuşla açılıp kapansın.
  4. [orta] Kule savunma patikası — Fareyle çizilen Catmull–Rom patika; düşmanlar sabit hızla izlesin; kuleler düşmanın ileride olacağı yere nişan alsın (tablo sayesinde kolay: yol + hız × süre).
  5. [zor] Pist düzenleyici — Catmull–Rom orta hattan pist kenarlarını üretin (her örnekte teğete dik vektör, G1); tur süresi ölçün; “ideal çizgi”yi ayrı bir eğri olarak çizdirin (Y17).
  6. [araştırma] Catmull–Rom türleri — Düzgün (uniform), kirişsel (chordal) ve merkezcil (centripetal) parametrelemeyi aynı noktalarda karşılaştırın: ilmekler ve taşmalar nerede oluşuyor? (Yuksel, Schaefer ve Keyser’in makalesi.)

Neler öğrendik? 🎒

  • Lerp: a + (b − a)·t. “Yolun yüzde kaçı?” Ters lerp oranı bulur; ikisi birlikte aralık eşler. Sayı, vektör, renk: hepsinde aynı.
  • Yumuşatma: lerp’e dokunma, t’yi eğ. Gelen şeyler “yavaş bitir”, taşınan şeyler smoothstep, vurgular “taşıp dön”. Süre ve varış değişmez; his değişir.
  • Hareketli hedef: kare başına sabit oran kare hızına bağlıdır. Oranı süreden hesapla: 1 − 2^(−dt / yarı ömür). Daha yumuşak kalkış için SmoothDamp.
  • Bézier: lerp’lerin lerp’i (De Casteljau). Uçlardan geçer, kontrol noktalarına doğru bükülür; tutamaçlar yönü verir.
  • Catmull–Rom: verilen noktaların içinden köşesiz geçer; teğeti komşulardan alır.
  • Sabit hız: eşit t eşit yol değildir. Yay uzunluğu tablosu + ikili arama + ters lerp (Godot’nun “baked” eğrisi).
  • Sonraki: ağ senkronizasyonu: çevrimiçi oyunlar gecikmeyi oyuncudan nasıl saklar? Lerp’in en ilginç kullanımı.

🎮 Bu sunumdaki oyunlar

Adı geçen oyunu tanımıyorsanız: oyuncuların kullandığı wiki sayfası ve oyunu kısaca gösteren bir video. ▶ video slaydın üstünde açılır (Esc ile kapanır); 🎯 işaretli bağlantılar doğrudan bu sunumdaki konuya gider.

Counter-Strike 1999– · takım nişancısı
Teröristler ve antiterör timi; isabet ve gecikme telafisi çok tartışılan rekabetçi nişancı.
Celeste 2018 · platform
Bir dağa tırmanış; zor ama cömert kontrol noktalı hassas platform oyunu.
Dead Cells 2018 · aksiyon roguelike
Her ölümde yeniden dizilen bir şatoda geçen hızlı platform-dövüş oyunu.
Hearthstone 2014 · dijital kart oyunu
Warcraft evreninde sıra tabanlı kart oyunu; rakibin elini göremezsiniz.
Slay the Spire 2019 · deste kurmalı roguelike
Kule tırmanırken kart toplayıp her savaşta elinizi oynadığınız oyun; harita dallanan bir graf.

Kaynaklar: videolar 🎬

Kaynaklar: kaynak kodu, yazılar ve etkileşimli sayfalar 📚

NEXT LEVEL ▶
Ağ Senkronizasyonu
ara değerleme, istemci tahmini, gecikme telafisi, geri sarma: lerp’in çevrimiçi oyunlardaki hayatı
SONRAKİ SUNUM ▶