holodepth

Three.js · Geometri

Attributes ve Buffer’lar (veri katmanları)

Geometri = GPU’ya giden sayılar

Three.js’te bir geometri, GPU belleğine aktarılan bir dizi sayıdan ibarettir. Bu sayılar rastgele değil; BufferAttribute adı verilen yapılarda, belirli bir düzende (interleaved veya sequential) saklanır. GPU, bu buffer’lar üzerinden okuma yaparak her bir noktayı ekrandaki piksellere dönüştürür.

Attribute nedir?

Attribute = her vertex için tekrar eden veri bloğu. Yani “modelin verisi” dediğiniz şey, aslında vertex sayısı boyunca tekrar eden sütunlardır: position, normal, uv, color…

GPU bir shader’ı çalıştırdığında her vertex için şu soruları sorar:

  • Position: Neredesin?
  • Normal: Nereye bakıyorsun?
  • UV: Üzerine hangi doku (texture) parçasını giyeceksin?
  • Color: (Eğer varsa) Senin rengin ne?

GPU her vertex için attribute’ları tekrar tekrar okur. Yani 1000 vertex varsa position, normal, uv gibi tüm attribute’lar 1000 kez işlenir.

Three.js tarafında bunların hepsi geometride bir isimle tutulur: geometry.attributes.position, normal, uv, color vb.

Typed Arrays ve BufferAttribute

JavaScript’in standart dizileri (Array) esnektir ama grafik tarafında veri transferi için pahalıdır. Bu yüzden TypedArray (özellikle Float32Array) kullanılır: bellekte kesintisiz bir blok kaplar; GPU veriyi tek bir hamlede “yutabilir”.

Item size, bir attribute’un kaç bileşenden oluştuğunu belirtir:

  • position için 3 (x, y, z)
  • uv için 2 (u, v)
  • normal için 3 (x, y, z)

Teknik tablo: buffer tipleri ve kullanım amaçları

Buffer türü İçerik GPU rolü
StaticDraw Çoğu geometri için varsayılan senaryo (küp, küre, statik mesh). Default düşün: Veri genelde bir kez yüklenir, çok hızlı okunur.
DynamicDraw Vertex sürekli değişiyorsa (animasyon, dalga, deformasyon). Önemli: Sık güncelleme için; CPU→GPU akışı vardır.
StreamDraw Çok nadir güncellenen veriler. Nadir: Bazı akış senaryoları için; çoğu projede gerekmez.

GPU’ya veri gönderme: interleaved vs sequential

Profesyonel projelerde veriyi nasıl dizdiğiniz, GPU’nun önbellek (cache) davranışını etkiler.

  • Sequential (ardışık): Önce tüm konumlar, sonra tüm normaller yazılır. CPU tarafında üretmesi ve yönetmesi kolaydır (Three.js default).
  • Interleaved (iç içe): Bir vertex’in konumu, normali, rengi bellekte yan yana yazılır: [pos, norm, col, pos, norm, col]. GPU tek bir okumada o vertex hakkındaki her şeyi aldığı için büyük veri setlerinde cache performansı daha iyi olabilir.

Kısa karar rehberi: “önce doğru çalışsın” diyorsanız sequential; veri setiniz devasa ve erişim paterni netse interleaved bazı GPU’larda daha iyi çıkabilir. (Her cihazda garanti değil; ölçmek gerekir.)

Görsel şema: aynı veri, iki farklı dizilim

Aşağıdaki şema, GPU’nun bellekte “nasıl yürüdüğünü” hissettirir. Solda ardışık kanallar, sağda vertex başına paketlenmiş kayıtlar:

Sequential → yönetimi kolay (Three.js default) · Interleaved → cache dostu olabilir (büyük veri).

Sequential (kanal kanal) Interleaved (vertex vertex)
[pos][pos][pos][pos]...
[normal][normal][normal][normal]...
[uv][uv][uv][uv]...
[pos norm uv][pos norm uv][pos norm uv]...
[pos norm uv][pos norm uv][pos norm uv]...

Uygulama: özel bir attribute eklemek

Sadece konumu değil, her vertex’e rastgele bir “boyut” veya “hız” bilgisi ekleyip shader’da kullanmak için, yeni bir TypedArray oluşturup geometriye isimle bağlarsınız. GPU bu veriyi shader içinde attribute float aSize olarak tanır.

Bağlantı şu: bu değer, vertex shader’da bir hesapta “çarpan” olur. Örneğin point cloud çiziyorsanız: gl_PointSize = aSize * 10.0;

const geometry = new THREE.BufferGeometry();
const count = 5000;

// Her vertex için 1 değer (itemSize: 1)
const sizes = new Float32Array(count);

for (let i = 0; i < count; i++) {
    sizes[i] = Math.random(); // 0 … 1 arası rastgele ölçek
}

// 'aSize' adında özel bir attribute oluşturuyoruz
geometry.setAttribute('aSize', new THREE.BufferAttribute(sizes, 1));

// GPU bu veriyi shader içerisinde 'attribute float aSize' olarak tanıyacak.
attribute float aSize;

void main() {
  // ... position transform ...
  gl_PointSize = aSize * 10.0;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

Mini araç: attribute belleğini anında hesapla

“Bu geometri kaç KB/MB yer tutar?” sorusu pratikte en çok iş yapan refleks. Aşağıdaki araç, seçtiğiniz vertex sayısı ve attribute seti için yaklaşık ham veri boyutunu hesaplar — Three.js’te sık kullanılan Float32Array / Float32 varsayımıyla (her bileşen 4 byte).

Bu bir GPU sürücü raporu değildir: index buffer, geometri meta verisi, InterleavedBuffer hizalama dolgusu ve doku belleği dahil değildir; ama “sadece bu dört attribute ile kaç MB büyür?” tahmini için hızlı bir cetvel işlevi görür.

Attribute bellek sayacı

Float32 · canlı tahmin

Hangi attribute’lar hesaba katılsın?
Tahmini toplam

Satır satır (Float32)

  • position
  • normal
  • uv
  • color

index buffer ve geometri ötesi bellek bu toplama dahil değildir.

Holodepth notu: bellek bütçesi

Attribute’lar çok hızlı büyür: önce ihtiyacı ölç

Her bir Float32Array elemanı bellekte 4 byte yer kaplar. 1 milyon vertex’li bir modelde sadece position verisi bile yaklaşık 12 MB (\(1{,}000{,}000 \times 3 \times 4\) byte) yer tutar.

Normaller, UV’ler ve diğer attribute’lar eklendikçe bu miktar hızla artar. Mobil cihazlarda çökme yaşamamak için her zaman ihtiyacınız olmayan attribute’ları temizleyin ve gerekiyorsa LOD / basitleştirme stratejileri kullanın.