Matrix Nedir?
Matrisler, 3D uzaydaki dönüşümleri (taşıma, döndürme, ölçekleme) tek bir "paket" altında
toplar. Bir modeli binlerce noktaya tek tek işlem uygulamak yerine, dönüşümü bir kez
matris olarak birleştirip her noktaya aynı kuralı uygularsın.
Bu sayfada dönüşüm paketini, matris çarpımının "birleşik güç" mantığını ve MVP zincirini
sezgisel şekilde kuracağız.
Matrix Bir "Dönüşüm Paketi"
Vektörler tek bir nokta veya yönü temsil eder; ama gerçek 3D sahnelerde bir model, binlerce noktadan oluşur.
Bir arabayı hem taşımak, hem 45° döndürmek, hem de iki kat büyütmek istediğinde her noktaya tek tek trigonometrik işlem yapmak istemezsin, işte matrisler tam burada devreye girer.
Bir matrisi, içinde birden fazla komutu barındıran bir konfigürasyon paketi gibi düşünebilirsin: translation (nerede), rotation
( nereye bakıyor ) ve scale (ne kadar büyük) bilgisi tek bir yapıda birleşebilir.
Three.js Notu: Three.js’te bir objenin position, rotation ve scale değerleri değiştiğinde, kütüphane bunları arka planda tek bir 4×4 dönüşüm matrisi içinde birleştirir.
"4×4" detayı tesadüf değildir: 3D’de taşıma işlemini de dönme/ölçekleme ile aynı çarpım modeline sokmak için
homogeneous coordinates kullanılır.
Böylece "taşı + döndür + ölçekle" gibi farklı türde dönüşümler, tek bir matris çarpımı zincirinde birleşebilir.
Bu paketin pratik karşılığı şudur: modelin her bir köşe noktası için "aynı kural" uygulanır.
Sen bir kez dönüşüm paketini kurarsın; GPU/CPU, o paketi binlerce noktaya uygular.
Yani matris, "tek tek işlem" yerine tek kural yaklaşımıdır.
Nerede İşine Yarar? Bir objeyi sahnede taşırken aslında geometriyi yeniden yazmazsın; sadece onun dönüşüm paketini değiştirirsin. Bu, hem performans hem de sahne düzeni için çok büyük bir avantajdır.
Three.js Pratik Detayı: Bazı senaryolarda ( özellikle matrixAutoUpdate kapalıysa ) position gibi değerleri değiştirsen bile matrisi güncellemen gerekebilir.
"Neden taşıdım ama etkisi yok?" gibi sorunlar, çoğu zaman matrisin henüz update edilmemesinden çıkar.
Neden Matris? Birleşik Güç
Matrislerin en büyük gücü, çarpılabilir olmalarıdır.
Bir döndürme matrisi ile bir taşıma matrisini çarptığında, elinde hem döndüren hem taşıyan tek bir dönüşüm paketi kalır.
Buradaki kritik detay: matris çarpımı değişmeli değildir.
Yani çoğu zaman \(R \cdot T \neq T \cdot R\).
Önce döndürüp sonra taşımak ile önce taşıyıp sonra döndürmek aynı sonucu vermez; çünkü ikinci senaryoda "taşıdığın şey" de döndürülmüş olur.
Bu yüzden matrisler, dönüşümün sadece "ne" olduğunu değil, "hangi sırayla" uygulandığını da taşır.
Sezgi: Çoğu 3D kurguda önce objeyi kendi merkezinde ölçekler, sonra döndürür, en son dünyada bir yere taşırsın.
Bu sıralama (S→R→T) "objenin yerini değiştirmeden döndürme" gibi beklentileri karşılar.
Bu, CPU tarafında da stratejiktir: binlerce noktayı üç ayrı işlemden geçirmek yerine, önce işlemleri matrislerde birleştirir; sonra her noktaya aynı tek matrisi uygularsın.
Bu yüzden matris çarpımı, "çok iş"i "tek kural"a indirger.
Bu "tek kural" yaklaşımı, CPU–GPU iş bölümünde de anlamlıdır: CPU tarafı dönüşüm paketlerini hazırlar, GPU tarafı ise aynı paketi devasa sayıda vertex üzerinde paralel uygular.
Bu mantık, GPU vs CPU sayfasındaki "emir yazan vs uygulayan" ayrımıyla birebir örtüşür.
Hiyerarşi taşıyıcısı: Local space’ten world space’e geçiş (bkz: Koordinat Sistemleri) tamamen matrislerin zincir halinde birbirini etkilemesiyle olur: parent’ın world matrisi, child’ın local dönüşümünü "dünyaya" taşır.
Bu zincirde performans sezgisi şudur: parent değişmediyse, çoğu child’ın world matrisi de değişmez.
Bu yüzden motorlar genellikle dönüşümleri "kirli" işaretleyip sadece gerekli dalları günceller.
Sahne grafiğini doğru kurduğunda, bir parent hareketi tüm alt ağaca tek çarpım zinciri üzerinden taşınır.
MVP Model • View • Projection
Bir 3D nesnenin ekrana düşene kadar geçtiği yol, çoğu zaman üç matrisle kontrol edilir: Model, View, Projection.
Bu üçlü aslında bir "uzay dönüşüm zinciri"dir:
local ( objenin kendi uzayı ) → world (sahne uzayı) → view ( kamera uzayı ) → clip → NDC.
Yani ekranda gördüğün her pikselin arkasında, bir noktanın bu uzaylardan geçerek normalize edilmesi vardır.
View matrisi çoğu zaman şaşırtıcıdır: kamera "dünyada duruyor" gibi görünse de, matematikte genellikle dünya kameraya göre ters yönde bükülür. Yani kamera transform’unun tersini uygulayan bir matris düşünürsün.
Operasyonel okuma: Model matrisi "objeyi dünyaya koyar", view matrisi "dünyayı kameraya göre hizalar", projection matrisi ise bu hizalanmış uzayı "ekrana sığan" bir frustum’a dönüştürür.
Bu yüzden projection, sadece görsel değil; aynı zamanda görünürlük hacmi tanımıdır.
Projection bağı: Projection matrisi, sahneyi NDC aralığına indirger (bkz: NDC).
Bu yüzden "ekrana nasıl sığıyor?" sorusunun matematiksel cevabı projeksiyondur.
Clip uzayından NDC’ye geçişte kritik adım perspective divide’dır: koordinatlar \(w\) bileşenine bölünür (\(x/w, y/w, z/w\)).
Bu adım, perspektif hissinin matematiksel çekirdeğidir ve NDC’nin \([-1, +1]\) aralığını "standart dil" haline getirir.
GPU çoğu pipeline’da bu üç dönüşümü tek bir zincire bağlar (MVP) ve bir karede milyonlarca noktaya aynı kuralı uygular.
Bu da matris fikrinin "ölçek kazanma" gücüdür.
Pratikte bu zincir çoğu zaman tek bir matrise birleştirilir: \(MVP = P \cdot V \cdot M\).
Böylece shader tarafında her vertex için tek bir çarpım çalışır: gl_Position = MVP * vec4(position, 1.0).
Bu "tek çarpım" yaklaşımı, GPU’nun paralel yürütme modeline en uygun formdur.
Hafif Bir Bakış Matris Okuma
4×4 matris ilk bakışta korkutucu görünebilir; ama 3D web’de çoğu zaman bakacağın yerler bellidir.
Standart bir dönüşüm matrisinde, üstteki 3×3 alan genellikle dönme/ölçekleme bileşenlerini, son sütun (veya düzenine göre satır) ise konum bilgisini taşır.
Three.js bunu senin için yönetir: matrixWorld, objenin world uzayındaki dönüşümünü temsil eder.
Ancak bu yapıyı bilmek, "Neden objeyi taşıdım ama değerler değişmedi?" gibi problemlerde çok işe yarar: bazen matris henüz güncellenmemiştir.
Matris okurken ikinci pratik ipucu şudur: üstteki 3×3 blok, çoğu zaman objenin yerel eksenlerini taşır.
Yani bu blok, "objenin sağ/yukarı/ileri yönleri world uzayında nereye dönmüş?" sorusunun cevabıdır.
Bu yüzden bir objenin "yönü ters mi?" gibi sorunlarda 3×3 blok çok hızlı sinyal verir.
Ölçek sezgisi: Eğer dönüşüm matrisi ölçek içeriyorsa, bu 3×3 bloktaki eksen vektörlerinin boyları 1 olmaz.
Yani sütun/satır uzunlukları, objenin scale değerine dair ipucu verir. "Neden model yamuldu?" gibi sorularda, istemeden eklenen ölçek burada yakalanır.
Düzen Notu: "Konum son sütunda mı, son satırda mı?" detayı kütüphanenin matris düzenine (column-major/row-major) bağlıdır.
Three.js, bunu kendi içinde tutarlı şekilde yönetir; senin için önemli olan, aynı projede tek bir düzeni izlemek ve debug ederken
"yanlış yere bakmamak"tır.
Three.js Debug Noktası: Eğer matrixAutoUpdate kapalıysa veya sahne grafiği henüz güncellenmediyse, matrixWorld beklediğin değeri vermeyebilir.
Bu durumda "update edilmemiş matris" problemi yaşarsın.
Bu mantık, local vs world bölümündeki dönüşüm zinciriyle doğrudan bağlantılıdır.
Pratik Sezgi: Matris, uzayın hafızası gibidir: objenin nerede olduğunu, nasıl döndüğünü ve ne kadar ölçeklendiğini tek bir "durum" olarak saklar.
Bu yüzden sahne grafiğinde dolaşırken, aslında matrisi takip edersin.
Uzayı Rakamlarla Bükün
4×4’lük bir sayı tablosunun koca bir dünyayı nasıl döndürüp taşıdığını bizzat görün. Matrix hücrelerine manuel müdahale edin ve MVP zincirinin her halkasını canlı olarak analiz edin.
Matris hücrelerini değiştir, sıralamayı boz, geri al. MVP zincirinde hangi halkanın uzayı nasıl etkilediğini gözünle izle.