Three.js · İleri geometri
Geometry Optimization: Performansın Görünmez Mimarisini İnşa Etmek
Görsel kaliteyi koruyarak GPU yükünü bilinçle düşürmek
HoloDepth’in yüksek performanslı 3D dünyasında bir modelin yalnızca iyi görünmesi yetmez; aynı zamanda saniyede 60 (veya 120) karede akıcı çalışması gerekir. Geometry optimization, ham vertex verisini ve çizim stratejisini, görünür kaliteyi gereksiz yere düşürmeden GPU üzerindeki maliyeti minimize etme disiplinidir. Altın cümle: Performansın düşmanı poligon değil, koordinasyon maliyetidir.
Bu sayfada darboğazları tanıyıp draw call ve geometri birleştirme, çözünürlük /
LOD, buffer kullanım ipuçları ve InstancedMesh gibi araçlarla “akıllı veri”
tarafını
özetliyoruz. Bağlam için
Geometri giriş,
Indexed vs
non-indexed ve
Instancing sayfalarına dönebilirsiniz.
Canlı ölçüler için demo
sabitleri tablosuna da bakabilirsiniz.
1000 obje → CPU ~1000 komut; birleştirilmiş veya instanced tek yükte ~1 komut — farkı hem sayaçta hem görselde (renk / hover) okuyun. Aynı ızgarada 1000 küp: mod sekmeleri sahneyi yeniden kurar; draw call modunda birleştirilmiş tarafta hafif sınır ızgarası tek mesh alanını vurgular. LOD’da orbit veya Yakın/Uzak kısayolları; draw / instancing’de imleci sahne üzerinde gezdirerek hover vurgusunu deneyin.
Draw call / instancing: çoklu mesh modunda her küp farklı renkte;
birleştirilmiş veya InstancedMesh modunda tek “batch” rengi (Holodepth
camgöbeği) ile alan bütünleşir — gözle de “tek yük” ayrımı netleşir. Birleştirilmiş
draw modunda zemin üzerindeki ince ızgara, tek geometri sınırını görsel olarak
pekiştirir.
Hover: ayrı mesh’te yalnızca bir küp parlar; birleşik blokta tüm gövde aydınlanır;
instanced modda ise tek bir örnek vurgulanır. Üstteki Draw calls bir
kareden sonra sıfırlanır; LOD ve buffer modlarında ise sahne farklı bir stres profili
gösterir.
Demo sabitleri tablosu (Optimization Playground)
Aşağıdaki tablo doc-geometry-optimization-demo.js içindeki
initGeometryOptimizationDemo ile aynı sabitleri listeler; dört sekme sahneyi
yeniden kurar, alt satırlardaki toggles ise ilgili modun alt durumunu değiştirir.
| Sahne / rol | Parametre | Değer | Tür |
|---|---|---|---|
| Örneklem | N |
1000 küp / instance |
🔒 Sabit |
| Izgara yerleşimi | GRID_COLS / GRID_ROWS / GRID_SPACING |
40 · 26 · 0.21 |
🔒 Sabit |
| Paylaşılan küp | BoxGeometry (sharedBox) |
(0.11, 0.11, 0.11) |
🔒 Sabit |
| Çoklu mesh renk | randomHueColor |
HSL: altın oran ile i · S 0.74 · L 0.56 |
🔒 Sabit |
| Birleştirilmiş draw | mergeGeometries |
BufferGeometryUtils · klon + applyMatrix4 çeviri ·
useGroups: false
|
🔒 Sabit |
| Birleşik gövde | mergedSolidMat |
MeshBasicMaterial · 0x5ec8ff |
🔒 Sabit |
| Instancing | InstancedMesh + renk |
instanceColor · DynamicDrawUsage · başlangıç cyan tabanı
|
🔒 Sabit |
| Sınır ızgarası | buildBatchBoundaryLines |
LineBasicMaterial 0x7ae8ff · opaklık 0.32 ·
depthWrite: false
|
🔒 Koşul |
| LOD gövde | lodHigh / lodMid / lodLow |
boyut (2.35)³ · segment 14³ / 4³ /
1³
|
🔒 Sabit |
| LOD hedef / eşik | lodTarget · mesafe d |
(0, 1.05, 0) · d > 17 düşük · d > 9.2
orta · aksi yüksek |
🔒 Sabit |
| LOD materyal | lodMat |
MeshStandardMaterial · 0x6ad0ff · metalness
0.12 · roughness 0.42
|
🔒 Sabit |
| Buffer düzlem | PlaneGeometry |
7×7 · segment 42×42 · rotateX(-π/2) |
🔒 Sabit |
| Buffer materyal | bufferMat |
0x7c5cff · DoubleSide |
🔒 Sabit |
| Buffer usage | position.setUsage |
StaticDrawUsage · DynamicDrawUsage (alt mod) |
↔ UI |
| Dynamic dalga | updateBufferDynamic |
y += sin(x×0.85 + t×0.0018) × 0.06 × cos(z×0.7 + t×0.0012) (taban
üzerine) |
🔒 Koşul |
| Işık | HemisphereLight |
0xb8dcff / 0x101520 · yoğunluk 0.95 |
🔒 Sabit |
| Işık | DirectionalLight |
beyaz · yoğunluk 1.35 · konum (4.5, 8.2, 5) |
🔒 Sabit |
| Kamera | PerspectiveCamera |
FOV 42 · yakın/uzak 0.06 / 220 · konum
(4.6, 3.15, 5.85)
|
🔒 Sabit |
| LOD kısayol | btnLodNear / far |
kamera (3.2, 2.4, 4.2) · (22, 16, 28) · hedef
lodTarget
|
↔ UI |
| OrbitControls | target / dampingFactor |
(0, 0.25, 0) · 0.06 · maxPolarAngle ≈ 0.49π
|
🔒 Sabit |
| Renderer | makeRenderer |
ACESFilmicToneMapping · exposure 1.28 ·
SRGBColorSpace · setPixelRatio(min(dpr,2)) · arka plan
0x04060e
|
🔒 Sabit |
| Metrik | renderer.info.render |
calls · triangles (her kare sonunda) |
🔒 Sabit |
| JS başlangıç | mainMode / drawSub / instanceSub /
bufferSub
|
'draw' · 'many' · 'many' ·
'static' (HTML ile uyumlu)
|
🔒 + ↔ UI |
Önemli kod kesiti
Dört sekme aynı sahne grubunu (content) temizleyip yeniden doldurur; çekirdek
yönlendirme rebuild() içinde toplanır.
function rebuild() {
clearContent();
if (mainMode === 'draw') {
if (drawSub === 'many') buildManyCubes();
else buildMergedCubes();
} else if (mainMode === 'instance') {
if (instanceSub === 'many') buildManyCubes();
else buildInstanced();
} else if (mainMode === 'lod') {
buildLodObject();
} else if (mainMode === 'buffer') {
buildBufferPlane();
}
}
Draw call kavramı ve darboğazlar
Optimizasyonun ilk kuralı, maliyetin nereden geldiğini doğru okumaktır. Birçok projede en büyük sürtünme yalnızca poligon sayısı değil; CPU’nun GPU’ya sürekli “şimdi bunu çiz” komutu göndermesiyle büyüyen draw call yüküdür.
Sorun: Her ayrı çizim çağrısında sürücü ve API katmanı devreye girer; binlerce küçük mesh aynı sahneyi kalabalıklaştırırken iletişim hattı (bus / validation) tıkanabilir.
Geometry merging: Birbirine yakın ve aynı materyali
paylaşan parçaları tek bir BufferGeometry içinde birleştirerek yüzlerce küçük
emri tek büyük çizime indirgemek klasik ve etkili bir çözümdür — tabii materyal ve
attribute düzeni uyumlu olmalıdır.
Batching ve instancing: merging (batching) tek geometri üretir; instancing
aynı geometriyi çoğaltır. Batching’de vertex/index listesi gerçekten birleşir (UV atlası,
materyal uyumu gibi konular gündeme gelir); instancing’de ise taban
BufferGeometry paylaşılır, her kopyanın dönüşümü (ve gerekiyorsa renk gibi
veriler) instance tarafında taşınır — aşağıdaki bölümde bu ikinci modeli
ayrıntılandırıyoruz.
Bu farkı sayılarla görmek için yukarıdaki Optimization Playground demosuna göz atın; ölçüler için demo sabitleri tablosuna bakın.
Vertex sayısı ve hassasiyet (çözünürlük)
Bir modelin detay seviyesi (çözünürlük), optimizasyonun merkezindedir: gereksiz her vertex, vertex shader’da işlenecek ekstra matematik ve bellek / bant genişliği demektir.
LOD (Level of Detail) stratejisi
Kullanıcıya yakın nesneler yüksek poligonlu gösterilirken, uzaktakiler daha basit geometriyle değiştirilmelidir. Kameraya göre dinamik LOD kuran sistemler, sahne karmaşıklığını ciddi ölçüde düşürebilir — HoloDepth tarafında bu, “her karede en pahalı mesh’i çizmek zorunda değiliz” disiplininin ta kendisidir.
Normal map ile detay
Milyonlarca üçgenle modellenmiş yüzey mikro detayını, düşük poligonlu bir gövdeye giydirilen normal map ile taklit edebilirsiniz: ışık, yüzeyde sanki ekstra geometri varmış gibi hesaplanır; oysa taban mesh yalnızca az sayıda vertex taşıyabilir.
Buffer optimizasyonu: static vs dynamic
Verinin GPU belleğinde nasıl işaretlendiği, güncelleme sıklığına göre performansı etkiler.
BufferGeometry attribute’larında kullanım amacını doğru seçmek kritiktir.
-
THREE.StaticDrawUsage(varsayılan): Veri bir kez yüklenir ve seyrek veya hiç değişmez. Statik sahneler, binalar, prop’lar için uygundur. -
THREE.DynamicDrawUsage: Veri her karede veya sık sık güncellenecekse (ör. dalgalanan su, deformasyon) kullanılır; sürücü veriyi daha sık güncellenebilir kabul eder.
Yanlış seçim: Hareket etmeyen bir yapıyı “dynamic” işaretlemek, gereksiz bellek trafiği ve doğrulama maliyeti yaratarak FPS’i düşürebilir. Gerçekten değişen attribute’lar için dynamic; geri kalan için static düşünün.
Yoğun attribute güncellemelerinde veri düzenini interleaved buffer ile ele almak da ayrı bir optimizasyon eksenidir.
InstancedMesh: klonlama ordusu
Aynı geometriden çok sayıda kopya (orman ağaçları, sunucu rafları, parçacık benzeri
tekrarlar)
gerekiyorsa her birini ayrı Mesh olarak tutmak çoğu zaman verimsizdir. Bu
senaryoda hedef, üst bölümdeki batching gibi tek bir süper-mesh üretmek
değil; aynı örgüyü defalarca referanslayıp draw call’ı yine düşürmektir.
- Geometri GPU’ya tek kez yüklenir.
- Her örnek için yalnızca değişen veri (dönüşüm, renk vb.) instance kanalı veya
InstancedMeshmatrisleriyle taşınır. - Tek draw call altında binlerce kopya çizilebilir.
Ayrıntılar ve API için Instancing sayfasına bakın; bu bölüm geometri optimizasyonu perspektifinde “tekrar eden şekil = instancing adayı” kuralını pekiştirir.
HoloDepth için altın kurallar
Geometri optimizasyonu yaparken şu kontrol listesini yanınızda tutun:
-
Veri tiplerini küçültün: Gereksiz
Float32hassasiyetinden kaçının; aralık uygunsa daha dar tipler veya normalize edilmiş tam sayı formatları değerlendirin ( Attributes & buffer’lar). - Vertex paylaşımı: Indexed geometry ile aynı köşeyi gereksiz yere çoğaltmayın.
- Frustum culling: Kameranın dışında kalan nesneler için Three.js varsayılan culling’i kullanın; çok özel sistemlerde manuel katmanlar veya BVH tabanlı seçim gerekebilir.
Derin not
Gerçek bir optimizasyon uzmanı “daha ne eklerim?” değil, görünürlüğü bozmadan neyi çıkarırım? diye sorar — vertex, draw call ve buffer kullanımı bu sorunun doğrudan cevaplarıdır.