Three.js · İleri geometri
Custom Attributes: Geometriye Kişisel Bir Kimlik Kazandırmak
Standart kanalların ötesinde, vertex başına özel veri taşımak
Advanced Geometri yolculuğunun bu durağında, Three.js’in sunduğu standart sınırların dışına
çıkıyoruz. position, normal ve uv gibi varsayılan
değerler bir objenin şeklini ve dokusunu belirler; ancak custom attribute’lar,
o geometriye özel davranış veya görsel “karakter” yükleyen ek veri
kanallarıdır.
Temel attribute modeli için Attributes & buffer’lar; özel geometri inşası için Custom BufferGeometry; çoklu örnek için Instancing.
Custom attribute nedir?
Kısaca: bir attribute, GPU’ya her bir vertex (veya ilgili shader girişi)
için gönderdiğiniz veri kanalıdır. Standart attribute’lar (ör. position)
motor ve materyal tarafından doğrudan kullanılır; custom attribute ise
adını ve anlamını siz tanımlarsınız — tipik olarak yazdığınız
ShaderMaterial / RawShaderMaterial içindeki GLSL kodu ile
anlamlandırılır.
Örneğin bir deniz yüzeyi simülasyonunda, her dalga tepesinin fazını, yüksekliğini veya bir parçacığın kalan ömrünü vertex başına taşıyarak CPU’da tek tek döngü yazmadan GPU’da yoğunlaştırabilirsiniz.
Neden “uniform” değil de “attribute”?
Yeni başlayanların sık karıştırdığı nokta: uniform tüm çizim çağrısı boyunca tek değerdir (zaman, genel renk, global parametre); tüm vertex’ler aynı uniform’u okur. Attribute ise vertex başına (veya ilgili düzenlemeye göre instance başına) farklı değer taşır — 10.000 noktanız varsa, teoride 10.000 ayrı “hız”, “ölçek” veya “parlaklık” katsayısı taşınabilir.
Bu ayrım, hem görsel çeşitlilik hem de performans stratejisi için kritiktir: örneğin instancing ile tek draw call altında her örneğe farklı karakter vermek, sıklıkla attribute (veya instance attribute) kombinasyonlarıyla kurulur.
| Tür | Kapsam | Tipik kullanım |
|---|---|---|
uniform |
Tüm vertex’ler / fragment’ler için ortak | Zaman uTime, genel renk, global eşik değerleri |
attribute / custom |
Vertex (veya instance) başına | Faz, ömür, rastgele ofset, köşe başına renk ağırlığı |
Bu ayrımı en net gösteren örneklerden biri nokta bulutu
(Points)
tabanlı sahnelerdir: her vertex kendi hızı, fazı, yönü ve ekran boyutuyla hareket edebilir.
Aşağıdaki canlı modelde yaklaşık 12.000 parçacık; vertex başına dört özel
kanal (aRandomSpeed, aRandomPhase, aRandomSize,
aRandomDir) taşınır.
Teknik ölçüler demo sabitleri tablosunda
doc-custom-attributes-demo.js ile satır satır eşlenir.
Uniform mod: tüm noktalar aynı yön ve hızla salınır; ölçek de ortaktır. Custom attribute mod: her vertex kendi shader verisini okur — bulut “dağılır” ve ritimleri farklılaşır.
Aynı geometri ve aynı zaman (uTime) ile iki mod arasında geçiş
yapın: fark sadece verinin tek mi yoksa vertex başına mı taşındığında
ortaya çıkar.
Demo sabitleri tablosu (Points · uniform ↔ attribute)
initCustomAttrParticleDemo ve buildParticleGeometry: aynı
ShaderMaterial içinde uAttrMix ile ortak uniform yolu ile
vertex başına kanallar arasında geçiş.
| Sahne / rol | Parametre | Değer | Tür |
|---|---|---|---|
| Örneklem | PARTICLE_COUNT |
12000 |
🔒 Sabit |
| Konum | küre içi + yarıçap | randomUnitSphere · r = 0.55 + rand × 0.95 |
🔒 Sabit |
| Custom float | aRandomSpeed |
0.55 + rand × 1.85 |
🔒 Sabit |
| Custom float | aRandomPhase |
rand × 2π |
🔒 Sabit |
| Custom float | aRandomSize |
4.2 + rand × 10.5 |
🔒 Sabit |
| Custom vec3 | aRandomDir |
birim küre yönü (randomUnitSphere) |
🔒 Sabit |
| Uniform (paylaşık yön) | uUniformDir |
(0.22, 1, 0.12) normalize |
🔒 Sabit |
| Uniform | uUniformSpeed / uUniformPointSize |
1.15 · 6.8 |
🔒 Sabit |
| Vertex shader | yer değiştirme | dir * sin(uTime × speed + phase) × 0.48 (speed /
dir uniform ↔ attribute mix)
|
🔒 Sabit |
| Vertex shader | gl_PointSize |
sizeBase × (320 / max(0.001, -mvPosition.z)) ·
clamp(2, 36)
|
🔒 Sabit |
| Fragment shader | daire + renk | discard if length(gl_PointCoord-0.5) > 0.5 ·
cyan–mor mix · α edge × 0.88 |
🔒 Sabit |
| Materyal | ShaderMaterial |
transparent: true · depthWrite: false ·
NormalBlending
|
🔒 Sabit |
| Kamera | PerspectiveCamera |
FOV 48 · yakın/uzak 0.06 / 80 · konum
(0, 0.15, 4.35)
|
🔒 Sabit |
| Pivot | dönüş / zaman | y += dt × 0.11 · x += dt × 0.04 ·
uTime += dt
|
🔒 Sabit |
| Renderer | makeRenderer |
ACESFilmicToneMapping · exposure 1.35 ·
SRGBColorSpace · setPixelRatio(min(dpr,2)) ·
setSize(…, true)
|
🔒 Sabit |
| Mod geçişi | uAttrMix |
uniform mod 0 · custom attribute mod 1 |
↔ UI |
| JS başlangıç | mode |
'attributes' (HTML ile uyumlu: Custom attribute mod seçili) |
🔒 Sabit |
Önemli kod kesiti
Geometriye position ile birlikte dört özel BufferAttribute
eklenir; shader’da
uAttrMix ile uniform tabanlı hareket ile per-vertex veri arasında
mix yapılır.
const PARTICLE_COUNT = 12000;
const geo = new THREE.BufferGeometry();
geo.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geo.setAttribute('aRandomSpeed', new THREE.BufferAttribute(aRandomSpeed, 1));
geo.setAttribute('aRandomPhase', new THREE.BufferAttribute(aRandomPhase, 1));
geo.setAttribute('aRandomSize', new THREE.BufferAttribute(aRandomSize, 1));
geo.setAttribute('aRandomDir', new THREE.BufferAttribute(aRandomDir, 3));
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0 },
uAttrMix: { value: 1 },
uUniformDir: { value: uUniformDir },
uUniformSpeed: { value: 1.15 },
uUniformPointSize: { value: 6.8 },
},
vertexShader: VERT,
fragmentShader: FRAG,
transparent: true,
depthWrite: false,
blending: THREE.NormalBlending,
});
function applyMode() {
const isAttr = mode === 'attributes';
material.uniforms.uAttrMix.value = isAttr ? 1 : 0;
}
Neden bu model? Attribute tam olarak vertex başına veridir; farkı en çok hissettiren şey, her noktanın bağımsız davranmasıdır. Üretimde sık görülen alternatifler (dalgalanan düzlem, küre deformasyonu, instanced küpler) bu sayfada da iş görür; ancak düzlem bazen displacement / mapping konusuyla karışır, kürede fark daha az belirgindir, instancing ise başlı başına ayrı bir konu başlığıdır.
Teknik yapılandırma ve veri akışı
Custom attribute eklerken verinin CPU’dan GPU’ya yolculuğu kabaca şu adımlarla özetlenir:
-
Veri hazırlama: JavaScript tarafında vertex sayınızla orantılı bir
Float32Array(veya ihtiyaca uygun başka typed array) oluşturursunuz. -
BufferAttribute: Bu diziyi Three.js’in anlayacağı birBufferAttribute(veya interleaved senaryosunda ilgili attribute sınıfı) ile sararsınız. -
Geometriye bağlama:
geometry.setAttribute('attributeName', attribute)ile kanalı geometriye eklersiniz. -
Shader’da okuma: Vertex shader’da uyumlu tipte bir giriş tanımlarsınız;
örneğin
attribute float aRandomSpeed;— ardından bu değeri pozisyon, normal veya başka çıktılara bağlayarak görsel manipülasyon yaparsınız.
Materyal tarafında attribute adlarının shader’daki isimlerle eşleşmesi gerekir; aksi halde veri sessizce yok sayılır veya bağlama hatasına yol açar.
HoloDepth projelerinde kullanım senaryoları
HoloDepth’in daha “premium” ve futuristik görsellerinde custom attribute’lar sık devreye girer — hazır kalıpların ötesine geçip atomik vertex verisiyle oynamanızı sağlarlar.
A. Vertex tabanlı animasyon
Her vertex’e örneğin aRandomSpeed gibi bir attribute vererek, bir kürenin
parçalarının farklı hızlarda dağılması veya yüzeyin dalga dalga hareket etmesi gibi
efektleri GPU üzerinde, CPU’da ağır döngüler yazmadan kurgulayabilirsiniz.
B. Köşe başına renklendirme
Doku yerine (veya dokuya ek olarak) color benzeri özel bir attribute ile
köşe başına renk taşıyarak ışık oyunları veya karmaşık geçişler kurabilirsiniz; yüksek
poligonlu “glassmorphism” tarzı yüzeylerde esneklik sağlar.
C. Gürültü ile displacement
Bir ofset veya genlik attribute’u ile düz bir PlaneGeometry’yi gerçek zamanlı
engebeli arazi veya dalgalanan yüzey gibi göstermek; uniform zaman + vertex attribute fazı
kombinasyonu tipik bir kalıptır.
Performans ve optimizasyon uyarısı
Custom attribute’lar güçlüdür; fakat her yeni kanal GPU’ya taşınan vertex verisinin boyutunu artırır — bant genişliği ve bellek baskısı doğrudan etkilenir.
-
Veri tipi: Değer aralığınız küçükse
Float32yerine daha dar tipler veya normalized integer formatları (ör. renk için) düşünün. - Gereksiz kanal yok: Shader’da gerçekten kullanmayacağınız attribute’u göndermeyin; kullanılmayan her kanal, bant genişliğinden “çalınan” lükstür.
- Önbellek / interleaved: Yoğun güncelleme senaryolarında veri düzenini interleaved buffer ile düşünmek, attribute sayısı arttıkça daha anlamlı hale gelir.
Özet: özgünlüğün sınırı
Custom attribute’lar, HoloDepth kullanıcılarına hazır modellerin ötesine geçip geometrinin atomik yapısına müdahale etme şansı verir. Standart geometriler birer kalıpsa, bu özel kanallar o kalıpları canlandıran sinir sistemi gibidir: doğru yerde, doğru miktarda veriyle kullanıldığında en yüksek etkiyi verir.