Holodepth • ByteOmi Köprü • Yaşam Döngüsü
Render Loop
Render loop, 3D uygulamanın kalp atışıdır: her karede önce dünya güncellenir, sonra ekrana çizilir. Bu ritim doğru kurulmazsa stutter, gereksiz CPU yükü ve tutarsız hareketler kaçınılmaz olur. Bu sayfada loop sezgisini, update→render ayrımını, rAF zamanlamasını ve delta time ile gerçek‑zaman tutarlılığını kuruyoruz.
Kaynak metin: byteomi.com • İlgili köprüler: GPU vs CPU • Sonraki köprü: requestAnimationFrame (ekran ritmini takip etmek)
Canlı demo: “Heartbeat & Delta Runner”
İki koşucu aynı pisti koşuyor. Soldaki “frame-based” koşucu gerçek zamandan kopuk bir şekilde “her tick sabit adım” modelini kullanır; FPS düşünce gerçek sürede yavaşlar ve bazen geriye bile kayabilir. Sağdaki “delta-based” koşucu ise \( \Delta t \) ile hızını gerçek saniyeye bağlar; FPS düşse bile aynı gerçek sürede bitiş çizgisini geçmeye yakın kalır.
Hero demo
Update → Render ritmi, rAF vs setInterval sezgisi ve \( \Delta t \) ile FPS bağımsızlığı tek sahnede.
İpucu: Sabotage açıldığında ana iş parçacığında yapay bir “ağır iş” oluşur ve FPS düşer. Soldaki “yanlış model” gerçek sürede geriye düşer; sağdaki doğru model ise clamp ile ani sıçramayı kontrol eder.
Loop nedir? Film şeridi sezgisi
3D sahneler birer optik illüzyondur: durağan kareleri çok hızlı ardı ardına gösterdiğinde beyin bunu “hareket” olarak algılar. 60 FPS hedefi, saniyede yaklaşık 60 kez yeni bir kare üretebilmek demektir. Bu yüzden 3D uygulama “yüklenip bekleyen” bir sayfa değildir; kendi kendini tekrar eden canlı bir sistemdir.
Bu ritmin kuralı kare bütçesidir: 60 FPS hedefinde bir kare için yaklaşık \(16.7ms\) zamanın vardır. Bu pencere içinde mantık (update), çizim (render) ve tarayıcının kendi işleri aynı bütçeyi paylaşır. Tek bir karede uzun süren bir iş oluşursa, kullanıcı bunu “takılma” (stutter) olarak hisseder.
İdeal akış: update → render
Her tick’te iki iş vardır. Update aşamasında “bu karede ne değişti?” sorusunu cevaplarsın (konumlar, input, animasyon zamanı, mantık). Render aşamasında ise güncel state’e göre sahneyi ekrana basarsın. Sezgi: update “dünyayı düzeltir”, render “dünyayı gösterir”.
İyi bir loop’ta update tahmin edilebilir ve kısa tutulur. Aynı kare bütçesinde 5ms→25ms zıplamak, kullanıcıya stutter olarak döner. Büyük işler ya parçalara bölünür ya da kritik yolun dışına alınır.
Zamanlama: neden setInterval yetmez?
setInterval ekranın tazeleme ritminden bağımsız çalışır: ekran hazır değilken
çizimi zorlamak gereksiz CPU/GPU baskısı üretir.
Ayrıca pratikte “drift” oluşur; aralıklar kayar, kareler düzensiz gelir ve akıcılık bozulur.
Çözüm: requestAnimationFrame (rAF). Tarayıcıya “ekran yeni kare çizmeye hazır
olduğunda beni çağır” dersin; loop VSync ile
senkronize olur ve arka planda otomatik yavaşlar/durur.
Delta time: FPS bağımsızlığı
Döngünün en büyük düşmanı değişken FPS’dir. Bu yüzden iki kare arasındaki süreyi \( \Delta t
\) ölçer ve hareketi buna göre ölçeklersin:
position += velocity * dt. Böylece FPS kaç olursa olsun, obje gerçek saniyede
benzer mesafeyi kateder.
Pratik not: \( \Delta t \) çok büyürse (sekme geri geldi, frame kaçırıldı) hareket “zıplayabilir”. Bu yüzden bazı sistemler \( \Delta t \)’yi üstten sınırlar (clamp) veya fixed-step simülasyon uygular.