holodepth

Three.js · İleri geometri · Advanced Geometries (final)

Procedural Geometry: Kodla form inşa etmek

Statik dosya değil, çalışma zamanında üretilen yaşayan geometri

Advanced Geometries serisinin bu son aşamasında, hazır modelleme araçlarından (Blender, Maya vb.) tamamen kopmuyor; fakat geometrinin bizzat kendisini çalışma zamanında (runtime) matematiksel formüllerle inşa etme fikrine odaklanıyoruz. Procedural geometry (yordamsal geometri), önceden kaydedilmiş statik veriler yerine algoritmaların hüküm sürdüğü bir düzendir: aynı kod, farklı parametrelerle sonsuz varyasyon üretebilir.

Ön okuma: Indexed vs non-indexed, Custom attributes, Geometry optimization, Attributes lifecycle & buffer,
Geometri giriş. Her canlı örneğin altında kendi demo sabitleri tablosu vardır: parametrik, noise, regenerate, L-system — hepsi doc-procedural-geometry-demo.js ile satır satır eşlenir.

Matematiksel tasarım: fonksiyondan forma

Procedural (yordamsal) geometride, birçok senaryoda her bir vertex bir fonksiyonun çıktısıdır. Bir küreyi doğrudan SphereGeometry ile çağırmak yerine, trigonometrik denklemlerle (sin, cos) noktaların uzaydaki konumlarını siz hesaplayabilirsiniz; böylece şekil, veri dosyasından değil koddan türetilir.

Parametrik yüzeyler: Bir yüzeyin formunu tanımlamak için u ve v gibi parametreler kullanılır. Bu parametreler değiştikçe yüzey, bir kumaş gibi dalgalanabilir veya bir kabuk gibi kıvrılabilir; ızgara üzerinde örnekleme yaparak BufferGeometry doldurmak doğal bir sonraki adımdır.

Sonsuz varyasyon: Elinizde sabit bir .obj dosyası olmak zorunda değildir. Bunun yerine bir tohum (seed) değerine veya kullanıcı kaydırıcılarına göre her seferinde farklılaşan dağlar, ağaçlar, bulutlar veya soyut formlar üretebilirsiniz.

Canlı · parametrik yüzey

Form = matematik — her vertex u ve v ile tanımlanan dalga fonksiyonundan gelir; kaydırıcılar yalnızca yerel hesabı değiştirir.

Düzlem ızgara üzerindeki her köşe, aynı analitik yüzeyin örneklenmiş hâlidir; segment sayısı arttıkça eğri yumuşar, azalınca “dijital kırılım” belirginleşir. Dış veri veya ağ isteği yoktur.

Demo sabitleri tablosu (parametrik yüzey)

initParametricDemo; dört kökün bağlanması için L-system kod kesitindeki bootProceduralDemos bölümüne bakın (bu tabloda özet).

initParametricDemo · parametrik yüzey
Sahne / rol Parametre Değer Tür
Ortak makeRenderer ACESFilmicToneMapping · exposure 1.2 · SRGBColorSpace · setPixelRatio(min(dpr,2)) · arka plan 0x04060e 🔒 Sabit
Geometri PlaneGeometry 5.5×5.5 · segment uSeg×vSeg · rotateX(-π/2) · girdi clamp 4…64 🔒 + ↔ UI
Dalga vertex Y amp×sin(freq×2π×u)×cos(freq×2π×v) · u=x/5.5+0.5 · v=z/5.5+0.5 🔒 + ↔ UI
Materyal MeshStandardMaterial 0x4ad4c8 · metalness 0.15 · roughness 0.42 · DoubleSide 🔒 Sabit
Işık Ambient / Directional beyaz 0.35 · yönlü 1.05 konum (2.2, 4.5, 3.2) 🔒 Sabit
Kamera PerspectiveCamera FOV 42 · yakın/uzak 0.06 / 200 · konum (4.2, 3.4, 5.2) 🔒 Sabit
OrbitControls target (0, 0.2, 0) 🔒 Sabit
Modül bootProceduralDemos data-proc-demo="parametric"initParametricDemo (diğer kökler aynı fonksiyonda) 🔒 Sabit

Önemli kod kesiti

Her input değişiminde build() düzlemi yeniden kurar ve dalga ile position yüksekliğini yazar.

const geo = new THREE.PlaneGeometry(5.5, 5.5, uSeg, vSeg);
geo.rotateX(-Math.PI / 2);
const pos = geo.attributes.position;
for (let i = 0; i < pos.count; i++) {
  const x = pos.getX(i);
  const z = pos.getZ(i);
  const u = x / 5.5 + 0.5;
  const v = z / 5.5 + 0.5;
  const y =
    amp * Math.sin(freq * Math.PI * 2 * u) * Math.cos(freq * Math.PI * 2 * v);
  pos.setY(i, y);
}
pos.needsUpdate = true;
geo.computeVertexNormals();

Gürültü fonksiyonları (noise)

Doğadaki düzensizliği taklit etmek için bilgisayar biliminin en güçlü araçlarından biri noise fonksiyonlarıdır. Standart rastgele değerlerden farklı olarak, Perlin ve Simplex gibi gürültü aileleri genellikle sürekli ve yumuşak geçişler sunar; komşu noktalar birbirinden kopuk zıplamaz.

Kullanım alanı: Bir düzlemi (PlaneGeometry veya özel bir ızgara) alıp yükseklik veya yer değiştirmeyi noise ile modüle ettiğinizde, kısa sürede arazi, deniz yüzeyi veya organik deformasyon hissi elde edebilirsiniz. Gürültünün frekansını ve genliğini (amplitude) değiştirerek yumuşak tepelerden daha keskin varyasyonlara kadar kontrol sizde kalır.

Canlı · noise arazi (yerel, deterministik)

Seed değişince yeni dünya — aynı frekans ve genlikte bile topoğrafya tamamen farklı; bu, “sonsuz varyasyon” fikrinin somut hâlidir.

Üçlü gürültü (yerel hash + yumuşak interpolasyon) ile yükseklik üretilir; Perlin kütüphanesi yoktur, böylece demo hafif ve tamamen tarayıcı içi kalır. Frekans ölçeği küçüldükçe geniş tepeler, arttıkça daha sık detay görürsünüz.

Demo sabitleri tablosu (noise arazi)

initNoiseTerrainDemo · terrainHeight yerel smoothNoise2D katmanlarını kullanır.

initNoiseTerrainDemo · noise arazi
Sahne / rol Parametre Değer Tür
Ortak makeRenderer ACESFilmicToneMapping · exposure 1.2 · SRGBColorSpace · setPixelRatio(min(dpr,2)) · arka plan 0x04060e 🔒 Sabit
Geometri PlaneGeometry 7×7 · segment 56×56 · rotateX(-π/2) 🔒 Sabit
Yükseklik terrainHeight smoothNoise2D oktavları · katsayılar 1 · 0.45 · 0.22 · 0.11 · çıktı (n−0.48)×amp 🔒 + ↔ UI
Materyal MeshStandardMaterial 0x6eb87a · metalness 0.08 · roughness 0.62 · DoubleSide 🔒 Sabit
Işık Ambient / Directional beyaz 0.38 · yönlü 0xfff0e0 yoğunluk 1.05 konum (-3, 6, 2) 🔒 Sabit
Kamera PerspectiveCamera FOV 40 · yakın/uzak 0.08 / 200 · konum (5.5, 4.2, 6.2) 🔒 Sabit
OrbitControls target (0, 0.35, 0) 🔒 Sabit

Önemli kod kesiti

Kaydırıcılar applyHeights() ile tüm köşelerin Y değerini günceller.

function applyHeights() {
  const freq = Number(inFreq.value);
  const amp = Number(inAmp.value);
  const seed = Math.round(Number(inSeed.value));
  const pos = geo.attributes.position;
  for (let i = 0; i < pos.count; i++) {
    const x = pos.getX(i);
    const z = pos.getZ(i);
    pos.setY(i, terrainHeight(x, z, seed, freq, amp));
  }
  pos.needsUpdate = true;
  geo.computeVertexNormals();
}

Dinamik topoloji ve buffer manipülasyonu

Procedural geometri yalnızca ilk şekli üretmekle kalmaz; aynı zamanda bu şekli canlı tutabilir. Kullanıcı etkileşime girdiğinde (örneğin fare ile bir bölgeye dokunma), BufferAttribute içindeki sayıları anında yeniden hesaplayıp GPU’ya haber vermeniz gerekir: Three.js’te bu sinyal needsUpdate bayrağıdır; kısmi yükleme için güncel sürümlerde addUpdateRange / clearUpdateRanges kullanımını buffer lifecycle sayfasında özetledik. Aşağıdaki iki figürün her birinin altında o demoya özel demo sabitleri ve L-system sabitleri tabloları bulunur.

Canlı · vertex yenileme

Geometry = hesaplanan veri — procedural modda her karede pozisyon buffer’ı yeniden yazılır; statik modda ise son anlık görüntü dondurulur.

Statik mesh: anlık yüzeyi dondurur (örneğin bir kareyi yakalamak için). Procedural regenerate: zamanla sürekli yeni dalga formülü yazar; GPU’ya needsUpdate ile haber verilir. Düğme, statik moddayken farklı bir “fotoğraf” almanız için fazı kaydırır.

Demo sabitleri tablosu (vertex regenerate)

initRegenerateDemo · statik / procedural modları aynı düzlem buffer’ında needsUpdate ile ayırır.

initRegenerateDemo · statik ↔ procedural
Sahne / rol Parametre Değer Tür
Ortak makeRenderer ACESFilmicToneMapping · exposure 1.2 · SRGBColorSpace · setPixelRatio(min(dpr,2)) · arka plan 0x04060e 🔒 Sabit
Geometri PlaneGeometry 4.5×4.5 · segment 42×42 · rotateX(-π/2) · baseY Float32Array 🔒 Sabit
Statik dalga staticWaveY çift sinüs terimi + sin((x+z)×3.2 + t×2.2) · bakeStaticInitial başlangıç t≈0.85 🔒 Koşul
Procedural dalga proceduralWaveY morfoloji frekansı · drift · ridge · smoothNoise2D örneklemesi 🔒 Koşul
Zaman procTime procedural modda procTime += dt × 0.18 · düğme pulsePhase += 1.7 🔒 + ↔ UI
Materyal MeshStandardMaterial 0x7aa8ff · metalness 0.12 · roughness 0.45 · DoubleSide 🔒 Sabit
Işık Ambient / Directional beyaz 0.4 · yönlü 1 konum (2, 5, 3) 🔒 Sabit
Kamera PerspectiveCamera FOV 42 · yakın/uzak 0.08 / 200 · konum (3.6, 2.8, 4.4) 🔒 Sabit
OrbitControls target (0, 0, 0) 🔒 Sabit
JS başlangıç mode 'static' · HTML: Statik mesh seçili 🔒 + ↔ UI

Önemli kod kesiti

Procedural modda her karede proceduralWaveY ile Y yeniden yazılır; sonra needsUpdate ve normal yeniden hesaplanır.

if (mode === 'proc') {
  procTime += dt * 0.18;
  for (let i = 0; i < pos.count; i++) {
    const x = pos.getX(i);
    const z = pos.getZ(i);
    pos.setY(i, proceduralWaveY(x, z, procTime, pulsePhase));
  }
  pos.needsUpdate = true;
  geo.computeVertexNormals();
}

L-systems (Lindenmayer sistemleri): Bitki büyüme örüntülerini veya fraktal dallanmaları modellemek için kullanılan kural kümeleridir. Tek bir çizgi veya basit bir başlangıçla, özyinelemeli kurallarla genişleyen yapılar kurup bunları üçgene veya çizgiye dökmek procedural düşüncenin klasik örneklerindendir.

Showcase · Koch / L-idea

Procedural yalnızca yüzey değildir — aynı mantık, çizgi ve kural genişlemesiyle fraktal büyüme gösterir.

Klasik Koch dizesi (F → F+F−F−F+F, 90° dönüş) ile üretilen çizgi; iterasyon arttıkça dize uzunluğu hızla büyür, bu yüzden üst sınır 4 ile sınırlıdır. Gerçek bitki L-system’leri daha zengin alfabe ve yığın sembolleri kullanır; burada fikir gösterimi amaçlanmıştır.

Demo sabitleri tablosu (Koch / L-system)

initLsystemDemo · Koch dizesi üretimi ve bbox ile sahneye sığdırma.

initLsystemDemo · Koch çizgisi
Sahne / rol Parametre Değer Tür
Ortak makeRenderer ACESFilmicToneMapping · exposure 1.2 · SRGBColorSpace · setPixelRatio(min(dpr,2)) · arka plan 0x04060e 🔒 Sabit
Kural expandKoch F → F+F-F-F+F · başlangıç dizesi 'F' 🔒 Sabit
Kaplumbağa ANGLE / TURTLE_STEP π/2 · 1 🔒 Sabit
Güvenlik dize uzunluğu genişleme döngüsünde maxLen 120000 aşılırsa dur 🔒 Sabit
İterasyon inIter clamp 0…4 (girdi) 🔒 + ↔ UI
Yerleşim bbox ölçek hedef genişlik 5.2 · y = 0.04 🔒 Sabit
Çizgi LineBasicMaterial 0xffd24a 🔒 Sabit
Işık Ambient / Directional beyaz 0.55 · yönlü 0.9 konum (0, 8, 4) 🔒 Sabit
Kamera PerspectiveCamera FOV 38 · başlangıç (0, 5.5, 10) · boundingSphere ile yakın/uzak ve konum ayarı 🔒 Koşul
Modül bootProceduralDemos data-proc-demo="lsystem"initLsystemDemo 🔒 Sabit

Önemli kod kesiti

Koch kuralı: her iterasyonda F beş karakterlik dizgeyle genişler. Aynı dosyada dört canlı örneği bağlayan giriş bootProceduralDemosdır (üstteki dört tabloda da kısaca geçer).

function expandKoch(s) {
  let out = '';
  for (let i = 0; i < s.length; i++) {
    const ch = s[i];
    if (ch === 'F') out += 'F+F-F-F+F';
    else out += ch;
  }
  return out;
}

function bootProceduralDemos() {
  document.querySelectorAll('[data-proc-demo]').forEach((root) => {
    const kind = root.getAttribute('data-proc-demo');
    if (kind === 'parametric') initParametricDemo(root);
    else if (kind === 'noise') initNoiseTerrainDemo(root);
    else if (kind === 'regenerate') initRegenerateDemo(root);
    else if (kind === 'lsystem') initLsystemDemo(root);
  });
}

Neden procedural? (HoloDepth vizyonu)

HoloDepth perspektifi

Modern ve fütüristik bir 3D web platformunda procedural yaklaşımların öne çıkmasının birkaç güçlü gerekçesi vardır:

  • Düşük dosya boyutu: Gigabaytlarca önceden modellenmiş veri indirmek yerine, çoğu zaman kısa bir matematik tanımı ve birkaç parametre taşınır; dünya, kullanıcının tarayıcısında o an üretilir.
  • Sonsuz detay: Kullanıcı bir bölgeye yaklaştıkça, algoritma o bölge için daha ince bir ızgara veya daha zengin kurallarla detay üretebilir (fraktal yakınlaştırma mantığıyla ilişkilendirilebilir).
  • Benzersiz deneyim: Parametreler veya tohum değiştiğinde, her oturumda dünyada eşi benzeri olmayan bir geometri ile karşılaşmak mümkündür.

Teknik uygulama stratejisi

Bir procedural geometri hattı kurarken sık görülen yapı taşları şunlardır:

Teknik Kısa tanım Tipik kullanım
Voxel tabanlı yapılar Veriyi 3B ızgarada (küp hücrelerde) saklama. Minecraft benzeri blok dünyalar, hacimsel düzenleme.
Marching cubes Yoğunluk alanından üçgen ağı çıkarma. Tıbbi hacim verisi, akışkan yüzeyi, “iso-surface” önizlemesi.
Parametrik ızgara + noise u, v üzerinde örnekleme ve gürültü ile yükseklik. Arazi, dalga, basit organik yüzeyler.

Bu tablo “her şeyi marching cubes yapın” demez; ama hangi matematiksel temsilin (voxel alan mı, parametrik yüzey mi) sizin probleminize uyduğunu seçmenize yardım eder.

Özet: geometrinin geleceği

Advanced Geometries üst konusunu burada tamamlarken şunu netleştirebiliriz: geometri artık yalnızca statik bir dosya değil, yaşayan ve gelişen bir veri kümesi olarak düşünülebilir. Indexed yapı ile verimlilik, custom attribute’lar ile ifade gücü, optimizasyon ile hız disiplini ve son olarak procedural yöntemlerle sonsuzluk ve varyasyon aynı haritada bir araya gelir.