holodepth

Three.js · Transform · Koordinat uzayları

İki farklı gerçeklik: Yerel ve dünya uzayı

3D bir sahnede her objenin iki farklı kimlik kartı vardır: biri ebeveyne göre yerel (local) dönüşümü, diğeri sahnenin köküne göre dünya (world) dönüşümü. Bu ayrımı anlamak, objeleri doğru konumlandırmanın ve tutarlı animasyonlar kurmanın anahtarıdır.

Bu sayfa sözlük ve zihinsel model katmanıdır: sahnede gördüğünüz sayıların hangi koordinat sisteminde geçerli olduğunu ve dünya verisine geçerken hangi API yüzeyinin devreye girdiğini netleştirir. Model parenting «hangi düğüm kime bağlansın?» sorusuna; Çoklu model runtime düğüm taşıma akışlarına odaklanır — burada aynı cümleleri yeniden kurmak yerine bu iki konuyu tamamlayan okuma sunulur.

Önerilen okuma sırası

Önce Object3D hiyerarşisi, ardından bu sayfadaki yerel/dünya ayrımı; bağlama kararları ve örnekler için parenting ile sahne grafiği metinlerine geçmek, kavramları üst üste binmeden oturtur.

Yerel ve dünya dönüşümü

A. Local transform (yerel uzay)

Objenin doğrudan bağlı olduğu ebeveyne (parent) göre olan konum, dönüş ve ölçek bilgisidir.

  • Referans noktası: Ebeveynin merkezidir (0, 0, 0) — yani çocuğun position vektörü, ebeveynin yerel eksenlerinde tanımlıdır.
  • Mantık: Bir karakterin elindeki kılıç ele tam oturmuşsa, karakter dünyanın neresine giderse gitsin kılıcın yerel konumu değişmez; elin koordinat sisteminde hep aynı yerdedir.

B. World transform (dünya uzayı)

Objenin, tüm sahnenin mutlak merkezi olan sahne köküne (scene root) göre olan dönüşümüdür.

  • Referans noktası: Sahnenin mutlak merkezi (0, 0, 0) ile tanımlanan dünya uzayıdır.
  • Mantık: Karakter haritada koşarken elindeki kılıcın dünya konumu her karede değişir; çünkü kılıç karakterle birlikte mutlak uzayda yer değiştirir.

Sahne kökü: «nerede yerel biter?»

Bir düğümün doğrudan ebeveyni scene (veya tek kök grup) ise, o düğüm için yerel öteleme çoğu pratikte dünya ile aynı eksenleri kullanır; yine de rotation / quaternion / scale alanları yerel temsil olmaya devam eder. Zincir derinleştikçe — örneğin gövde → omuz → el — «yerel» kavramı yalnızca bir üst düğüme sıkışır; dünya ise tüm zincirin birleşik sonucudur.

Yön uyarısı: İki nokta arasındaki offset vektörünü düşünürken, vektörü hangi uzayda ürettiğinize dikkat edin. Aynı sayı üçlüsü, bir objenin yerel eksenlerinde «ileri» anlamına gelirken dünyada farklı yöne dönmüş olabilir; ışın, kuvvet veya kamera «baktığı yön» için çoğu zaman dünya uzayında normalize edilmiş yön gerekir (getWorldDirection gibi yardımcılar).

Neden kritik? (Hata senaryoları)

Bu iki kavramı birbirine karıştırmak, çözülmesi zor mantık hatalarına yol açar.

Yanlış hesap = yanlış pozisyon. Örneğin bir lazer ışınını karakterin silahından çıkarmak istediğinizi düşünün: silahın position değerini doğrudan lazerin dünya başlangıcı sanırsanız, değer yalnızca silahın ebeveyne göre ötelemesidir; dünyada nerede durduğunu söylemez. Lazerin başlangıcını dünya uzayında kurmak için getWorldPosition veya eşdeğer bir dünya vektörü hesabı gerekir.

Animasyon ve senkronizasyon. İki farklı ebeveyne bağlı iki objeyi (örneğin iki farklı araçtaki iki karakter) birbirine göre hareket ettirirken yalnızca yerel koordinatlarla mesafe veya çarpışma kurmak yanıltıcıdır. Aralarındaki gerçek ilişkiyi kurmak için çoğu zaman her ikisinin de dünya uzayı temsiline ihtiyaç duyarsınız.

UI ve ekran uzayı. Fare isabeti, etiket sabitleme veya seçim halesi gibi işlerde ekran / kamera ile köprü kurarken, sahne köküne göre tutarlı bir «gerçekten nerede?» cevabı genelde dünya vektörleri üzerinden gider; yalnızca position kopyalamak bu yüzden sık sık kayar.

Ebeveyn değişimi. Bir düğümü yeniden bağlarken (re-parent) yerel sayılar hedef ebeveyne göre yeniden yazılır; ekranda aynı yerde tutmak için dünya matrisini korumak ayrı bir iştir — bu akışın ayrıntısı runtime birleştirme metninde; burada yalnızca şu cümle yeter: yerel kolayca değişir, dünya aynı kalmak zorunda değildir.

Matematiksel arka plan: matris çarpımı

Bilgisayar grafikleri bu geçişi matris çarpımı ile modeller. Bir objenin dünya matrisi, ebeveynlerinin dünya matrisleriyle yerel model matrisinin zincirle çarpılmasıyla elde edilir:

Mworld = Mparent, world × Mlocal

Bu dönüşüm zinciri (transformation chain), ebeveyndeki en ufak bir değişikliğin alt düğümlere dalga dalga yayılmasını sağlar; Three.js de her Object3D için bu zinciri sahne grafiğinde günceller.

Zincir birden fazla ebeveyn içeriyorsa, düşünsel olarak Mworld = Müst, world × ··· × Mparent × Mlocal biçiminde uzar; uygulamada bu çarpımı elle kurmak yerine motorun hesapladığı matrixWorld önbelleğini okumak daha güvenlidir.

Three.js sütun vektörü düzeninde (column-vector) çalışır: bir noktayı dönüştürürken vektörü soldan matrisle çarpmayı düşünebilirsiniz. Bu sayfa matris cebirine inmez; yeter ki çarpım sırasının tersine sahne ağacında kökten uca doğru biriken bir bütün olduğunu hatırlayın.

Uygulama: Three.js yaklaşımı

Three.js’te position, rotation (veya quaternion) ve scale alanları yerel uzayı ifade eder. Dünya verisine geçmek için aşağıdaki yardımcıları kullanırsınız.

İhtiyaç → çözüm metodu

İhtiyaç Çözüm metodu
Yerel konum object.position
Dünya konumu object.getWorldPosition(targetVector)
Dünya dönüşü object.getWorldQuaternion(targetQuaternion)
Koordinat dönüşümü object.localToWorld(vector) veya object.worldToLocal(vector)
Dünya yönü (ör. ileri eksen) object.getWorldDirection(targetVector) — özellikle yerel position farkı kadar bariz olmayan yönelim hatalarında işe yarar.

Tablonun arkası: iki sık tuzak

  • localToWorld ve worldToLocal, gönderdiğiniz Vector3 örneğini yerinde günceller; yeni vektör dönmez. Aynı vektörü hem girdi hem çıktı sanıp yanlış paylaşmak yaygın bir hatadır.
  • getWorldPosition / getWorldQuaternion için sahne genelinde yeniden kullanılabilir «çizgi içi» Vector3 / Quaternion tutmak, döngü başına new atmaktan daha öngörülebilir performans verir (özellikle çok sayıda düğüm okunuyorsa).

Kısa seçim kılavuzu

  • Yerel: Eklem açısı, menteşe limiti, model içi ofset — yani «ebeveynin içinde, ona göre ne yapıyorum?»
  • Dünya: İki ayrı dalı karşılaştırma, ışın başlangıcı, ses dinleyicisi veya kamera takibi — yani «haritada gerçekten nerede ve hangi yöne bakıyor?»

İllüstrasyon

Küçük sahne: turuncu küre, mavi küpün çocuğu. Kürenin position değeri ebeveyne göre sabit kalır; sürgü yalnızca küpü Y ekseninde döndürür — dünya konumu satırında sayıların değiştiğini izleyin. Tam laboratuvar değil; okuma desteği.
Parent rotation (Y) Ebeveyn dönüşü (Y)
Yerel child.position
Dünya getWorldPosition

Ayrıntılı sahne düğümü davranışı için Object3D ve sahne hiyerarşisi sayfasına bakabilirsiniz.

HoloDepth ipucu: updateMatrixWorld

Three.js performans için dünya matrislerini her milisaniyede tek tek yeniden hesaplamaz; genelde render öncesi veya ihtiyaç duyulduğunda toplu günceller. Bir objeyi hareket ettirdikten hemen sonra, aynı kare içinde dünya konumunu okursanız, değerin henüz güncellenmemiş görünmesi mümkündür.

Çözüm: Okumadan önce ilgili alt ağaç için object.updateMatrixWorld(true) çağrısıyla hiyerarşiyi güncellemeye zorlayın (yalnızca gerektiğinde; her karede kökten koşullu çağrı performansı düşürür).

updateMatrixWorld(true) çağrısı, alt düğümleri de kapsayacak şekilde dünya matrislerini tazeler; aynı karede okuma öncesi «değer neden eski kaldı?» sorununu çoğu zaman böyle çözersiniz. Argümansız veya false ile çağrı, yalnızca güncelleme bayrakları işaretliyse iş yapar — bu yol bazen yeterlidir, fakat hata ayıklarken önce true ile netleştirip ardından kapsamı daraltmak pratik bir sıradır. scene.updateMatrixWorld(true) çağrısını her karede kökten yürütmekten ise performans için kaçının.

parent.position.x += 0.1;
// Aynı karede dünya konumu gerekiyorsa:
parent.updateMatrixWorld(true);
const worldPos = new THREE.Vector3();
child.getWorldPosition(worldPos);