holodepth

Three.js · Etkileşim · Performans

Performans ve güncelleme döngüsü: kontroller ne zaman iş yükü olur?

Üç boyutlu bir web uygulamasında çizim döngüsü genelde requestAnimationFrame ile saniyede onlarca kez tetiklenir; üst uç ekranlarda bu sayı 120 ve ötesine çıkabilir. Her turda eklenen küçük bir hesaplama, yıllık ölçekte binlerce kez tekrarlanır — kontrollerin güncellenmesi de bu yüzden bazen sessiz bir sıcak nokta haline gelir. Bu sayfa, özellikle Three.js kontrol sınıfları ve kamera senkronizasyonu bağlamında döngüyü nasıl «incelteceğinizi» özetler.

Genel girdi → işleme akışı için Kontrol mantığı · boru hattı sayfasına dönün; burada odak, borunun sonunda kamerayı güncelledikten sonra döngünün kalanında nelerin biriktiğidir.

Bölümler: controls.update ne zaman şart, talep üzerine çizim, darboğazlar, Δt entegrasyonu.

Controls.update() gerçekten her karede mi?

Birçok örnek projede kontrol örneği oluşturulur oluşturulmaz döngüye controls.update() eklenir; bu, öğretici kod için güvenli bir varsayılandır çünkü hangi bayrakların açık olduğunu görmezden gelmez. Üretimde ise soru şudur: kontrolün içinde zamanla süren bir durum var mı? Bu soruyu «bu karede kullanıcı dokundu mu?» ile karıştırmayın: süren durum, tuş veya işaretçi boşta olsa bile matematiğin kapanmadığı anlamına gelir — işte maliyet tam burada birikebilir.

  • Damping / atalet: Kullanıcı girdiyi kestiğinde bile kamera bir süre daha süzülüyorsa, ara durum her karede ilerletilir — bu yüzden güncelleme çağrısı süreklidir. Davranışsal detay Damping sayfasında; tuning ise OrbitControls ayarları ile birlikte düşünülür. Benzer «durmayan» his TrackballControls dinamiğinde momentum ile de ortaya çıkar; matematik farklı kontrol sınıflarında farklı paketlenmiş olsa da döngü maliyeti aynı mantıkla değerlendirilir.
  • Otomatik dönüş (autoRotate): Sahne kendi ekseninde dönüyorsa hedef açı her karede yeniden üretilir; bu da sürekli güncellemeyi gerektirir. Kullanıcı etkileşimi ile çakıştığında iç önceliklendirme (priority) ve duraklatma kuralları ürün kararıdır — döngü tarafında kritik olan, dönüşün durduğu anda gerçekten durduğunu doğrulayıp gereksiz çağrıyı kesmektir.
  • Sürekli kısıtlama veya süzülmeli düzeltme: Çarpışma sonrası itme, yaylı takip veya sürtünmeli kaydırma gibi «fizik benzeri» ekler bağladıysanız, iç durum yine kare kare ilerler — Dinamik kısıtlar bölümündeki örnekler bu sınıfa girer. Ayrıca sürüklenen bir TransformControls ile sahneyi canlı önizliyorsanız, seçim süresince küçük güncellemeler zinciri oluşabilir — bunu kamera kontrolünden ayrı bir «kirli» kanal olarak izlemek profillemeyi kolaylaştırır (TransformControls).

Eğer yalnızca işaretçi hareket ettikçe kamera anında yeniden konumlanıyor ve süzülme yoksa, döngüyü inceltmek mümkündür: bazı düzenlerde her kare yerine kirli bayrak (dirty flag) ile «bir şey değişti mi?» sorusuna göre çağırırsınız (bir sonraki bölüm). Tersine, kontrol kütüphanesinin iç yapısını bilmeden güncellemeyi tamamen atlamak ise iç durum ile görüntüyü ayırabilir — üreticide mutlaka ölçümle doğrulayın. Kullandığınız Three.js sürümünde ve kontrol varyantında updateın içinde ek yan etkiler (örneğin dahili normalizasyonlar) olup olmadığını bir kez kaynak veya profil ile kontrol etmek, «görünürde statik» sahnede yaşanan hayalet düşüşlerini erken yakalar.

Talep üzerine çizim: statik sahnede boş döngüyü kesmek

Hiçbir piksel değişmeyecekken saniyede yüz kare çizmek, özellikle dizüstü ve mobilde hem ısınma hem batarya maliyetidir. Bu yüzden vitrin ve yapılandırıcı panellerde sık görülen desen: sahne «kirli» olduğunda tek kare üretmek. Uygulama birden fazla görünüm veya bileşik çıktı (EffectComposer, ekstra geçiş hedefleri) kullanıyorsa «kirli» bayrağı bazen tek bir çağrıya indirgenemez; hangi geçidin yenilenmesi gerektiğini ürün düzeyinde listelemek gerekir — aksi halde talep üzerine optimizasyon kısmi kalır ve kullanıcı yine sürekli döngüye döner.

  • Değişiklik dinleyicisi: Birçok Three.js kontrolü, kullanıcı etkileşimi sonrası bir change olayı yayınlar; bu olayda bir bayrak kaldırılır ve yalnızca o karede renderer.render(scene, camera) çağrılır. Aynı jest başka alt sistemleri de kirletiyorsa (örneğin seçim gizmo’su veya ölçüm yer işaretleri), tek olaya güvenmek yetersiz kalabilir — bayrakları kaynak bazında birleştirmek daha güvenilirdir.
  • Zamanlayıcıyla uyuma: Etkileşim bittiği halde damping nedeniyle birkaç kare daha çizim gerekebilir — talep üzerine modda genelde «animasyon bitene kadar kısa süreli sürekli döngü» veya «her güncellemede bir kare» birleştirilir. Süzülme sıfıra yaklaşırken küçük bir eşik tanımlayıp döngüyü erken kesmek, özellikle düşük güç modlarında fark edilir; eşik çok agresif seçilirse ise son karede mikro sıçrama görülebilir — bu yüzden görsel eşik ile zaman eşiğini birlikte ayarlayın.

Dikkat: sahne «statik» görünse bile video dokusu, karşıtlık animasyonu, ortam haritası kayması veya arka planda çalışan veri görselleştirmesi varsa kareleri tamamen durdurmak yanlış poz verir. Talep üzerine render bir iş kararıdır; hangi alt sistemlerin sessizce değiştiğini envanterlemek şarttır. Pencere yeniden boyutlandığında veya cihaz döndüğünde tek kare üretmek genelde unutulan bir «kirlenme» kaynağıdır; tam ekran geçişleri ve DPR sıçramaları da aynı kategoriye girer — bunları talep üzerine mimaride açıkça listelemek, görünürde optimize bir sayfanın arada bir rAF ile yağ yakmasını önler.

Darboğazlar: matrisler ve girdi gürültüsü

Kare süresi düşüyorsa önce «çiziyor muyuz?» sorusunu ayırın; sonra kontrol güncellemesi sırasında GPU’dan çok CPU tarafı senkron iş birikiyor mu bakın. Tarayıcı profilinde uzun «küçük kutu» süreleri bazen kontrol kodundan değil, üst üste binmiş matris güncellemelerinden gelir — önce sahne grafiğindeki kim kimi izliyor? sorusunu yanıtlamak, yanlışlıkla kontrol matematiğini optimize etmeye çalışmaktan daha hızlı sonuç verir.

  • Matris zinciri: Kamera hareket ettiğinde dünya matrisleri yenilenir; kameraya doğrudan veya dolaylı bağlı çok sayıda nesne varsa maliyet çarpılır. Yardımcı objeleri mümkünse kameranın altına değil, paylaşılan bir grup veya sahne grafiği düzeniyle yönetin; yalnızca gerçekten ebeveyn izlemesi gerekenleri bağlayın. Hareket etmeyen dallarda gereksiz güncellemeyi kesmek için matrixAutoUpdate ve seçici manuel güncelleme desenleri sık kullanılır — burada amaç sahneyi dondurmak değil, hareket dalgasının gereksiz yere tüm grafiği süpürmemesidir.
  • Girdi yoğunluğu: pointermove veya mousemove her alt pikselde tetiklenebilir; tam çözünürlükte bu, kontrol matematiğinden bağımsız bir üst sınır oluşturur. Çözüm tek değildir: istekleri requestAnimationFrame içinde birleştirmek, basit throttle veya «bu karede yalnızca bir kez» politikası — gözün zamansal çözünürlüğü ile işlemci bütçesi arasında bilinçli takas yapılır (16 ms ile 20 ms farkını kullanıcı fark etmese bile birikmiş güç ve ısı farkı oluşur). Dokunmatikte mümkün olduğunda passive dinleyiciler ve birleştirilmiş örnekler (getCoalescedEvents) ile işi tek bir döngü örneğinde toplamak, ana iş parçacığını gereksiz uyandırmayı azaltır — ancak tüm tarayıcı sürümlerinde aynı davranışı varsaymayın.

Dokunmatik ve kalem cihazlarında olayların birleştirilmesi (coalesced events) ve yakalama (pointer capture) davranışları tarayıcıya göre değişir; girdi katmanını soyutlarken Input mapping sayfasındaki masaüstü / mobil ayrımını hatırlamak, gereksiz dinleyici çoğaltmasını önler. Aynı jest hem sayfa kaydırmasına hem kameraya bağlanıyorsa, tarayıcı düzeyinde kaydırma ile WebGL tuvalinin rekabeti ek gecikme ve fazladan olay üretebilir — bu da kontrol kodundan bağımsız bir CPU maliyeti satırıdır ve ürün UX’inde «donmuş kontrol» olarak geri döner.

Δt ile kare hızından bağımsız hareket

Aynı kod 144 Hz monitörde ve 60 Hz telefonda farklı sürelerde çalışırsa, ham «her kare sabit adım» ile tanımlanan hızlar cihazdan cihaza kayar. Kontrol işleme katmanında konumu veya hızı güncellerken çarpanı geçen zamana (delta time, Δt) bağlamak, algılanan fiziksel hızı yaklaştırır.

Δt kullanımı damping ve easing ile birlikte düşünülmelidir: düşük kare hızında adım büyür; yüksek kare hızında küçülür. Sekme arka planda kaldığında veya ayıklayıcı duraklatıldığında Δt bazen tek karede şişer; patlamayı kesmek için üst sınır (clamp) yaygın bir güvenlik kemeridir — aksi halde bir sonraki etkileşimde kamera istenmeyen sıçrama yapar.