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:
| Ö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.
—
Görsel mod
Height (gri = veri)
Düzlem bölünmesi
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üzlem8×8veya96×96segmentdisplacementaçık/kapalı, wireframe, yavaş dönüş onay kutularıdisplacementScalevedisplacementBiassürgüleri (fiziksel modda ve displacement açıkken)
| 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.05–40 · 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.