Three.js · Animasyon
Animasyon döngüsü ve zaman yönetimi
3B sahnede bir nesnenin hareket etmesi, aslında saniyede onlarca kez sahnenin
yeniden çizilmesidir. Profesyonel bir projede bu çizim hem akıcı olmalı hem de
mümkün olduğunca her cihazda aynı zaman ölçeğinde ilerlemelidir. Temel araçlar
requestAnimationFrame,
delta time ve
THREE.Clock'tur;
render döngüsü ile
birlikte düşünülür.
Döngü, zaman ve kare hızı
requestAnimationFrame: modern döngü
Eskiden animasyonlar için setInterval kullanılırdı; modern web standartlarında
tek bir "kral" vardır: requestAnimationFrame (rAF).
- Akıllı senkronizasyon: rAF, tarayıcının yenileme hızıyla (çoğu ekranda 60 Hz civarı) otomatik hizalanır.
- Performans dostu: Kullanıcı başka sekmeye geçtiğinde veya pencereyi küçülttüğünde animasyon genelde duraklar; GPU ve pil ömrü için kritiktir.
- Daha düzgün çizim: Kod, ekranın bir sonraki boyama döngüsünden hemen önce çalıştırılarak "tekleme" (stuttering) riski azaltılır.
requestAnimationFrame ekranın yenileme hızına bağlı çalışır; bu yüzden farklı
cihaz ve monitörlerde farklı FPS değerleri oluşabilir. Bu da delta time ile
kare hızından bağımsız hareket
gerektirmesinin nedenidir.
Tick: güncelle, sonra çiz
Oyun ve etkileşimli 3B geliştirmede her animate çağrısı genelde bir
tick sayılır: önce sahne durumu (konum, animasyon, fizik) bu tick içinde
güncellenir, ardından renderer.render(scene, camera) ile kare çizilir.
Bu döngü, Renderer sayfasında anlatılan render çağrısını
sürekli tekrarlar; böylece
render pipeline her karede yeniden işletilmiş olur — yani
sistemin "kalbi" burada
atar.
Delta time: kare hızından bağımsızlık (FPS independence)
En sık yapılan hata, nesneleri her karede sabit bir adımla hareket
ettirmektir — örneğin cube.rotation.y += 0.01.
Sorun: 60 Hz bir ekranda bu "normal" görünürken, 144 Hz bir oyuncu monitöründe aynı kod nesneyi belirgin şekilde daha hızlı döndürür.
Çözüm (delta time): Bir önceki kareden bu yana geçen süreyi (çoğunlukla saniye) hesaplayıp hareketi bu süreyle çarpmak gerekir. Böylece donanım ne kadar hızlı olursa olsun, nesne gerçek zamanda (saniye başına) tutarlı hızla hareket eder.
THREE.Clock ile tipik kullanım:
const delta = clock.getDelta();
mesh.position.x += 2 * delta; // saniyede 2 birim (birim/s × saniye)
2 * delta ifadesi, hızın birim/saniye cinsinden verildiği
düşünüldüğünde her karede ne kadar yer değiştireceğini verir; FPS artsın azalsın, saniyede
toplam mesafe aynı kalır.
THREE.Clock: zamanı ölçmek
Three.js, zamanı yönetmek için THREE.Clock sunar. İki temel okuma birbirinin
yerine geçmez; kısaca ayrım şöyledir:
.getElapsedTime()sürekli artan toplam süreyi (saniye) döndürür; genelde matematiksel / periyodik animasyonlar için kullanılır (sinüs, dalga, dönen değerler)..getDelta()yalnızca iki kare arasındaki süreyi verir; fiziksel hız, ivme ve sabit birim/saniye ile hareket gerektiren güncellemeler için tercih edilir.
Uygulamada aynı karede hem toplam süreye hem delta'ya ihtiyaç varsa:
Three.js kaynaklarında getElapsedTime() içeride getDelta()
çağırdığı için önce const delta = clock.getDelta()
deyip, toplam süre için clock.elapsedTime özelliğini okumak güvenli bir
kalıptır (aşağıdaki birleşik örnek).
Teknik tablo: zaman yönetimi yöntemleri
| Yöntem | Kullanım alanı | Avantajı |
|---|---|---|
getElapsedTime() |
Dalgalanma, yüzen nesneler, sürekli dönüşler. | Sin / cos ile periyodik hareketlerde doğrudan kullanım. |
getDelta() |
Karakter hareketi, mermi hızı, fiziksel düşüş. | 60 FPS / 144 FPS farkında aynı gerçek zaman hızı. |
Date.now() |
Düz JavaScript zaman damgası. | Three.js'e bağlı değildir; rAF ile doğal senkron garantisi yoktur. |
Uygulama: profesyonel render döngüsü
Aşağıdaki örnek, aynı animate içinde hem süre tabanlı dalga
hareketini (elapsedTime ile sinüs) hem delta ile FPS
bağımsız dönüşü birleştirir. mesh, scene, camera ve
renderer önceden tanımlıdır.
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
const elapsedTime = clock.elapsedTime;
// Dalga hareketi (sürekli artan süre → sin/cos için uygun)
mesh.position.y = Math.sin(elapsedTime) * 0.5;
// FPS bağımsız dönüş (radyan/s × saniye)
mesh.rotation.y += 2 * delta;
renderer.render(scene, camera);
}
animate();
Holodepth notu: getDelta() tuzağı
getDelta() metodunu aynı döngü içinde birden fazla kez
çağırmayın. getElapsedTime() da içeride getDelta()
tetiklediği için peş peşe
getElapsedTime(); getDelta(); yazmak ikinci bir delta ölçümü yaratır ve
süreleri bozar. Hem delta hem toplam süre gerekiyorsa: önce
const delta = clock.getDelta(), toplam süre için
clock.elapsedTime (veya yalnızca biri yeterliyse tek bir API kullanın).