holodepth

Three.js · Doku · PBR

Texture türleri: Height / Displacement Map (fiziksel derinlik)

Daha önce işlediğimiz Normal Map, yüzeyde bir derinlik illüzyonu yaratıyordu. Objeye tam yandan baktığınızda ise yüzeyin aslında dümdüz olduğunu fark ederdiniz. Displacement map bu kuralı bozar: köşe noktalarını (vertex) yerel normal doğrultusunda fiziksel olarak öteleyerek silüeti ve gölge hattını değiştirir — yani artık sadece piksel boyası değil, üçgen topolojisi işin içindedir.

Bu harita da tipik olarak gri tonlu bir veri yüzeyidir; fakat etkisi yalnızca piksel boyamakla sınırlı değildir — geometriyi yeniden şekillendirir. Aynı gri veri çoğu DCC hattında normal üretimi için de kaynak olur; WebGL tarafında ise «önce gerçekten oynat, gerekirse üstüne normal ile mikro detay» ayrımını kurmak performans için kritiktir.

Bağlam: Albedo, Normal map, Roughness map, Ambient occlusion, Renk uzayı, MeshStandardMaterial, UV mapping.

Displacement mantığı: geometriyi yeniden şekillendirmek

Ambient occlusion da gri tonlu bir maske olabilir; fakat orada veri «dolaşım zayıflığı» kodlarken, height / displacement haritası yükseklik ölçeği taşır ve motor bunu vertex öteleme talimatına çevirir. Yani aynı dosya formatı gibi görünse de anlam farklıdır:

  • Siyah (≈ 0,0): Yüzeyin olduğu yerde kalacağını veya aşağı doğru çekileceğini belirtir.
  • Beyaz (≈ 1,0): Yüzeyin normal yönünde dışa fiziksel olarak itileceğini belirtir.
  • Gri tonlar: İtme miktarının şiddetini belirleyen geçiş bölgeleridir.

Üretimde «siyah aşağı, beyaz yukarı» yönü içerik paketine göre ters da olabilir; displacementScale işaretini veya haritayı ters çevirmeyi unutmayın. glTF tarafında yükseklik çoğu zaman ayrı doku değil, normal ile birlikte kaynak olarak kalır — doğrudan WebGL’de displacementMap bağlarken bu kökeni not edin.

Kritik gereksinim: poligon yoğunluğu (subdivision)

HoloDepth mühendislerinin en sık düştüğü hata, düşük poligonlu bir modele displacement map ekleyip sonuç alamamaktır.

Vertex bağımlılığı: Displacement, vertexleri hareket ettirir. Objeniz yalnızca dört köşeden oluşan bir düzlemse (Plane), harita teoride yalnızca o dört köşeyi oynatabilir; ortada yeni köşe yoksa orta kısımda detay oluşmaz.

Çözüm: Haritadaki detayı görebilmek için geometrinin yeterince segment / bölünme ile yoğunlaştırılmış olması gerekir. Bu da doğrudan GPU yükünü ve üçgen sayısını artırır.

İleri seviye motorlarda adaptif tessellation veya mesafeye göre dinamik LOD ile aynı fikir yönetilir; saf Three.js sahnesinde ise çoğu zaman elle segments seçilir; bu sayfadaki demo, düşük ve yüksek segmenti yan yana okumanız için bilinçli olarak sertleştirilmiştir.

Displacement ve Normal Map

Neden her zaman displacement kullanmıyoruz? Özet karşılaştırma:

Karşılaştırma özeti
Özellik Normal Map Displacement Map
Görsel etki Işık / gölge illüzyonu Gerçek fiziksel çıkıntı
Silüet Kenarlar düz kalır Kenarlar pürüzlü ve girintili görünür
Performans Çok hızlı ve hafif Ağır (yüksek poligon ister)
Kullanım Küçük çatlaklar, gözenekler Büyük taşlar, tuğlalar, dağlar vb.

Orta yol olarak parallax / POM gibi teknikler silüeti tam kırmadan derinlik hissi verir; maliyeti displacement’tan düşük, normalden yüksektir. Detay için Normal map sayfasındaki bump / displacement ayrımına geri dönebilirsiniz — burada odak tamamen gerçek geometri öteleme üzerindedir.

Three.js uygulama ve scale yönetimi

Three.js içinde displacement kullanırken iki ana parametre hayati önem taşır:

  • displacementScale: Çıkıntıların ne kadar yüksek olacağını belirler. Küçük bir hata objenin patlamasına veya kirpi gibi görünmesine neden olabilir.
  • displacementBias: Çıkıntıların «sıfır noktasını» belirler; objeyi genel olarak şişirmek veya içeri gömmek için kullanılır.

displacementMap yokken displacementScale çoğu durumda etkisizdir; harita var ama yanlış UV veya düşük segment varsa sonuç yine «hiç çalışmıyor» gibi görünür — teşhis için önce bu sayfanın demosundaki wireframe ve segment radyolarını kullanın.

const material = new THREE.MeshStandardMaterial({
  displacementMap: heightTexture,
  displacementScale: 0.1, // Genellikle küçük değerler kullanılır
  displacementBias: 0, // Ofset ayarı
});

Aynı yüzeyde normalMap ile displacementMap birlikte kullanılıyorsa tangent uzayı tutarlı olmalıdır; normalMap için geometride tangent özniteliği gerekir. Displacement kendisi teğetleri hesaplamaz ama yanlış üretilmiş teğetler, ikisini birden bağladığınızda çift «kırılma» hissi verir.

Etkileşimli displacement demosu

Aşağıdaki sahne harici model veya doku indirmez: yükseklik haritası tarayıcıda Canvas ile üretilir, THREE.NoColorSpace ile materyale bağlanır. Aynı veriden türetilen normal map ile fiziksel displacement karşılaştırması, gri önizleme, displacementBias ve üçgen / yaklaşık FPS satırı içerir.

«Yalnızca normal» modu, aynı yükseklik alanından türetilen teğet normalleri kullanır; böylece normal map sayfasındaki silüet sınırı dersi burada canlı karşılaştırma haline gelir. Fiziksel modda ise aynı veri vertex ötelemesine dönüşür — tablodaki sabitler diagram-displacement-demo.js ile örtüşür; değerleri değiştirmeden yalnızca metin tarafını genişlettik.

Mini demo · prosedürel height · WebGL · dosya yok

Görsel mod

Height (gri = veri)

Düzlem bölünmesi

0,090
0,000

Checklist: «Yalnızca normal» modunda dönünce silüet hâlâ düz mü? Fiziksel modda aynı dönüşte kenar kırılıyor mu? Bias tüm yüzeyi hafifçe yukarı / aşağı kaydırıyor mu? Üçgen sayısı 8×8 ile 96×96’da nasıl değişiyor? Doku ve geometri sayfada üretilir; ağdan model veya görüntü çekilmez.

Aşağıdaki tablo diagram-displacement-demo.js içinde bu demo için gerçekten kullanılan sabitleri özetler; «öneri» değil, dosyadaki değer kaydıdır. Tür sütunu: radyo, onay kutuları ve sürgüler dışındakiler kodda sabittir.

Bu demo’da kontrol edilenler

  • disp-demo-visual → fiziksel displacement (physical) veya yalnızca normal map (normalOnly)
  • disp-demo-segments → düzlem 8×8 veya 96×96 segment
  • displacement açık/kapalı, wireframe, yavaş dönüş onay kutuları
  • displacementScale ve displacementBias sürgüleri (fiziksel modda ve displacement açıkken)
diagram-displacement-demo.js — Demo Sabitleri (height-displacement-map.html)
Sahne / rol Parametre Değer Tür
Yükseklik verisi Izgara boyutu S 128 · buildHeightField(S) → gri doku + aynı veriden buildNormalMapFromHeight(..., strength) · varsayılan strength = 4.5 🔒 Sabit (kod)
Doku uzayı heightTex / normalTex · NoColorSpace · ClampToEdgeWrapping 🔒 Sabit
Renderer Temiz renk / ton setClearColor(0x080a12) · ACESFilmicToneMapping · exposure 1.05 · SRGBColorSpace çıkış 🔒 Sabit
Piksel oranı Math.min(window.devicePixelRatio || 1, 2) 🔒 Sabit
Işıklar AmbientLight 0xffffff · yoğunluk 0.22 🔒 Sabit
DirectionalLight (ana) 0xffffff · 0.95 · konum (2.2, 4.2, 1.6) 🔒 Sabit
DirectionalLight (dolgu) 0xa8c4ff · 0.28 · konum (-2.5, 1.2, -1.8) 🔒 Sabit
Düzlem + materyal (başlangıç ctor) PlaneGeometry / MeshStandardMaterial Boy 1.85 × 1.85 · başlangıç segment 96 · rotation.x = -Math.PI / 2 🔒 Sabit
PBR + displacement color 0xc5ccd8 · metalness 0.05 · roughness 0.65 · DoubleSide · başlangıç displacementScale 0.09 · displacementBias 0 🔒 Sabit
Normal-only mod normalMap / normalScale Harita height’tan türetilir · normalScale (2.35, 2.35) 🔄 Mod (normalOnly)
Kamera PerspectiveCamera FOV 42 · clip 0.0540 · pozisyon (1.68, 0.5, 2.12) · lookAt(0, 0, 0) 🔒 Sabit
Dönüş pivot.rotation.y Açıkken t × 0.32 (t saniye); kapalıyken 0 🔄 Onay kutusu
Sürgü aralıkları (HTML ile uyumlu) displacementScale / displacementBias 0…0.22 adım 0.005 · varsayılan 0.09 · bias -0.08…0.08 adım 0.002 · varsayılan 0 (kodda sırasıyla clamp(..., 0, 0.22) ve clamp(..., -0.08, 0.08)) 🔄 Dinamik (HUD)
İstatistik FPS penceresi ~500 ms aralıkta yenilenen yaklaşık Hz + üçgen sayısı 🔒 Sabit (kod)
HUD Görsel / segment / kutular disp-demo-visual · disp-demo-segments · data-displacement-demo-enabled|wire|rotate 🔄 Dinamik (HUD)
// diagram-displacement-demo.js — özet (height alanı ve ışık tabloda)

const S = 128;
const heightData = buildHeightField(S);
const heightTex = heightDataToCanvasTexture(heightData, S);
const normalTex = buildNormalMapFromHeight(heightData, S); // strength varsayılan 4.5

const mat = new THREE.MeshStandardMaterial({
  color: 0xc5ccd8,
  metalness: 0.05,
  roughness: 0.65,
  side: THREE.DoubleSide,
  displacementMap: heightTex,
  displacementScale: 0.09,
  displacementBias: 0,
});

const mesh = new THREE.Mesh(new THREE.PlaneGeometry(1.85, 1.85, 96, 96), mat);
mesh.rotation.x = -Math.PI / 2;

const cam = new THREE.PerspectiveCamera(42, 1, 0.05, 40);
cam.position.set(1.68, 0.5, 2.12);
cam.lookAt(0, 0, 0);

Teknik kurallar ve renk uzayı

HoloDepth standartlarını koruyoruz: bu bir veri dokusudur.

  • THREE.NoColorSpace (doğrusal): Displacement map bir mesafe / yükseklik bilgisidir. sRGB uygulanırsa yükseltiler doğrusal olmaz; yüzeyde istenmeyen basamaklanma (banding) ve ölçek hatalarına yol açabilir.

Bu kural roughness ve AO için söylediğimiz «veri = NoColorSpace» disiplininin aynısıdır; fark, burada pikselin yükseklik ölçeği olarak yorumlanmasıdır.

heightTexture.colorSpace = THREE.NoColorSpace;

Performans ve optimizasyon (HoloDepth stratejisi)

Displacement map web tarafında «pahalı» bir tekniktir. Akıcı FPS için şu taktikleri düşünün:

  • Hibrit kullanım: Büyük formlar için düşük şiddetli bir displacement, mikro detaylar için üzerine bir normal map ekleyin. Böylece poligonu aşırı şişirmeden maksimum gerçekçilik elde edilir.
  • Mesafe bazlı kontrol: Yalnızca kameraya çok yakın objelerde displacement açık tutun; uzakta normal map aynı işi fark edilmeden görebilir.

Instancing ile çoğaltılan mesh’lerde her örnek aynı segment yoğunluğunu taşır; toplam üçgen bütçesi hızla büyür. Doku çözünürlüğü ve mipmap seçimi için ayrıca Doku optimizasyonu rehberine bakın — bu sayfa geometri maliyetine odaklanır.

HoloDepth «Displacement» checkpoint’i

Özet

Height / Displacement map, 3D objenize dokunulabilir bir kütle kazandırır. Poligon maliyeti nedeniyle her zaman premium bir seçenektir. Doğru kullanıldığında izleyici «bu model gerçekten oynatılmış» der; yanlış kullanıldığında ise aynı sahne gürültülü tel örgü ve düşük FPS ile hatırlanır.

HoloDepth özet stratejisi

Poligon şartı

Objenin yeterince segments (veya eşdeğer bölünme) değerine sahip olduğundan emin ol; şüphede bu sayfadaki düşük / yüksek segment radyolarını aç.

Doğrusal kural

Veri haritası: NoColorSpace; sRGB kayması basamaklanma yapar.

Scale hassasiyeti

displacementScale değerini milimetrik düzeyde ayarla; küçük sapma büyük deformasyon yapar.

Silüet testi

Yandan bakmıyorsan veya silüet önemsizse, önce normal map yolunu değerlendir.

Sonraki durak: bu alt dizideki doku türleri sona erer; maliyet ve bellek tarafını toparlamak için Doku optimizasyonu sayfasına geçebilir veya genel bağlam için Materyal girişi omurgasına dönebilirsiniz.