Three.js · Gölge haritası · seri 2 / 4
PCFShadowMap: komşu örnekleme ile yumuşak kenar
PCFShadowMap (Percentage Closer Filtering), aynı derinlik haritasını
okurken tek noktaya değil, komşu örneklere de bakıp sonucu oransal bir karışıma
çevirir. Three.js tarafında WebGLRenderer.shadowMap.type için sık görülen
varsayılanlardan biridir; yine de projede açıkça atamak sürüm farklarında netlik sağlar. Bu
sayfadaki oynatıcı her zaman THREE.PCFShadowMap ile çalışır.
Önce gölge girişi, BasicShadowMap (sert eşik), ardından gölge haritası mantığı ve türler tablosu ile çerçeveyi tamamlayın; PCF’nin eklediği şeyin «fiziksel penumbra» değil, harita uzayında yumuşatma olduğunu böylece daha kolay ayırırsınız.
Aşağıdaki playground Technical · şehir ve Organic ·
eğriler
arasında geçer: ilki kesişen gölgelerle gri tonları, ikincisi eğri yüzeylerle kenar
okumasını
öne çıkarır. light.shadow.radius ve mapSize birlikte
oynatıldığında
blokluluk ile bulanıklık arasındaki gerilim belirginleşir.
Basic ile aynı
sahneyi açıp kıyaslamak yerine her türe özel düzen kullanıldığından, iki sekmeyi yan yana
tutarak «ikili test → yüzdesel karışım» farkını izlemeniz yeterlidir.
Teknik yapı: komşuya sor, ortalamayı al
Basic ile fark nerede başlar?
BasicShadowMap hedef noktada tek derinlik karşılaştırmasıyla «gölgede mi, değil mi?» ikilisine yakın sonuç üretirken; PCF aynı haritayı okurken çevreden birden fazla örnek alıp bunları birleştirir.
- Örnekleme (sampling): Yalnızca tek texel değil, komşu bölgeler de derinlik testine dahil edilir.
- Oransal sonuç: Örneğin komşu dört örnekten ikisi gölgede, ikisi aydınlıkta ise nokta tam siyah yerine ara gri tonlara yaklaşabilir.
- Yumuşak kenar hissi: Bu yüzdesel yakınlık yaklaşımı, sert basamakları gradyana benzer bir geçişle yumuşatır.
Maliyet sezgisı: Basic’e göre ne eklenir?
PCF, aynı haritayı birden fazla kez örnekleyerek karar verir; bu, GPU’da ek
dokunuş demektir — genelde hâlâ makul bir aralıktadır, fakat mobilde çok sayıda
gölge veren ışık ve düşük mapSize bir aradayken fark hissedilir. Pratik kural:
önce harita çözünürlüğünü ve frustum’u doğrula, sonra radius ile kenarı
yumuşat;
performans rehberi ile birlikte ölç.
Neden hâlâ “mükemmel” değil?
Harita kaba kaldığında
PCF kenarı yumuşatır; fakat gölge blokluluğu (düşük çözünürlükte karemsi
yapı) tamamen kaybolmayabilir. shadow.mapSize çok düşükse, filtre yumuşatsa
bile
harita «kaba ızgara» hissi vermeye devam eder.
Gerçek dünyadaki penumbra (gölgenin mesafeye göre genişlemesi) ile karıştırmayın: PCF’deki yumuşaklık çoğu zaman ekran / harita uzayındaki bir yumuşatmadır; mesafe veya geometriye göre fiziksel olarak doğru dağılması gerekmez.
radius haritayı inceltmez
Yüksek shadow.radius kenarı bulanıklaştırır ama haritadaki texel
sayısını artırmaz: bloklu bir 256 haritada radius’u şişirmek, “daha keskin
silüet” yerine daha bulanık merdiven verir. İnce kenar istiyorsan önce
mapSize ve gölge kutusu, sonra radius sırası daha az hayal kırıklığı yaratır.
Avantajlar: neden varsayılan tercih?
Pratikte ne kazanırsınız?
- Daha okunaklı kenarlar: Basic’deki rahatsız edici aliasing büyük ölçüde azalır.
- Geniş donanım uyumu: Çoğu mobil ve masaüstü GPU ile sorunsuz çalışır.
- Dengeli maliyet: Gözle görülür kalite kazanımı sunarken PCFSoft / VSM gibi seçenekler kadar agresif olmayabilir (sürüm ve sahneye bağlıdır).
Üretimde “varsayılan PCF” ne zaman yeter?
Çoğu iç mekân ve ürün vitrininde, tek ana ışık + makul mapSize ile PCF, acne
ayarı yapıldığında uzun süre yeterli kalır. Daha geniş yarı gölge veya hareket halinde bile
stabil kenar istiyorsan sırada
PCFSoftShadowMap veya
VSM denemeleri
vardır — maliyet ve artefakt profili farklıdır.
Kritik parametre: light.shadow.radius
Radius neyi genişletir, neyi genişletmez?
mapSize dışında PCF tarafında en çok işinize yarayan ayarlardan biridir:
radius — komşu örneklerin ne kadar geniş bir alandan
toplanacağını etkiler. Değeri artırdıkça kenar daha bulanık görünür; bu, gerçek bir yarı
gölge değil, matematiksel yumuşatmadır — sınır çizgileri kabaca aynı ölçüde
yumuşar; nesne–ışık mesafesine göre doğal penumbra beklemeyin.
Tuning: radius ile bias birlikte
Radius arttıkça yüzey acne’si bazen maske gibi görünür; bu durumda yalnız
radius’u kesmek yerine bias / normalBias ile birlikte küçük
adımlar
ver. Kötü kombinasyonları bu sayfadaki Kötü ayar örneği kutusuyla güvenli
biçimde gözlemleyebilirsin;
Bias & shadow acne
rehberi teşhis dili için kullan.
// Bu sayfadaki demo açıkça PCF seçer (yazmazsanız sürümünüzün varsayılanına bağlı kalırsınız)
renderer.shadowMap.type = THREE.PCFShadowMap;
// Yumuşaklık (örnek; sahneye göre ayarlayın — varsayılan genelde küçük değerdedir)
directionalLight.shadow.radius = 4;
Oynatıcı: iki sahne, aynı PCF çekirdeği
Hangi ipuçlarına odaklanmalısınız?
Technical · şehir kule yüksekliği ve ayak izini oynatarak kesişen
gölgelerde
gri ton birikimini gösterir; başlangıç ışığı daha yatay bir gökten uzun gölge okur.
Organic · eğriler TorusKnot ve heliks ile kenar okumasını farklı bir
yüzeyde dener. shadow.radius tüm sınırlara benzer bulanıklık ekler; haritayı
256 veya 512’ye indirip blokluluk ile PCF yumuşamasını üst üste izleyin. Spot ve ışık
mesafesi, gerçek penumbra beklentisi ile ekran uzayı filtresini ayırt etmeye yarar.
Kenarları vurgula Technical’de cadde kenarına, Organic’de knot yakınına
yaklaşır.
Amaç: «yumuşar ama fiziksel dağılmayı taklit etmek zorunda değildir» sınırını elle
hissetmek.
Harita: 256 = blok + blur birlikte · 1024 = denge · 2048 = daha temiz kenar.
Sürükle: dönüş ve zoom (pan kapalı). Technical · şehir: kule örtüşmeleri gri geçiş üretir; zemin tonu gölgeleri ayırt etmek için biraz açıktır. Organic: knot ve heliks ayrık; zemin daha açık, formlar hafif parlak. Radius kenarı eşit bulanıklaştırır (fiziksel penumbra değildir). Işık yüksekliği / dönüşü yan ışık denemesi için. Kenarları vurgula Technical’de cadde, Organic’de düğüm yakını. Spot kapsamı (zemin) yalnız Spot’ta. Yönsel modda mesafe sürgüsü kapalıdır.
Kod yolu: diagram-shadow-map.js içinde data-shadow-variant="pcf"
dalı; sahne radyosu Technical · şehir (PCF_EDGE_LAB) veya
Organic · eğriler (PCF_ORGANIC) arasında seçilir. Aşağıdaki
tablo bu varyantın sayısal haritasıdır — Tür sütunu HUD ile değişenleri
dosyada kilitli kalanlardan ayırır; PCF sayfasına özgü ek sürgü shadow.radius
satırlarında görünür.
Sabit doğrulama: tablodaki PCF_EDGE_LAB ve
PCF_ORGANIC blokları, pcf varyantında buildPcfEdgeLabInto /
buildPcfOrganicInto ile birebir; renderer
(PCFShadowMap, exposure 1.02, arka plan 0x030305),
dolgu
ışıkları ve kamera başlangıcı da aynı dosyadaki pcf dalından gelir. HUD satırları
«Dinamik» ile işaretlenir; Technical / Organic seçimi radyo ile sahneyi yeniden kurar.
HUD’dan hangi parametreler akıyor?
mapSize— çözünürlük; düşük değerde blokluluk ile PCF yumuşaması üst üste binirshadow.radius— komşu örnekleme yarıçapı; kenar bulanıklığı (fiziksel penumbra değil). Artınca yayılım mesafesi değil, filtre genişliği hissi büyürbias/normalBias— shadow acne ve yüzey kaydırması- Azimut ve yükseklik — ışın yönü;
setLightPoseile güncellenir - Mesafe — yalnızca
SpotLightiçin anlamlıdır;DirectionalLightparalel ışın kullandığından yönsel modda sürgü gizlenir
| Sahne / rol | Parametre | Değer | Tür |
|---|---|---|---|
| Ortak · hedef | LIGHT_TARGET (yönsel hedef) |
(0, 0.58, 0) |
🔒 Sabit |
SpotLight.target (spot dalı) |
(0, 0.52, 0) — setLightPose |
🔒 Sabit | |
PCF_EDGE_LAB · Technical · şehir |
Zemin | groundSize 20 · 0x1a2330, roughness
0.9, metalness 0.035
|
🔒 Sabit |
| Kule ızgarası | InstancedMesh birim BoxGeometry(1,1,1) · kule mat.
0xd8e6f4 · hücre 0.44 · yaklaşık 11×11
(merkez şerit / aralık atlamalı) · yükseklik 0.3–1.26
arası pseudo-rastgele
|
🔒 Sabit | |
| Plaza | BoxGeometry(2.35, 0.038, 2.35) · konum (0.04, 0.019,
−0.08) · 0x8f9eb2 |
🔒 Sabit | |
focusRing |
Merkez (−0.92, 0.48), yarıçap 0.62 |
🔒 Sabit | |
focusOrbit |
Kamera (1.88, 1.02, 2.28) → hedef (−0.58, 0.035,
0.38), FOV 28, min/max 0.64 /
5.95
|
🔒 Sabit | |
PCF_ORGANIC · Organic · eğriler |
Zemin | groundSize 20 · 0x242e3e, roughness
0.93, metalness 0.025
|
🔒 Sabit |
TorusKnotGeometry + heliks TubeGeometry |
Knot: TorusKnotGeometry(0.38, 0.032, 118, 14, 2, 3), konum
(−0.58, 0.5, −0.72) · tüp: 136 kesit, boru yarıçapı
0.024, 8 radial; heliks eğrisi 100 örnek,
4.4 tur
|
🔒 Sabit | |
focusRing |
Merkez (−0.35, −0.55), yarıçap 0.72 |
🔒 Sabit | |
focusOrbit |
Kamera (2.65, 1.32, 2.88) → hedef (−0.15, 0.045,
−0.35), FOV 27, min/max 0.72 /
6.2
|
🔒 Sabit | |
| Ana ışık (pcf yükleme) | color + yoğunluk |
0xffffff · yönsel 1.92 · Spot 108 |
🔒 Sabit (varyant) |
DirectionalLight gölge kamerası (ortho) |
±5.2 · near 0.8 · far
26
|
🔒 Sabit | |
SpotLight (makeSpot + pcf) |
Ctor + pcf renk / yoğunluk | distance 30 · angle
Math.PI / 5.2 · penumbra 0.22 ·
decay 1.2 · pcf’de color
0xffffff, intensity 108
|
🔒 Sabit |
| Spot gölge kamera | near 0.25 · far 38 ·
shadow.focus 1
|
🔒 Sabit | |
| Gölge tabanı + HUD | mapSize / bias / normalBias |
Başlangıç 1024 · −0.0001 · 0.02 · “Kötü
ayar”da BAD (512, 0, 0)
|
🔄 Dinamik (HUD) |
shadow.radius |
PCF dalında HUD sürgüsü 0–10 (adım 0.25);
başlangıç 2 · applyShadowParams ile
clamp(0, 12)
|
🔄 Dinamik (HUD) | |
| Sahne modeli | data-shadow-pcf-model · varsayılan rods (Technical)
|
🔄 Dinamik (HUD) | |
| Dolgu (pcf sahne) | AmbientLight |
0xffffff, yoğunluk 0.028 |
🔒 Sabit |
HemisphereLight |
0x8899aa / 0x06080c, yoğunluk 0.1 |
🔒 Sabit | |
| Renderer / kamera (pcf) | Ton / gölge / arka plan | ACESFilmicToneMapping, exposure 1.02 ·
PCFShadowMap · 0x030305
|
🔒 Sabit |
PerspectiveCamera + OrbitControls |
Başlangıç poz (5.35, 3.95, 6.55), bakış / hedef
(0.08, 0.2, −0.18); zoom 3.8–13.5; pan
kapalı
|
🔒 Sabit | |
| Yardımcı çizimler | Tel / grid / eksen | Yönsel: sarı Line; Spot: koni LineSegments. Grid
açıkken GridHelper(20, 40, 0x2a3848, 0x121820) |
🔒 Sabit + HUD (görünürlük) |
HUD başlangıç (pcf-shadow-map.html) |
Sürgü / seçim | Harita 1024; radius 2; bias −10 →
−0.0001; normal bias 20 → 0.02; azimut
104°, yükseklik 26°, mesafe 20
|
🔄 Dinamik (HUD) |
| Yönsel başlangıç konumu | setLightPose |
Yaklaşık (17.44, 9.35, −4.35) = LIGHT_TARGET + offset
(104°, 26°, 20) |
🔄 Dinamik (HUD) |
// diagram-shadow-map.js — PCF varyant okuma sırası (Technical / Organic geometri tabloda)
// 🔑 PCFShadowMap’te gölge okuması: shadowMap.type + light.shadow.mapSize + light.shadow.radius (+ bias / normalBias)
// 1. Renderer
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFShadowMap;
// 2. Işık kurulumu (pcf: beyaz + yoğunluk yükseltilir)
const LIGHT_TARGET = new THREE.Vector3(0, 0.58, 0);
const light = new THREE.DirectionalLight(0xffffff, 1.92);
light.castShadow = true;
light.target.position.copy(LIGHT_TARGET);
scene.add(light);
scene.add(light.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;
light.shadow.radius = 2; // PCF: komşu örnekleme — sahneye göre 0–12 aralığında ayarla
İleri seviye not
Yüzdesel filtre neyi sorar?
PCF, kabaca konuşmak için GPU’ya şu soruyu çoğaltır: «Bu noktanın çevresinde, derinlik testine göre ışık almayan örneklerin oranı nedir?» İsimdeki percentage (yüzdesel) buradan gelir: sonuç saf ikili değil, istatistiksel bir karışımdır. Bu sayfa ve tablo, bu fikrin sahne sabitleriyle somutlaşmış halini verir.
Aynı fikir, genel tür tablosundaki PCF satırı ile de köprülenebilir — bu sayfa o satırın çift sahne laboratuvarıdır.
Sırada ne var?
Bir sonraki basamakta PCFSoftShadowMap ve VSMShadowMap farklı çekirdek ve maliyet profilleri sunar. Hepsini tek bakışta Shadow map türleri tablosunda kıyaslayabilirsiniz.