Gökyüzü, gün batımı ve gezegen render etme
(blog.maximeheckel.com)- Tarayıcı shader’ı, mavi gökyüzünü ve gün batımı/gün doğumunu gerçek zamanlı render etmek için Rayleigh saçılması, Mie saçılması ve ozon soğurmasını birleştirir
- Kamera ışınının optik derinliği ile Beer's Law geçirgenliği biriktirilir ve saçılım dağılımı, güneş yönüne göre faz fonksiyonu ile hesaplanır
- Gün batımı efekti, her örnekte güneş yönünde ayrı bir light-march çalıştırarak güneş ışığının atmosferden geçerken ne kadar kaybettiğini yansıtır
- Düzlemsel gökyüzü shader’ı, depth buffer ve dünya koordinatı yeniden oluşturma ile bir post-processing efekti haline gelir; böylece sahne nesneleri arasındaki atmosferik sis de işlenir
- Gezegen ölçeğinde bu yapı, logarithmic depth buffer, ray-sphere intersection ve LUT tabanlı Transmittance, Sky-view, Aerial Perspective ile genişletilir
Atmosferik saçılım shader’ının hedefi ve başvuru kaynakları
- Amaç, uzay mekiği Endeavour’un alçak yörüngeden çekilmiş gün batımı fotoğraflarındaki gibi Dünya’nın üst atmosferinde koyu turuncu, mavi ve uzay arka planının siyahına uzanan katmanları tarayıcı shader’ı ile yeniden üretmektir
- Uygulama kapsamı, raymarching, Rayleigh saçılması, Mie saçılması ve ozon soğurmasını birleştiren gerçekçi bir sky dome ile başlar; ardından gezegen çevresindeki atmosfer kabuğu ve LUT tabanlı optimizasyonlarla genişler
- Başlıca kaynaklar Three Geospatial, Sébastien Hillaire’in A Scalable and Production Ready Sky and Atmosphere Rendering Technique makalesi ve Atmospheric Scattering (and also just faking it) sunumudur
Gökyüzü render etmenin temel modeli
-
Basit gradyanın neden yetersiz olduğu
- Gökyüzü rengi, yalnızca mavi bir arka plan olarak değil, ışığın hava ve onun bileşenleriyle etkileşiminin sonucu olarak ele alınmalıdır
- Gözlemcinin irtifası, toz miktarı ve günün saati gibi değişkenler dikkate alınmalıdır; hesaplamalar hacim (volume) içinde yapılır
-
Atmosfer yoğunluğunu örnekleme
- Atmosfer, volumetric clouds veya volumetric light örneklerinde olduğu gibi raymarching ile örneklenir
- Kamera konumundan bir ışın gönderilir ve saydam ortam boyunca ilerletilir; bu sırada atmosferden geçip hayatta kalan ışık olan geçirgenlik (transmittance) ile her örnekte kamera yönüne yeniden yönlendirilen saçılım (scattering) hesaplanır
- Raymarching’e tekrar bakmak için Painting with Math: A Gentle Study of Raymarching kaynağına başvurulabilir
-
Rayleigh yoğunluğu ve optik derinlik
- Geçirgenliği hesaplamak için, ışının yol boyunca karşılaştığı atmosfer yoğunluğu biriktirilerek optik derinlik (optical depth) hesaplanmalıdır
- Rayleigh yoğunluk fonksiyonu,
hyüksekliğinde ne kadar “hava” bulunduğunu gösterir ve irtifa arttıkça atmosferin seyrekleşmesi etkisini yansıtır - Örnek uygulama
RAYLEIGH_SCALE_HEIGHT = 8.0km,ATMOSPHERE_HEIGHT = 100.0km,VIEW_DISTANCE = 200.0km,PRIMARY_STEPS = 24kullanır rayleighDensity(h),exp(-max(h, 0.0) / RAYLEIGH_SCALE_HEIGHT)şeklindedir ve döngü içindeviewOpticalDepth += dR * stepSizeile biriktirilir
-
Beer's Law ve gündüz göğünün maviliği
- Optik derinlikten belirli bir noktadaki geçirgenlik
Thesaplanır;T=1.0ışık kaybı olmadığı,T=0.0ise ışığın tamamen yok olduğu anlamına gelir - Geçirgenlik Beer's Law ile hesaplanır; örnek kod
vec3 transmittance = exp(-rayleighBeta * viewOpticalDepth)kullanır rayleighBeta, Rayleigh saçılım katsayısıdır ve shader’davec3(0.0058, 0.0135, 0.0331)olarak tutulur- Güneş ışığı yönü ile bakış ışını arasındaki açı,
3.0 / (16.0 * PI) * (1.0 + mu * mu)biçimindeki Rayleigh phase function ile modellenir - Rayleigh saçılım katsayıları nedeniyle kırmızı neredeyse hiç saçılmaz, yeşil biraz daha fazla saçılır ve mavi en çok saçıldığı için gündüz gökyüzü mavi görünür
- Bu yaklaşım her piksel için tek bir ışına genişletildiğinde, ufka doğru daha fazla atmosferden geçildiği için parlak beyaz bir pus gibi görünür; irtifa arttıkça ise daha derin ve daha koyu bir maviye dönüşür
- Optik derinlikten belirli bir noktadaki geçirgenlik
Mie saçılması ve ozon soğurması
-
Yalnızca Rayleigh’in yetmediği etkiler
- Yalnızca Rayleigh saçılmasıyla da makul sonuçlar alınabilir, ancak daha gerçekçi bir gökyüzü için ek atmosfer etkileri gerekir
- Mie saçılması, toz veya aerosol gibi daha büyük parçacıklarla ışığın etkileşimini ifade eder; bir yoğunluk fonksiyonuna ve yönlere göre yeniden dağılımı gösteren bir faz fonksiyonuna sahiptir
- Ozon soğurması, üst atmosferden geçen ışığın bazı dalga boylarını saçmadan yolundan çıkarır
- Ozon soğurması özellikle ufukta, gün batımında, gün doğumunda ve alacakaranlıkta gökyüzü rengini daha derin hale getirir ve renkleri kaydırır
-
Mie ve ozonun biriktirilmesi
- Rayleigh, Mie ve ozonu birlikte kullanan uygulama, ilgili optik derinlikleri
viewODR,viewODM,viewODOile ayrı ayrı biriktirir - Her örnekte
dR = rayleighDensity(h),dM = mieDensity(h),dO = ozoneDensity(h)hesaplanır vetau,BETA_R * viewODR,BETA_M_EXT * viewODM,BETA_OZONE_ABS * viewODOtoplamından oluşturulur - Geçirgenlik
exp(-tau)ile hesaplanır; her yoğunluk, geçirgenlik vestepSizedeğerisumR,sumM,sumOiçine biriktirilir - Nihai saçılım
SUN_INTENSITY * (phaseR * BETA_R * sumR + phaseM * BETA_M_SCATTER * sumM + BETA_OZONE_SCATTER * sumO)biçiminde hesaplanır
- Rayleigh, Mie ve ozonu birlikte kullanan uygulama, ilgili optik derinlikleri
-
Başlıca sabitler ve etkileri
MIE_SCALE_HEIGHT, aerosoller içinRAYLEIGH_SCALE_HEIGHTkarşılığıdır; parçacıklar genelde ufka yakın yoğunlaştığı için daha küçük bir değer olan1.2kmseçilirMIE_BETA_SCATTER, parçacıkların ışığı kameraya doğru ne kadar saçacağını kontrol eder; çoğunlukla dalga boyundan bağımsız olduğu içinvec3(0.003)olarak ayarlanırMIE_BETA_EXT, yoldan ne kadar ışık çıkarıldığını gösteren Mie sönümleme katsayısıdır ve uzak atmosferin daha puslu görünmesini sağlarMIE_G, anizotropiyi kontrol eder;0.0düzgün saçılma,1.0ise daha güçlü ileri yönlü saçılma eğilimi anlamına gelirOZONE_BETA_ABS,vec3(0.00065, 0.00188, 0.00008)değerine sahiptir; yeşil ile sarı-turuncu tonları daha fazla soğurarak gökyüzü rengini mavi, kırmızı ve mora doğru kaydırır- Mie ve ozon birlikte ele alındığında daha doğal bir “sky blue” tonu ve güneş çevresinde puslu bir ışık halesi oluşur; güneş ufka yaklaştığında Mie saçılması etkisi daha belirgin hale gelir
Işık yolları ve gün batımı·gün doğumu
-
Mevcut uygulamanın sınırları
- sky fragment shader, farklı irtifalarda doğal renkleri render edebilir ve Mie, Rayleigh, ozon geçirgenliği modellerini yansıtabilir
- Ancak güneş ufka yaklaştırılsa bile ışık zayıflaması ya da gün batımı·gün doğumu etkisi olmadan yalnızca beyaz, puslu bir ışık kümesi görünür
- Bunun nedeni, mevcut raymarching döngüsünün ışık zayıflamasını yalnızca kameradan her örneğe giden görüş ışını üzerinde hesaplamasıdır
- Örnek noktasına ulaşmadan önce, güneş ışığının atmosferden geçerken ne kadar kayba uğradığını da hesaplamak gerekir
-
light-march iç içe döngüsü
- Her örnek noktasında, ışık kaynağı yönünde ayrı bir iç içe döngü çalıştırılarak bu yolun geçirgenliği örneklenir
- İlgili yaklaşım real-time cloudscapes ve volumetric lighting içinde de kullanılır
lightMarch(float start, float sunY),LIGHTMARCH_STEPSkadar yinelenirkenodR,odM,odOdeğerlerini biriktirir- Mevcut uygulamadaki optik derinlik
viewODR,viewODM,viewODOüzerine güneş yönündeki optik derinliksunODeklenir - Nihai
tau,BETA_R * (viewODR + sunOD.x),BETA_M_EXT * (viewODM + sunOD.y),BETA_OZONE_ABS * (viewODO + sunOD.z)değerlerinin toplamından oluşur - Bu uygulama ile gün batımı, gün doğumu, tepedeki güneş ve aradaki aydınlatma koşullarındaki gökyüzü render edilebilir
sun angleuniform'u ile gün boyunca gökyüzünün mavi tonundaki değişim oluşturulur ve Mie saçılması, gün batımı ile gün doğumunda ışığı ufukla doğal biçimde karıştırır- Güneş alçaktayken ozon, gökyüzüne mor tonlar katar
Gezegen atmosferine genişletme
-
Düz arka plandan post-processing efektine
- Daha önce oluşturulan shader iyi bir gökyüzü arka planı sağlar, ancak React Three Fiber sahnesinde düz bir arka plana yakındır
- Sonraki adım, bunu post-processing effect'e dönüştürerek sahne derinliğini hesaba katan bir hacim ve gezegen mesh'ini saran bir atmosfer kabuğu olarak render etmektir
- Bunun için
screenUVkoordinatlarından dünya uzayı koordinatları yeniden oluşturulur ve sahnenin depth buffer'ı raymarching'e yansıtılır
-
Dünya uzayı yeniden oluşturma ve 3D ışınlar
- Atmosfer saçılmasını sahneye uygulamak için yalnızca gökyüzünü çizmek değil, kamera ile ekranda render edilen nesneler arasındaki alanı doldurmak gerekir
- Gerekli veriler sahnenin depth buffer'ı, kameranın
projectionMatrixInverse,matrixWorld,positiondeğerleridir ve bunlar post-processing efektinin uniform'ları olarak aktarılır getWorldPosition(vec2 uv, float depth),depth * 2.0 - 1.0ileclipZoluşturur,uv * 2.0 - 1.0ile NDC koordinatlarını üretir, ardındanprojectionMatrixInverseveviewMatrixInverseuygular- Aynı süreç, On Shaping Light içindeki volumetric lighting post-processing efektinde de kullanılır
- Mevcut pikselin
worldPositiondeğeri alındıktan sonrarayOriginkamera konumu olarak,rayDirisenormalize(worldPosition - rayOrigin)ile hesaplanır ve ekrandaki her piksel için 3D ışın boyunca ilerlenir
-
Depth buffer ile raymarch aralığını ayarlama
- Sahne geometrisini hesaba katmak için sabit
stepSizeyerine, mevcut ışının raymarch aralığı depth buffer ile belirlenmelidir sceneDepth = depthToRayDistance(uv, depth)ile ışın üzerindeki sahne derinliği alınır- Arka plan pikselleri
depth >= 1.0 - 1e-7ile ayırt edilir ve “sky pixels” içinsceneDepth = atmosphereHeight * SKY_MARCH_DISTANCE_MULTIPLIERuygulanır - Işın aşağı yöneliyorsa,
tGround = observerAltitude / max(-rayDir.y, 1e-4)ile zemin kesişimi hesaplanır verayEnd = min(rayEnd, tGround)ile sınırlandırılır - Nihai
stepSize,(rayEnd - rayStart) / float(PRIMARY_STEPS)olarak hesaplanır - Yakın nesnelere ya da zemine çarpan ışınlar daha küçük
stepSizeile daha hassas örneklenir; uzağa giden ışınlarda ise aynı örnek sayısı daha uzun bir mesafeye dağıtılır
- Sahne geometrisini hesaba katmak için sabit
-
Sahne içi atmosferik sis
- Post-processing efekti olarak uygulanan shader, sahnenin tüm hacmine atmosfer saçılması uygular ve sahne geometrisini hesaba katarken sky shader'ı arka plan olarak kullanabilir
- Kameraya yakın nesneler daha net görünürken uzaktaki nesneler daha fazla bulanıklaşır
Raycasterile sürüklenebilir gök cisimleri eklenmiş etkileşimli örnek MaximeHeckel'in tweet'inde görülebilir
Gezegen render etme
-
Gerekli iki adım
- Gezegenin etrafında gerçekçi bir atmosfer render etmek için, büyük ölçeği işleyebilen bir logarithmic depth buffer ve ışının atmosferde nerede başlayıp bittiğini tanımlayan küresel bir atmosfer kabuğu gerekir
-
logarithmic depth buffer
- Gezegen ölçeğinde uzaktan bakıldığında, shader atmosfer ile gezegen kabuğu arasındaki derinlik farkını ayırt etmekte zorlanabilir ve bu da depth fighting sorununa yol açabilir
- Atmosfer yüksekliği yalnızca birkaç km olduğu için, hem sahnenin depth buffer tanımı hem de post-processing efektlerinde bunun okunma biçimi birlikte ayarlanmalıdır
- React Three Fiber'da
Canvası saranglprop içindelogarithmicDepthBuffer: trueayarlanır - Örnek yapılandırma
<Canvas shadows gl={{ alpha: true, logarithmicDepthBuffer: true }}>biçimindedir - Shader tarafında, logarithmic depth buffer'ı ışın üzerindeki mesafeye geri çevirmek için
sceneDepthhesabı yeniden tanımlanır logDepthToViewZ(depth)fonksiyonupow(2.0, depth * log2(cameraFar + 1.0)) - 1.0kullanır ve-ddöndürür
-
ray-sphere intersection ile atmosfer aralığını bulma
- Görüş ışınının atmosfer küresine (atmospheric sphere) girip çıktığı noktaları bulmak için ray-sphere intersection testi kullanılır
- İki kesişim noktası elde edildiğinde, atmosfer dışında örnekleme israf edilmez ve raymarching döngüsü yalnızca bu aralıkla sınırlandırılabilir
- Gezegen küresel bir mesh olduğundan ve onu biraz daha büyük bir atmosfer küresi çevrelediğinden, aynı kesişim testi gezegenin kendisi için de uygulanır
- Işın atmosferden çıkmadan önce zemine çarpıyorsa, zemin kesişim noktası raymarching aralığının sonu olarak kullanılır
- Kullanılan
raySphereIntersectimplementasyonu, Inigo Quilez'in Ray-Surface intersection functions içeriğini referans alır
-
Sahne nesneleri ve atmosferin bitiş koşulları
- Atmosfer, gezegen yüzeyine ulaştığında ya da zemine ulaşmadan önce başka bir sahne nesnesiyle karşılaştığında sonlanmalıdır
- Gezegene çarpma durumunda varsayılan olarak
atmosphereFar = min(atmosphereFar, planetHit.x)ile zeminde durur - Başka bir mesh zeminin önünde render ediliyorsa, bu durum
sceneDepth < planetHit.x - 2.0koşuluyla belirlenir veatmosphereFar = min(atmosphereFar, sceneDepth)uygulanır - Bu mantık olmazsa, gezegen yüzeyinin nesneden daha önde görünmesi sorunu ortaya çıkar
-
React Three Fiber demosu ve kalan glitch'ler
- Bu iki düzenleme koda yansıtıldığında, atmosfer saçılımı bir post-processing efekti olarak uygulanabilir ve gezegen çevresindeki atmosfer render edilebilir
- Demo sahnesi React Three Fiber içinde basit bir “Sun - Earth system” render eder ve özel efekti uygular
- Güneş konumunu değiştirip uzaklaştığınızda, yer seviyesinden yörüngeye kadar farklı açılardan shader'ın ürettiği gökyüzü rengini görebilirsiniz
- Aynı efekt, nisan başındaki yazı duyurusu için hazırlanan poster görselinde de kullanıldı; render görseli bir tweet olarak paylaşıldı
- Sahnedeki torus, güneş battıktan sonra bile hâlâ “lit-up” durumda görünebilir
- Bunun nedeni, ana directional light'ın shadow-map veya shadow-camera ölçeğinin küçük kalması ve çok uzaktaki torus'u kapsayamamasıdır
- Geçici çözüm olarak, volumetric lighting article içeriğindeki shadow-mapping yaklaşımı yeniden kullanılabilir; ancak bu pratikte denenmedi
Güneş tutulmasını işleme
- Büyük bir gökcisminin Güneş'i kapattığı durumlar,
lightMarchsonrasındasunVisibilityfonksiyonu çağrılıp dönen[0, 1]değerinin geçirgenlikle çarpılmasıyla eklenebilir - Temel fikir, mevcut örnek noktasında Ay yönü ile Güneş yönü arasındaki skaler çarpımı karşılaştırmaktır
- İki yön neredeyse aynıysa ve skaler çarpım
1.0değerine yakınsa, Ay Güneş'i kapatıyor demektir; yönler dikse ve0.0değerine yakınsa kapatma yoktur - Yalnızca skaler çarpım kullanmak, sahnedeki nesnelerin boyutunu ve ölçeğini yansıtamaz; bu yüzden implementasyon, Güneş ile Ay'ın açısal uzaklığını ve her birinin açısal yarıçapını karşılaştırır
sunVisibility, Ay'ın Güneş'i kapatmadığı durumu, kameradan bakıldığında Ay'ın Güneş'ten daha büyük ya da benzer boyutta göründüğü halde kapattığı durumu ve Ay'ın kameradan bakıldığında Güneş yarıçapı içine girerek kapattığı durumu ele alır- Demo, mevcut atmosfer saçılımı örneğine
sunVisibilityve bir Ay mesh'i ekleyerek, Ay Güneş'le hizalandığında düşük ışık koşullarını Atmospheric Scattering shader'ının işlemesini sağlar - Daha gelişmiş güneş tutulması ve korona simülasyonu, Physically Based Real-Time Rendering of Eclipses makalesinde ele alınır; ancak bu makaledeki implementasyon WebGL'e taşınmadı
Diğer gezegenlerin atmosferleri
- Kullanılan atmosfer yoğunluğu ve saçılım modeli büyük ölçüde gezegen ile atmosfer yarıçapları ve
RayleighScaleHeight,RayleighBeta,MieScaleHeight,MieBeta,mieBetaExt,mieG,OzoneHeight,OzoneWidthgibi birkaç sabitle belirlenir - Bu değerler ayarlanarak Mars atmosferine ya da başka gezegenlerin atmosferlerine yakın sonuçlar elde edilebilir
- Mars için kullanılan değerler yaklaşık değerlerdir
planetRadius: 3390atmosphereRadius: 3500, yaklaşık110 kmkalınlıkrayleighScaleHeight: 11.1rayleighBeta: new THREE.Vector3(0.019, 0.013, 0.0057)mieScaleHeight: 1.5mieBeta: 0.04mieBetaExt: 0.044mieG: 0.65ozoneCenterHeight: 0.0ozoneWidth: 1.0ozoneBetaAbs: new THREE.Vector3(0.0, 0.0, 0.0)sunIntensity: 15.0planetSurfaceColor: '#8B4513'
- Mevcut sabitler bu değerlerle değiştirildiğinde daha tozlu ve turuncu tonlu bir atmosfer elde edilir; ayrıca Mars'a özgü gün batımındaki mavi ton da yakalanabilir
- İlgili çalışmalardan biri Physically Based Rendering of the Martian Atmosphere makalesidir
LUT tabanlı atmosferik saçılım
-
Yaklaşım ve kısaltılan kısımlar
- Mevcut shader, küçük ve büyük ölçekli atmosferi sezgisel biçimde render edebiliyor, ancak çok sayıda
PRIMARY_STEPSiçeren raymarching döngüsü, iç içelightmarchingdöngüsü ve tam ekran çözünürlükte yapılan hesaplamalar nedeniyle çalıştırma maliyeti yüksek - Sebastian Hillaire'in A Scalable and Production Ready Sky and Atmosphere Rendering Technique çalışması, maliyetli saçılım hesaplarını texture içinde saklayıp son render aşamasında önceden hesaplanmış texture'ları örnekleyip birleştiren Look Up Tables (LUTs) tabanlı bir yaklaşım öneriyor
- Ele alınan LUT'ler, ışığın atmosferden geçerken ne kadarının hayatta kaldığını saklayan Transmittance LUT, belirli bir kamera konumundaki gökyüzü rengini saklayan Sky-view LUT ve kamera ile görünen sahne geometrisi arasındaki atmosferik haze ile saçılan ışığı saklayan Aerial Perspective LUT
- Tüm makalenin implementasyonu birebir aktarılmadı; LUT'ler WebGPU compute shader için uygun olsa da zaman kısıtı ve yazının sürekliliği nedeniyle WebGL korunmuş
- Makalede Aerial Perspective LUT bir 3D texture, ancak bu implementasyonda 2D render target kullanılıyor
- Bu yaklaşımda kamera her hareket ettiğinde doğru piksel değerleri için texture'ların yeniden üretilmesi gerekiyor; bunları önceden hesaplayıp hazır tutmak zor
- Multi-Scattering zaman yetersizliği nedeniyle atlanmış
- Mevcut shader, küçük ve büyük ölçekli atmosferi sezgisel biçimde render edebiliyor, ancak çok sayıda
-
Transmittance LUT
- Mevcut shader'da tüm örnekleme noktaları, güneş ışığının ne kadar ulaştığını hesaplamak için
lightmarchçağırıyordu ve bu süreç pahalıydı - Transmittance LUT, bu veriyi düşük çözünürlükte önceden saklayarak daha sonra diğer LUT'lerin ışık verisine ihtiyaç duyduğunda okuyabilmesini sağlıyor
- Implementasyonda
250 x 64çözünürlüklü özel bir Frame Buffer Object tanımlanıyor, özel shader material özeltransmittanceLUTScenesahnesindeki full-screen quad'a uygulanıyor ve render sonucu texture downstream LUT'lere uniform olarak aktarılıyor - Her pikselde
vec3(0.0, radius, 0.0)noktasından itibaren raymarching yapılıyor; buradaradius,vUv.ykoordinatı boyuncaplanetRadius'tanatmosphereRadius'a kadar artıyor - LUT'nin x ekseni ışık açısını, y ekseni ise irtifayı temsil ediyor; saf beyaz
100%geçirgenlik anlamına gelirken siyah veya renkli alanlar zemini ya da havanın en kalın olduğu bölgeleri gösteriyor - Sonraki LUT'ler artık “verilen açı ve irtifada atmosferden geçip hayatta kalan ışık miktarı”nı yalnızca texture sorgusuyla alabiliyor
- Mevcut shader'da tüm örnekleme noktaları, güneş ışığının ne kadar ulaştığını hesaplamak için
-
Sky-view LUT
- Sky-view LUT, yerden belirli bir yöne bakıldığında gökyüzünün hangi renkte görüneceğini hesaplıyor
getSkyViewRayDir,vUv.xdeğerini azimuth[-PI, PI]aralığına,vUv.ydeğerini ise elevation[-PI/2, PI/2]aralığına eşleyerek raymarching yönünü tanımlıyor- Elevation için
(vUv.y * vUv.y - 0.5) * PIbiçiminde quadratic mapping kullanılıyor; bu, uzak mesafelerde Sky View'un aşırı titreşmesini önlemek için bir geçici çözüm - Işın atmosfere girmiyorsa siyah döndürülüyor; gezegene çarpan ışınlar ise yalnızca görünür atmosfer aralığı boyunca raymarching yapıyor ve gezegene ulaştığında daha erken duruyor
- Saçılım döngüsü öncekiyle aynı, ancak Sky View yönü boyunca ilerliyor ve güneş ışığı için Transmittance LUT kullanılıyor
-
Aerial Perspective LUT
- Hillaire'in makalesinden farklı olarak bu implementasyonun sonucu bir 2D texture ve her piksel görünen ekrandaki tek bir piksele karşılık geliyor
- Sahnenin depth buffer'ı kullanılarak ilgili ışın boyunca ne kadar ilerlenip saçılımın ne kadar biriktirileceği belirleniyor
- Mevcut saçılım kodu neredeyse olduğu gibi yeniden kullanılıyor, ancak her örnek güneş ışığı görünürlüğünü Transmittance LUT'den alıyor
- Çıktıda RGB'ye birikmiş atmosferik saçılım yazılıyor, alfada ise compositing sırasında kullanılacak packed view transmittance değeri saklanıyor
- Implementasyon akışı,
depthBufferiçinden derinliği okuyupgetWorldPosition(vUv, depth)ile ekran pikselinin world space konumunu geri oluşturduktan sonra kamera konumundan bu world konumuna gidenrayDir'i hesaplama şeklinde ilerliyor - Ardından
logDepthToRayDistance(vUv, depth)ile sahne derinliği ışın mesafesine dönüştürülüyor, atmosfer ve gezegen kesişimleri hesaplanıyor ve yalnızca görünür atmosfer aralığında march yapılıyor
-
Birleştirme
- Sky-view LUT ve Aerial Perspective LUT oluşturulduktan sonra son post-processing pass'te ikisi birleştiriliyor
- Buradaki temel iş, mevcut
rayDirdeğerini Sky View UV koordinatlarına dönüştürmek - Sahne geometrisine Aerial Perspective LUT uygulanıyor; alfa kanalı view transmittance, RGB kanalları ise saçılan ışık olarak kullanılıyor ve
color = color * aerialPerspective.a + aerialPerspective.rgbhesaplanıyor - Arka plan piksellerinde Sky View LUT örnekleniyor;
depth >= 1.0 - 1e-7ise bunun arka plan olduğu kabul edilipcolor = inputColor.rgb + sampleSkyViewLUT(rayDir, planetCenter)uygulanıyor - Son olarak
ACESFilm(color)vepow(color, vec3(1.0 / 2.2))uygulanıyor - LUT tabanlı atmosfer implementasyonunun tamamı Github link üzerinden görülebilir
Kapanış
- LUT tabanlı atmosferik saçılımın sonucu, önceki tam raymarching sürümüyle neredeyse aynı görünebilir, ancak iç süreç farklıdır
- İş daha küçük LUT'lere bölünüp son efektte birleştirilir ve her örnekte güneşe doğru tekrar tekrar raymarching yaparak ulaşan ışık hesaplanmaz
- Aydınlatma bilgisi doğrudan Transmittance LUT'den alındığı için maliyetli iç içe döngüler basit texture sorgularıyla değiştirilir ve son sahnede göz ardı edilemeyecek bir performans artışı elde edilir
- Bu implementasyon, Sébastian Hillaire ve başka alanlardaki implementasyonlarla kıyaslandığında eksik kalıyor; özellikle Sky View tarafında banding ve flickering var ve kısaltılan kısımlar nedeniyle optimum değil
- Muhtemelen en baştan WebGPU kullanmak gerekirdi
- Gerçek bir production-grade implementasyon olarak Shoda Matsuda'nın (@shotamatsuda) three-geospatial projesi öneriliyor
- Ek olarak volumetric clouds ekleme çalışması da yapılmış, ancak sonuç hâlâ mixed bag; yazıda gösterilecek kadar tatmin edici olmadığından daha fazla çalışma gerekiyor
1 yorum
Hacker News yorumları
Görsel efektler geliştirip bunların giderek daha gerçekçi hale geldiğini izlemenin ayrı bir keyfi var; bir gün ben de bu alanda bizzat denemeler yapmak istiyorum
Eskiden videoları milyonlarca izlenme alıyordu, şimdi ise 500 bini bile zar zor geçiyor. Bunun nedeni, pandemi döneminde herkes evdeyken rastgele şeylere ilgi göstermesi de olabilir
Genelde uyurken açıyorum; sakin ama derinlemesine teknik konulara inen böyle içeriklerden daha fazla olsa keşke diye düşünüyorum, hatta bazen kendim üretmeyi bile düşündüm
Güneş battıktan sonra da bir süre başımızın üzerindeki atmosfer ve ufkun üstündeki bölge hâlâ güneş ışığı almaya devam eder; Dünya atmosferinde Güneş ufkun altında 18 dereceye inene kadar belirgin alacakaranlık sürer. Bunu ray tracing ile uygulamak pratik olmayabilir ama bunun için kullanılan yaygın algoritmalar var
https://www.threads.com/@mrsharpoblunto/post/DVS4wfYiG8f?xmt...
https://www.threads.com/@mrsharpoblunto/post/C6Vc-S1O9mX?xmt...
https://www.threads.com/@mrsharpoblunto/post/C6apksDRa8q?xmt...
1993 tarihli, bu konudaki öncü çalışmalardan sayılabilecek ve okunması çok kolay olan Nishita ve diğerlerinin “Display of The Earth Taking into Account Atmospheric Scattering” makalesini uyguladığımı hatırlıyorum: https://www.researchgate.net/publication/2933032_Display_of_...
Çalışır hale getirdiğimde, “Bu kadar karmaşık bir gerçek dünya olgusunu birkaç nispeten basit hesaplamayla oldukça iyi modelleyebiliyormuşum” dediğim bir an olmuştu. Statik mavi bir skybox'tan bir anda tam bir gece-gündüz döngüsüne geçmiştim
Bir zamanlar web'de gökyüzünü birkaç gradyanı üst üste bindirerek render etmeyi denesem nasıl olur diye düşünmüştüm. Bir noktaya kadar başarılı olup fena olmayan sonuçlar almış olabilirim ama burada yapılanla kıyaslanmaz. Ortaya çıkan şey etkileyici ve ilham verici
Sadece bununla bile oldukça ikna edici bir gün batımı/gün doğumu döngüsü çıktığını görünce şaşırmıştım; yanlış hatırlamıyorsam güneşin kendisi de bir şekilde bunun içinden doğal biçimde ortaya çıkıyordu. Microsoft'un C# oyun geliştirme platformu XNA'i kullanırken Riemer'in harika eğitim serisini takip etmiştim; arşivlenmiş kopyası burada https://github.com/SimonDarksideJ/XNAGameStudio/wiki/Riemers...
Yalnız saçılımla ilgili kısmı göremiyorum; o bölümü başka bir yerden almış olabilirim. Formüller içeren makaleler okuduğumu hatırlıyorum
https://spaceengine.org/
“SpaceEngine'de kaç nesne var?” sorusuna verilen yanıt; Hipparcos yıldız kataloğunun tamamı, bilinen tüm ötegezegenler, on binden fazla galaksi ve Güneş Sistemi'ndeki nesnelerin çoğu dahil olmak üzere 130 bin nesne olduğu, buna ek olarak gözlemlenebilir evrende gerçekte var olandan bile fazla galaksi ve yıldız sisteminin eklendiği yönünde. “Su gezegeni nasıl sıcak olabilir?” sorusuna ise üst atmosferdeki suyun sıcak su buharı olduğu, aşağı indikçe yüksek basınç altında sıvıya yumuşak biçimde geçtiği ve daha derinlerde ice VII denilen katı bir hâle dönüştüğü cevabı veriliyor. “Nasıl hareket edilir?” sorusunun cevabı ise WASD tuşları
Harika bir oyun ve epey eski olmasına rağmen hâlâ bu kadar iyi başka bir şey görmedim
Bu yazıyı görünce benim de aklıma SpaceEngine geldi
En sevdiğim makalelerden biri: http://www.graphics.stanford.edu/papers/bssrdf/bssrdf.pdf
Sütü render etmenin zor bir problem olduğunu sanırım ilk kez o zaman öğrenmiştim
Sanırım ancak %5'ini anlayabildim ama yine de çok etkilendim
Üstelik MIT lisansı ise oyunumdaki skybox sorunu çözülmüş sayılır. Perspektif sabit kalacağından, yalnızca güneşin gökyüzü boyunca hareketini render etmem gerekir; buna bir sinüs dalgası periyoduyla yıl içindeki güneş açısı değişimini de ekleyebilirim