holodepth

Three.js · İleri geometri

GPU displacement: geometrinin donanımsal evrimi

Düşük poligonlu kafesten, shader’da zengin silüete

Advanced Geometries serimizin bu zirve noktasında, işlemciyi (CPU) tamamen özgür bırakıp, geometrik detaylandırmayı bizzat ekran kartının (GPU) kalbine, yani vertex ve fragment shader katmanlarına devrediyoruz. GPU displacement, statik bir düşük poligonlu (low-poly) mesh’i, çalışma zamanında (runtime) milyonlarca poligonluk bir detaya dönüştürmenin en verimli yoludur. Canlı lab ölçüleri demo sabitleri tablosunda doc-gpu-disp-compare-demo.js ile eşlenir.

GPU displacement mekaniği

Aradaki fark, sadece hız değil, aynı zamanda verinin işlenme felsefesidir.

CPU tarafında

JavaScript ile her bir vertex’in pozisyonunu tek tek hesaplayıp buffer’ı güncellemeniz gerekir. Bu, her karede devasa bir verinin CPU’dan GPU’ya taşınması demektir (bant genişliği darboğazı).

GPU tarafında

CPU sadece düşük poligonlu bir kafes (cage) ve bir veri kaynağı (doku / gürültü) gönderir. GPU, her bir vertex’i paralel olarak işler ve saniyenin binde biri sürede koordinatlarını değiştirir. Pratikte bu yaklaşım, vertex deformation lab’ında GPU modunda gördüğünüz “birkaç uniform, binlerce vertex” fikrinin doğal uzantısıdır.

Canlı: CPU buffer vs GPU shader

Sol düzlem yalnızca sinüs tabanı ile çalışır; her karede JavaScript BufferAttribute güncellenir. Sağda aynı taban dalga vertex shader’da tutulur ve üzerine ek prosedürel detay (gürültü) eklenir — ek maliyet CPU’da vertex başına JS ile kopyalanmaz. Çözünürlüğü (224’e kadar) artırdıkça CPU maliyeti belirginleşir; CPU’yu gizleyerek FPS farkını netleştirin. Ölçüler demo sabitleri tablosunda özetlenir.

Displacement karşılaştırma
Sol: per-frame buffer update · Sağ: parallel vertex + procedural detail Çözünürlük: — FPS: —

Taban dalga CPU ile aynıdır; GPU tarafında vertex aşamasında ekstra noise katmanı vardır (performans kıyasında GPU hâlâ buffer yükü taşımaz).

Sol yalnızca taban dalga + per-frame buffer güncellemesi. Sağ taban dalga + prosedürel mikro detay; matematik vertex’lerde paralel, büyük segment sayılarında CPU tarafındaki bellek yazımı ile maliyet farkı büyür.

Demo sabitleri tablosu (CPU vs GPU displacement)

initGpuDispCompareDemo · sol düzlemde per-frame BufferAttribute, sağda aynı taban dalga + vertex shader’da ek gürültü.

initGpuDispCompareDemo · CPU buffer vs GPU vertex
Sahne / rol Parametre Değer Tür
Düzlem çifti PLANE_SIZE / PLANE_GAP boyut 7×7 · aralık 0.55 · rotateX(-π/2) · sol/sağ konum ±(PLANE_SIZE+GAP)/2 🔒 Sabit
CPU taban dalga heightWave amp×0.5×(sin+cos) · wt = t×speed · hız FIXED_SPEED 1.05 🔒 + ↔ UI
GPU yükseklik height() (vertex) taban dalga + uAmp×0.11×fine · vnoise UV (x,z)×(uFreq×3.1)+… · fdNormal e = 0.06 🔒 + ↔ UI
Segment MAX_SEG / yuvarlama aralık 12…224 (UI adım 4) · floor(seg/4)×4 veya 12 🔒 + ↔ UI
CPU materyal MeshStandardMaterial 0x4a7cbd · roughness 0.7 · metalness 0.1 🔒 Sabit
GPU fragment gpuFrag L normalize (0.38, 0.88, 0.52) · taban vec3(0.12, 0.42, 0.34) · lit = base×(0.22+0.78×ndl) 🔒 Sabit
Sis Fog 0x070910 · 10 / 48 🔒 Sabit
Işık HemisphereLight / DirectionalLight 0xb8e0ff / 0x1a1e28 · 0.82 · yönlü 1.02 (3.2, 9.5, 5.5) 🔒 Sabit
Renderer WebGLRenderer antialias: false · arka plan 0x070910 · setPixelRatio(min(dpr, 1.35)) · SRGBColorSpace 🔒 Sabit
Kamera PerspectiveCamera FOV 48 · yakın/uzak 0.1 / 100 · konum (0, 5.8, 13.2) 🔒 Sabit
OrbitControls hedef / mesafe / dönüş (0, 0.15, 0) · 5…28 · damping 0.07 · maxPolarAngle = π/2 − 0.1 · autoRotateSpeed 0.35 🔒 + ↔ UI
Girdi clamp readParams genlik 0.08…2.0 · frekans 0.15…2.4 · segment 12…224 🔒 + ↔ UI
HTML başlangıç range / toggles genlik 0.55 · frekans 0.85 · segment 48 · otomatik dönüş açık · wire / CPU gizle kapalı 🔒 + ↔ UI

Önemli kod kesiti

Sol taraftaki CPU yolu her karede heightWave ile Y ofsetini yazar; sağdaki GPU vertex shader’da aynı sinüs–kosinüs tabanına prosedürel mikro detay eklenir (FIXED_SPEED her iki tarafta ortak).

function heightWave(x, z, t, amp, freq, speed) {
  const wt = t * speed;
  return amp * 0.5 * (Math.sin(x * freq + wt) + Math.cos(z * freq + wt));
}

Teknik bileşenler: vertex texture fetch (VTF)

GPU displacement’ın ana yakıtı, önceki derslerimizde değindiğimiz displacement map’lerdir. Web katmanında uygulama, kullanılan WebGL sürümüne ve donanım desteğine göre değişiklik gösterir.

Vertex texture fetch (VTF): Modern WebGL (özellikle WebGL 2.0) ile artık vertex shader içinde doku örnekleme (texture sampling) yapılabilir. Bu teknikte vertex, dokudaki kendine karşılık gelen UV koordinatına bakarak yükseklik verisini doğrudan GPU üzerinde okur.

Uyumluluk ve performans: WebGL 2 ile bu süreç standartlaşmış olsa da, performans maliyeti ve eski cihazlardaki kararlılık sorunları nedeniyle birçok ileri seviye sistem bu veriyi hâlâ önceden hesaplanmış attribute’lar veya fragment shader tabanlı simülasyonlar üzerinden yönetmeyi tercih edebilir.

Doku kanalından gelen yükseklik mantığı için Height / Displacement map sayfasındaki ayrımı hatırlayın.

Kritik mühendislik: simüle edilmiş tessellation

Bir düzlemi (plane) GPU üzerinde yukarı kaldırmak kolaydır; ancak yeterli vertex yoksa sonuç bloklu ve kalitesiz görünür.

Subdivision stratejisi

Masaüstü GPU’lardaki gerçek donanımsal tessellation (hardware tessellation) WebGL standartlarında doğrudan mevcut değildir. Bu nedenle HoloDepth mimarisinde bu işlem genellikle önceden bölünmüş (subdivided) yüksek yoğunluklu geometriler veya shader tabanlı matematiksel tekniklerle simüle edilir.

Scale ve bias

Dokudan gelen veri genellikle 0 ile 1 aralığındadır. Bunu gerçek dünya ölçeğine taşımak için uDisplacementScale (yükseklik miktarı) ve uDisplacementBias (temel seviye ayarı) gibi uniform değerleri ile manipüle ederiz.

Normal ve ışık senkronizasyonu

GPU üzerinde noktaları hareket ettirdiğinizde, yüzeyin ışığı karşılama açısı değişir; ancak standart gölgelendirme hesaplamaları bu yeni pozisyondan haberdar olmaz — özetle silüet ile aydınlatma vektörü uyumsuz kalabilir.

Displacement + normal map

En keskin ve gerçekçi sonuçlar için displacement map ile birlikte bir normal map kullanılır: displacement geometrik formu (silüeti) değiştirirken, normal map mikro detaylardaki ışık kırılmalarını yönetir.

Shader derivatives

Daha ileri seviyede, shader içinde dFdx ve dFdy fonksiyonlarını kullanarak (türev alma yoluyla) anlık olarak yüzey normallerini hesaplayabilirsiniz. Bu yapılmazsa, yükselen tepeler düz bir kağıt gibi parlayacak ve derinlik hissi kaybolacaktır.

HoloDepth uygulama stratejileri

Bu tekniği HoloDepth projelerinde şu üç ana senaryo için kullanıyoruz:

  • Holografik dalgalanmalar: Bir küre veya düzlemin yüzeyini yüksek frekanslı gürültü ile displacement yaparak enerji kalkanı veya plazma efekti yaratmak.
  • Dinamik mikro detaylar: Düşük poligonlu bir zemin üzerine yüksek çözünürlüklü bir veri dokusu giydirerek, her taşın ve çukurun fiziksel olarak orada olduğu hissini vermek.
  • Veri görselleştirme: Topografik verileri veya ses frekanslarını doğrudan vertex’lere bağlayarak veriyi dokunulabilir bir 3D forma dönüştürmek.

Özet: geometride son nokta

GPU displacement, bir web geliştiricisinin elindeki en güçlü araçlardan biridir. Ancak WebGL dünyasında bu gücü kullanırken donanım limitlerini ve normal hesaplamalarını doğru yönetmek, projenin “profesyonel” ile “amatör” arasındaki farkını belirler.