Varlık Anatomisi
Dijital bir varlık (asset), ekranda gördüğümüz pürüzsüz yüzeyden ibaret değildir: GPU’ya gönderilen sayı dizileri ve bu sayıların nasıl okunacağını söyleyen talimatlar bütünüdür. 3D’de “obje oluşturmak” çoğu zaman bu veri paketini (buffer) tasarlamaktır.
Atomik Yapı: Vertices (Köşeler) Vertex Data
Odak: Her 3D varlığın temel birimi vertex’tir; ama vertex yalnızca uzaydaki bir nokta (\(x, y, z\)) değildir. O, beraberinde GPU’nun yorumlayacağı bir veri çantası taşır.
Neden kritik? Çünkü GPU, “model” gibi yüksek seviyeli kavramlarla değil; veri akışı ile çalışır. Vertex’in içeriği, sahnenin hem şeklini (position) hem de ışık tepkisini (normal) ve kaplamasını (UV) belirler.
Bu veri çantasında tipik olarak şu katmanlar bulunur:
Position: Uzaydaki konumu.
Normal: Yüzeyin hangi yöne baktığı (ışık hesapları için hayati).
UV Coordinates: 2D dokunun (texture) 3D yüzeye nasıl yapıştırılacağı bilgisi.
Vertex Color: Her noktaya özel atanmış renk verisi.
Vertex Shader bağlantısı: Bu alanların her biri, shader tarafında bir attribute olarak okunur ve özellikle position ile ekran koordinatına (clip space) taşınır. normal ise ışık hesaplarının “hangi yöne bakıyor?” sorusunu besler.
GPU perspektifi: GPU için bu “obje”, karmaşık bir yapı değil; çoğu zaman devasa bir Float32Array (typed array) ve onu nasıl okuyacağını söyleyen attribute düzenidir.
Bu yüzden 3D’de “tasarım” çoğu zaman şu iki kararı doğru vermektir: hangi attribute’lar gerekli ve ne yoğunlukta (kaç vertex/kaç üçgen) kullanılacak? Çünkü vertex sayısı arttıkça, vertex shader’ın yapacağı iş de doğrudan artar.
İskelet Sistemi: Faces ve İndisler (Indices) Index Buffer
Odak: Bilgisayar grafikleri üçgenlerle konuşur. Dörtgen veya karmaşık yüzeyler, aslında birleştirilmiş üçgenlerdir.
Neden üçgen? Çünkü üç nokta her zaman tek bir düzlem tanımlar; bu da rasterization aşamasında “içini doldur” problemini kararlı ve hızlı hale getirir. Dörtgenler ise eğri/çarpık geometriyle iki farklı üçgenle bölündüğünde farklı sonuçlar üretebilir.
Triangulation: Her poligon, GPU’nun anlayabileceği en küçük birim olan üçgenlere bölünür.
Index Buffer: Aynı vertex’leri defalarca tanımlayıp belleği yormamak için “indisleme” kullanılır.
Bu mekanizma GPU’ya şunu söyler: “Veri dizisindeki \(0,1,2\) numaralı vertex’leri bir üçgen yap; sonra \(2,3,0\) ile bir üçgen daha yap.” Yani geometriyi yeniden yazmak yerine, bağlantı şemasını (topology) ayrı bir listede tutarsın.
Örneğin bir küpün 8 köşesi vardır ama 12 üçgeni (toplam 36 köşe kullanımı) bulunur. İndisleme sayesinde 36 nokta yerine 8 nokta tanımlayıp, GPU’ya “şu noktaları birleştir” talimatı verilir. Bu, optimizasyonun ilk adımıdır.
Performans etkisi: İndisleme genellikle bellek kullanımını ve veri transferini düşürür; ayrıca bazı durumlarda GPU’nun vertex cache verimliliğini artırır. WebGL/Three.js tarafında bu, “diziyle çiz” yerine çoğu zaman indexed draw (mantıksal olarak drawElements) demektir.
Kritik nüans: “Aynı köşe noktası” her zaman tek bir vertex değildir. Sert kenarlarda farklı normal gerekir, UV dikişlerinde farklı UV gerekir. Bu yüzden pozisyon aynı olsa bile vertex verisi farklıysa, GPU açısından o nokta ayrı bir vertex olarak tutulur.
Deri ve Doku: UV Mapping Texture Coordinates
Odak: 3D objeyi hediye paketi yapılmış bir kutu gibi düşün. UV Mapping, o kağıdı (2D resim) tekrar düz bir masaya yayma işlemidir.
Unwrap sezgisi: 3D yüzeyi 2D’ye “açarken” bir yerlerden kesmen gerekir; bu kesiklere seam denir. Seam kaçınılmazdır; hedef, kesikleri göze daha az çarpan bölgelere saklamaktır.
U ve V, doku dünyasındaki X ve Y koordinatlarının karşılığıdır.
Her vertex’e bir \((u, v)\) değeri atanır. GPU bu değerleri pikseller arasında yumuşatarak (Interpolation) dokuyu yüzeye giydirir.
Buradaki kritik nokta şudur: GPU, üçgenin köşelerindeki UV’leri piksellere doğru lineer yayar. Bu yüzden UV’ler “düzgün” değilse, doku yüzey üzerinde gerilmiş veya ezilmiş görünür.
UV haritan hatalıysa, dokular objenin üzerinde “kayar” veya “gerilir”. Sorun çoğu zaman texture’tan değil, koordinat eşlemesinden gelir.
Texel density: UV adacıklarının (islands) ölçekleri tutarsızsa, aynı texture objenin bir yerinde “keskin”, başka bir yerinde “bulanık” görünür. Özellikle oyun/web hedeflerinde “her parçada benzer doku yoğunluğu” iyi bir kalite göstergesidir.
Pratik hata işaretleri: Doku bir yönde kayıyorsa çoğu zaman UV yönü/ölçeği; dikiş çizgisi görünüyorsa seam konumu veya normal/UV bölünmesi; “şekerleme” gibi titreme varsa mipmap/filtreleme ve UV ölçeği birlikte düşünülmelidir.
Geometri vs. BufferGeometry Typed Arrays
Odak: Three.js dünyasında iki farklı “hafıza yönetimi” modeli görürsün: eski Geometry ve modern BufferGeometry.
Temel fark: Eski modelde veri, JavaScript tarafında “okunabilir nesneler” olarak dolaşır; modern modelde ise veri, GPU’ya gönderilmeye hazır paketlenmiş sayılar gibi düşünülür. WebGL’in sevdiği şey budur: ham, düzenli ve ardışık bellek.
Geometry (Eski Model): İnsan dostu ve okunabilir; ancak JavaScript objeleri olarak taşındığı için daha yavaştır.
Buradaki “yavaşlık” genelde hesap gücünden değil; nesne overhead, garbage collector baskısı ve sık güncellemelerde ana thread’in şişmesinden gelir.
BufferGeometry (Modern Model): GPU dostudur. Veriler doğrudan tip atanmış dizilerde (Typed Arrays) tutulur.
BufferGeometry’de “vertex çantası” çoğu zaman attribute’lara ayrılır: position, normal, uv, color… ve eğer indeksleme varsa index. Her biri arka planda Typed Array olarak saklanır ve GPU’ya bu düzenle taşınır.
Pratik performans kuralı: Veriyi mümkünse bir kere gönder ve VRAM’de tut. Her karede büyük attribute güncellemesi yapman gerekiyorsa, maliyetin çoğu zaman shader değil transfer olur.
HoloDepth Notu: HoloDepth çekirdeği tamamen BufferGeometry üzerine kuruludur. Çünkü modern WebGL, verinin “hazır ve paketlenmiş” (ready-to-ship) olmasını bekler.
Dinamik güncelleme: Bazı senaryolarda (ör. particle, deform) attribute’ları değiştirmen gerekir. Bu durumda hedef, yalnızca gereken alanları güncelleyip “tüm geometriyi yeniden inşa etmek” yerine minimal güncelleme yapmaktır.
Poligon Bütçesi ve Performans Quality vs FPS
Odak: En büyük sınav “görsel kalite” ile “kare hızı” (FPS) arasındaki dengedir. Her üçgen, vertex shader ve fragment tarafında bir maliyet doğurur.
Önemli nüans: “Poligon sayısı” tek başına tüm hikâye değildir. Performansı belirleyen paket çoğu zaman şunların toplamıdır: vertex maliyeti, piksel (fragment) maliyeti, overdraw (üst üste çizim), doku bant genişliği ve sahnedeki draw call sayısı.
Low-Poly: Az sayıda üçgenle karakteri yansıtma sanatı. Mobil cihazlar için kritiktir.
Low-poly yaklaşımda amaç “detayı silmek” değil; detayı doğru yerde taşımaktır. Silüet (outline) çok önemlidir: kullanıcı objeyi uzaktan okurken önce silüeti görür.
High-Poly: Milyonlarca üçgen. Genelde render çiftliklerinde işlenir; web için çoğu zaman “fırınlanarak” (Baking) optimize edilmesi gerekir.
Baking, yüksek poligonlu modeldeki detayın “ışık/denge bilgisini” düşük poligonlu modele haritalamaktır. Bu sayede geometriyi taşımadan, gözü kandıran bir detay hissi üretirsin.
Normal Mapping: Düşük poligonlu bir objeyi, sanki milyonlarca detayı varmış gibi gösterme hilesidir. Işığın “sahte” detaylara çarpmasını sağlar.
Ne yapar / ne yapmaz? Normal map geometriyi artırmaz; yani silüeti değiştirmez. Ama piksel başına kullanılan normal yönünü değiştirerek ışık hesabını (özellikle \(N \cdot L\)) etkiler ve yüzeye “kabartı” algısı verir.
Pratik strateji: Web hedefinde genelde “LOD + baking + doğru materyal/ışık” kombinasyonu en iyi dengedir: yakında daha detaylı, uzakta daha hafif geometri; detay hissi ise map’lerle taşınır.
Buffer’ı paketle, sahneyi hızlandır
Bir asset’i “model” gibi değil; GPU’ya giden vertex, index ve UV paketleri gibi düşün. Attribute’ları değiştir, indekslemeyi aç/kapat ve BufferGeometry mantığının performansa etkisini sahnede anında hisset.
Poligon bütçesi, UV dikişleri ve normal map gibi “hilelerin” aslında hangi katmanda çalıştığını, ölçerek öğren.