Three.js · Gölge · Harita tabanlı
Shadow Map (Gölge Haritası) nedir?
Işığın gözünden derinlik — sonra kamera pikseli başına “arada engel var mı?”
Üç boyutlu bir sahnede gölge, yalnızca ışığın çarptığı yerin kararması kadar basit bir süreç değildir. Bilgisayar grafiklerinde gölge üretmenin en yaygın ve performanslı yollarından biri Shadow Mapping tekniğidir: sahne, ışığın bakış açısından bir kez “derinlik olarak” çizilir; ana kamera çizerken her nokta, bu haritayla karşılaştırılarak gölgede mi değil mi belirlenir.
Bağlam: Gölge girişi (fizik–harita köprüsü), DirectionalLight, SpotLight, PointLight, RectAreaLight (çekirdekte shadow map üretimi yok).
Temel mantık: ışığın bakış açısı
Shadow map’i anlamanın en kısa yolu şudur: Işığa bir göz takın ve sahneye onun gözünden bakın. Işık kaynağı kendi pozisyonundan (ve yönünden) sahneye baktığında hangi yüzeyleri “önde” görüyorsa, o bölgeler ışık altındadır. Işığın görüş hattında başka bir yüzeyin arkasında kalan noktalar ise gölge adayıdır: ışın o noktaya ulaşmadan önce engellenmiştir.
Harita uzayı: piksel = “ışık penceresi”
Shadow map, ışığın projeksiyonunda bir doku ızgarasıdır: her texel, dünya
uzayında belirli bir ayak izi (footprint) temsil
eder. Bu yüzden aynı geometri, harita çözünürlüğü düştükçe gölge kenarında merdiven
(aliasing) oluşturur; çözünürlük arttıkça bellek ve doldurma
maliyeti büyür — beşinci bölümde mapSize bu dengeyi doğrudan tutar.
Teknik süreç: iki aşamalı render
Shadow mapping, GPU üzerinde tipik olarak iki ana aşamada işler:
- Derinlik geçişi (depth pass): Sahne, ana kameranın değil, ışığın bakış açısından render edilir. Bu aşamada renklere odaklanılmaz; her hedef piksel için ışığa göre derinlik (z) değeri hesaplanır ve bir dokuya yazılır. Bu derinlik dokusuna shadow map (gölge haritası) denir.
- Gölge testi (shadow test): Ana sahne, kamera gözünden çizilirken her piksel için “bu nokta ışığa göre ne kadar uzakta?” sorusunun cevabı, shadow map’teki derinlikle kıyaslanır. Pikselin ışığa olan mesafesi, haritadaki engel mesafesinden büyükse, ışık ile nokta arasında daha yakında bir yüzey vardır ve piksel gölgelendirilir.
Derinlik geçişinde ne çizilir?
Tipik kurulumda derinlik geçişi gölge atan (castShadow) opak
geometri üzerinden gider; şeffaf yüzeyler, çift taraflı ince geometri veya özel materyal
yolları bu hikâyeyi karmaşıklaştırabilir. Ana fikir yine aynıdır: harita “ışığın gördüğü en
yakın yüzey”i kaydeder; ana geçişte piksel bu yüzeyin gerisinde mi diye sorulur.
Işık türüne göre gölge üretimi
Three.js’te gölge, ışığın geometrisine göre farklı projeksiyon ve derinlik alanı ile üretilir:
- DirectionalLight: Paralel ışınlar — güneş gibi uzak ve geniş alanlar için uygun ortografik gölge kamerası.
- SpotLight: Perspektif koni içinde tek bir derinlik haritası — el feneri veya sahne spot’u.
- PointLight: Her yöne yayılan ışık için çoğu zaman 6 yönlü derinlik (küp yüzleri / cube shadow) gerekir; maliyet genelde en yüksek seçeneklerdendir.
castShadow ve
receiveShadow
Three.js’te gölge iki rolle ayrılır: mesh castShadow ile haritaya
engel olur; receiveShadow ile zeminde veya başka yüzeyde
haritayı okuyarak kararma alır. Işıkta castShadow = true
olmadan harita üretilmez; alıcıda receiveShadow kapalıysa yüzey üzerinde
harita testi yapılmaz — “ışık gölge üretiyor ama zeminde yok” çoğu zaman bu ikiliden
biridir.
Shadow frustum (gölge görüş alanı)
Işığın gölge üretebildiği alan sınırsız değildir. Her ışığın bir shadow camera frustum’ı (görüş hacmi) vardır: kutunun veya koninin dışında kalan geometri, ekranda görünse bile bu ışık için gölge haritasına düşmeyebilir. Frustum’u sahneye sıkı sarmalamak hem çözünürlük verimini artırır hem de gereksiz boş alanı haritada israf etmezsin.
Sızma ve “kutu dışı” gölge
Frustum’u gereğinden geniş tutmak, haritada devasa boş alan demektir: aynı
mapSize ile dünya birimine düşen texel sayısı azalır ve gölge kenarları
kabaşır. Tersine, kutuyu fazla dar tutmak ise sahnede görünen ama haritaya hiç düşmeyen
geometriye yol açar — gölge ani kesilir veya tamamen kaybolur. Üretimde
kutu, oyun alanını saracak kadar sıkı; clip düzlemleri ise z-fighting ve kesme arasında
dengeye getirilir.
Çözünürlük ve kalite: mapSize
Shadow map bir dokudur; light.shadow.mapSize (ör. 512, 1024, 2048) haritanın
piksel boyutunu belirler.
- Düşük çözünürlük: Gölgeler bloklu ve tırtıklı görünür (aliasing).
- Yüksek çözünürlük: Kenarlar daha keskin olur; GPU belleği ve doldurma maliyeti artar.
Bir texel kaç “metre”?
Harita çözünürlüğü tek başına anlamlı değildir; anlamlı olan gölge kamerası
genişliği / harita pikseli oranıdır. Geniş alanı 1024 texele yaymak ince
detayı öldürür; dar alanı 2048’e sıkıştırmak ise bellek ve band genişliğini harcar. Bu
yüzden önce frustum’u (dördüncü bölüm), sonra mapSize’ı ayarlamak daha tutarlı
bir sıradır.
Yaygın problemler: shadow artifacts
Shadow acne & Peter Panning
Shadow acne: Derinlik karşılaştırmasındaki hassasiyet yüzünden yüzeyin kendi üzerine “titreyen” veya noktalı gölge düşürmesi.
Peter Panning: Gölgenin yüzeyden kopuk görünmesi — nesnenin zeminde süzülüyormuş hissi.
Pratik çözüm: Three.js’te shadow.bias,
shadow.normalBias ve gerektiğinde near/far ile frustum ayarı bu hataları
yumuşatır; değerler sahneye göre ince ayar ister.
light.castShadow = true;
light.shadow.mapSize.set(1024, 1024);
light.shadow.bias = -0.0001;
light.shadow.normalBias = 0.02;
Sonraki okuma: bias ve filtre
Acne ve peter panning için sayısal örnekler ve teşhis akışı
Bias & shadow acne
sayfasında toplanır; filtre türü (shadowMap.type) ile birlikte düşünmek gerekir
— özet tablo bu sayfanın
8. bölümünde.
İnteraktif: Shadow Playground
Dış model yok: geniş zemin, büyük küre (temas gölgesi),
ince panel (zeminde keskin gölge kenarı) ve havada küçük
küp
(bias / acne için silüet).
Tek ana ışık; OrbitControls yalnızca döndür + sınırlı zoom,
pan kapalı. Aşağıdan mapSize, bias, ışık yönü ve
kötü ayarlar ile acne / pikselleşmeyi güvenli biçimde gözlemle.
Örnek sahne renderer.shadowMap.type için PCFSoft kullanır;
diğer algoritmalar aşağıdaki 8.
bölümdeki tabloda özetlenir.
Harita: düşük = hızlı / gölge kaba · yüksek = net / GPU daha çok.
Sürükle: sadece dönüş + zoom (pan yok). Yönsel ışık seçiliyken Işık mesafesi sürgüsü devre dışıdır (paralel yön değişmez; anlamlı etki Spot modunda). Kötü ayar örneği açıkken harita 512², bias ve normal bias sıfıra zorlanır; harita ve bias sürgüleri kilitlenir — acne / z-fighting daha görünür olur. Kenarları vurgula ince panelin zemindeki gölge kenarına yaklaşır. Kapatınca kayıtlı harita ve bias değerlerin geri yüklenir. Spot kapsamı (zemin) açıkken zeminde mavi tonlu daireler Spot külahının izdüşümünü ve (yaklaşık) mesafe sönümünü gösterir; Yönsel modda bu kutu otomatik kapanır.
Üstteki Shadow Playground (diagram-shadow-map.js, bu sayfada varsayılan
GOLD_DEMO sahnesi) ile aynı sabitleri ön harita tabloda
topladık; aşağıdaki kod demodaki GOLD_DEMO geometri özetini ve
DirectionalLight / SpotLight kurulumunu hatırlatır. Sürgülerle
değişenler (azimut, yükseklik, mesafe, harita, bias) tabloda “HUD” satırında; kalan satırlar
dosyadaki sabitlerdir. Tür sütunu: HUD ile oynananlar ile dosyadan gelen
sabitleri bir bakışta ayırır.
Sabit doğrulama: tablodaki GOLD_DEMO, ışık ctor’ları ve HUD
başlangıçları, canlı sahne ile aynı kaynak dosyadan gelir
(diagram-shadow-map.js). Harita ve bias sürgüleri oynanırken satırlar
“Dinamik (HUD)” etiketiyle ayrılır; geometri ve hedef vektörleri kilitlidir.
Bu demo’da kontrol edilenler
mapSize→ gölge haritası çözünürlüğü (kalite / GPU maliyeti)bias→ shadow acne / z-fighting (ince ayar)normalBias→ yüzey yönüne göre gölge kayması (silüet / yüzey hataları)- Azimut / yükseklik → ışığın geliş yönü (
setLightPose) - Mesafe → yalnızca Spot modunda anlamlı (yönselde sürgü devre dışı; paralel ışıkta mesafe yönü değiştirmez)
| Sahne / rol | Parametre | Değer | Tür |
|---|---|---|---|
| Ortak · hedef | LIGHT_TARGET (yönsel ışık hedefi) |
(0, 0.58, 0) |
🔒 Sabit |
SpotLight.target (spot dalı) |
(0, 0.52, 0) — setLightPose içinde sabit |
🔒 Sabit | |
GOLD_DEMO · geometri |
Zemin PlaneGeometry |
planeSize 16 · materyal 0x2a3348,
roughness 0.72, metalness 0.12 |
🔒 Sabit |
| Küre | sphereR 0.5 · konum (−0.42, 0.5, 0.38)
|
🔒 Sabit | |
İnce panel (BoxGeometry) |
tx, ty, tz → 0.048 × 1.12 × 0.72 · konum
(0.48, 0.56, −0.58) · rotation.y −0.34
|
🔒 Sabit | |
| Havada küp | cubeS 0.17 · konum (0.2, 0.69, 0.52) ·
rotation.y 0.22
|
🔒 Sabit | |
GOLD_DEMO · odak |
focusRing (Kenarları vurgula, zemin) |
Merkez yaklaşık (0.02, −0.05), yarıçap 0.42 |
🔒 Sabit |
focusOrbit |
Kamera (0.45, 0.88, 1.52) → hedef (0.02, 0.028,
−0.06), FOV 31, min/max mesafe 0.76 /
4.35
|
🔒 Sabit | |
DirectionalLight (ctor) |
color / intensity |
0xfff4ec · 1.42 |
🔒 Sabit |
| Gölge kamera (ortho) | left/right/top/bottom ±5.2 · near
0.8 · far 26
|
🔒 Sabit | |
SpotLight (ctor) |
color / intensity / distance |
0xfff4ec · 88 · 30 |
🔒 Sabit |
angle / penumbra / decay |
Math.PI / 5.2 · 0.22 · 1.2 |
🔒 Sabit | |
| Spot gölge kamera | near 0.25 · far 38 ·
shadow.focus 1
|
🔒 Sabit | |
GOOD_DEFAULT (gölge tabanı) |
mapSize / bias / normalBias |
1024 · −0.0001 · 0.02 (ctor + HUD
başlangıcı ile uyumlu) |
🔄 Dinamik (HUD) |
shadow.radius (shadow-map sayfası) |
Işık oluşturulurken ctor’da 2.8; bu sayfada
applyShadowParams ile 1 (PCF dışı
varyant)
|
🔒 Sabit (kod) | |
| Dolgu ışıklar | AmbientLight |
0xd8e8ff, yoğunluk 0.06 |
🔒 Sabit |
HemisphereLight |
Gökyüzü 0x7a9cbd · zemin 0x1a1418 · yoğunluk
0.22
|
🔒 Sabit | |
| Renderer / kamera | Ton / gölge | ACESFilmicToneMapping, exposure ≈1.08 ·
PCFSoftShadowMap · arka plan 0x070a12
|
🔒 Sabit |
PerspectiveCamera + OrbitControls |
FOV 48, clip 0.08–80; başlangıç poz
(4.6, 3.35, 5.9), hedef (0, 0.52, 0); zoom
3.8–13.5; pan kapalı
|
🔒 Sabit | |
| Yardımcı çizimler | Tel / çizgi | Yönsel: sarı Line kaynak→hedef; Spot: koni
LineSegments (DirectionalLightHelper /
SpotLightHelper yok)
|
🔒 Sabit + HUD (görünürlük) |
HUD başlangıç (shadow-map.html) |
Sürgü / seçim | Harita 1024; bias adım −10 → −0.0001;
normal bias adım 20 → 0.02; azimut 118°,
yükseklik 38°, mesafe 14.5 (yönselde mesafe sürgüsü
kapalı) |
🔄 Dinamik (HUD) |
| Yönsel başlangıç konumu | setLightPose (° + mesafe) |
Yaklaşık (10.08, 9.51, −5.36) = LIGHT_TARGET +
küresel offset (118°, 38°, 14.5) |
🔄 Dinamik (HUD) |
// diagram-shadow-map.js — okuma sırası (GOLD_DEMO geometri tabloda)
// 1. Renderer
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// 2. Işık kurulumu (yönsel örnek; Spot ctor farklı — tabloya bak)
const LIGHT_TARGET = new THREE.Vector3(0, 0.58, 0);
const light = new THREE.DirectionalLight(0xfff4ec, 1.42);
light.castShadow = true;
light.target.position.copy(LIGHT_TARGET);
scene.add(light);
scene.add(light.target);
// Spot dalı (özet): new THREE.SpotLight(0xfff4ec, 88, 30, Math.PI / 5.2, 0.22, 1.2)
// spot.target.position.set(0, 0.52, 0); scene.add(spot); scene.add(spot.target);
// 3. Gölge ayarı (önemli kısım)
light.shadow.mapSize.set(1024, 1024);
light.shadow.bias = -0.0001;
light.shadow.normalBias = 0.02;
// Bu sayfada Directional: applyShadowParams sonrası shadow.radius ≈ 1 (PCF dışı varyant).
Shadow map türleri (algoritmalar)
renderer.shadowMap.type seçimi, aynı haritada kenar yumuşatma ve
artefakt dengesini değiştirir; sahne ölçeği ve hareket hızına göre farklı
türler “kabul edilebilir” olur. Aşağıdaki tablo hızlı seçim içindir; her satırın ayrı
sayfası ve demoları gölge alt klasöründe derinleşir.
| Teknik | Açıklama |
|---|---|
BasicShadowMap |
En hızlısı; kenarlar keskin ve pikselli. |
PCFShadowMap |
Çevre örneklemesiyle yumuşak kenar; çoğu projede güvenilir klasik seçenek. PCF sayfası ve demo. |
PCFSoftShadowMap |
Daha geniş filtre hissi; düşük mapSize’ta bile genelde daha
okunaklı. |
VSMShadowMap |
Variance Shadow Map — çok yumuşak gölgeler; sahneye ve ayarlara duyarlı, artefakt riski farklıdır. |
Önemli not ve Holodepth ipucu
Shadow map bir “hile”dir
Bu yöntem gerçek dünyadaki gibi fotonların sekerek dolanmasını (global illumination) simüle etmez; yalnızca “ışığa en yakın yüzey hangisi?” sorusunu tek ışın hattında derinlik kıyasıyla yaklaşıklar.
Holodepth pro ipucu
Sahnede on ışık varsa ve hepsinde castShadow açmak performansı hızla
düşürür. Üretimde çoğu zaman yalnızca ana ışığın (güneş benzeri
DirectionalLight veya ana SpotLight) gölgesini açmak,
kare süresini korumanın en sağlam yollarından biridir.
Çoklu harita, dinamik çözünürlük ve bütçe tablosu için Gölge performansı optimizasyonu sayfasına geç; nokta ışığında geçiş sayısı planı için PointLight gölge maliyeti notuna bak.