आसमान, सूर्यास्त और ग्रहों की rendering
(blog.maximeheckel.com)- ब्राउज़र shader Rayleigh scattering, Mie scattering और ozone absorption को मिलाकर नीला आसमान और सूर्यास्त·सूर्योदय को real time में render करता है
- कैमरा किरण की optical depth और Beer's Law transmittance को accumulate किया जाता है, और phase function से सूर्य की दिशा के अनुसार scattering distribution की गणना की जाती है
- सूर्यास्त effect के लिए हर sample पर सूर्य की दिशा में अलग light-march चलाया जाता है, ताकि वातावरण से गुजरते समय सूर्यप्रकाश में होने वाले नुकसान को दर्शाया जा सके
- planar sky shader, depth buffer और world coordinates reconstruction के साथ post-processing effect बन जाता है, जिससे scene objects के बीच का atmospheric fog भी संभाला जाता है
- ग्रह-स्तर पर इसे logarithmic depth buffer, ray-sphere intersection, और LUT-आधारित Transmittance·Sky-view·Aerial Perspective तक विस्तारित किया जाता है
atmospheric scattering shader के लक्ष्य और संदर्भ सामग्री
- लक्ष्य यह है कि Space Shuttle Endeavour की low-earth orbit sunset तस्वीरों की तरह, पृथ्वी के ऊपरी वातावरण की गहरा नारंगी·नीली·और अंतरिक्ष पृष्ठभूमि की काली परतों को ब्राउज़र shader में पुनर्निर्मित किया जाए
- implementation का दायरा raymarching, Rayleigh scattering, Mie scattering, और ozone absorption को मिलाकर एक realistic sky dome से शुरू होता है, और आगे ग्रह के आसपास के atmospheric shell तथा LUT-आधारित optimization तक बढ़ता है
- मुख्य संदर्भ सामग्री हैं Three Geospatial, Sébastien Hillaire का A Scalable and Production Ready Sky and Atmosphere Rendering Technique, और Atmospheric Scattering (and also just faking it)
sky rendering का मूल मॉडल
-
simple gradient क्यों काफ़ी नहीं है
- आसमान का रंग सिर्फ़ एक साधारण नीली background नहीं है, बल्कि इसे प्रकाश और हवा तथा उसके घटकों के interaction के परिणाम के रूप में देखना चाहिए
- इसमें observer की ऊँचाई, धूल की मात्रा, और दिन का समय जैसे variables को ध्यान में रखना होता है, और गणना volume के भीतर की जाती है
-
atmospheric density sampling
- वातावरण को volumetric clouds या volumetric light की तरह raymarching से sample किया जाता है
- कैमरा position से किरण छोड़ी जाती है और transparent medium के साथ आगे बढ़ते हुए, वातावरण से गुजरकर बची रहने वाली रोशनी यानी transmittance और हर sample पर कैमरा की ओर फिर से निर्देशित होने वाली scattering की गणना की जाती है
- raymarching की पुनरावृत्ति के लिए Painting with Math: A Gentle Study of Raymarching देखा जा सकता है
-
Rayleigh density और optical depth
- transmittance निकालने के लिए किरण के रास्ते में मिलने वाली atmospheric density को accumulate करके optical depth की गणना करनी होती है
- Rayleigh density function ऊँचाई
hपर यह दिखाता है कि “हवा” कितनी है, और ऊँचाई बढ़ने पर वातावरण के पतला होने के प्रभाव को दर्शाता है - उदाहरण implementation में
RAYLEIGH_SCALE_HEIGHT = 8.0km,ATMOSPHERE_HEIGHT = 100.0km,VIEW_DISTANCE = 200.0km,PRIMARY_STEPS = 24का उपयोग किया गया है rayleighDensity(h)हैexp(-max(h, 0.0) / RAYLEIGH_SCALE_HEIGHT), और loop मेंviewOpticalDepth += dR * stepSizeके रूप में accumulate होता है
-
Beer's Law और दिन के आसमान का नीला रंग
- optical depth से किसी विशेष बिंदु पर transmittance
Tनिकाला जाता है, जहाँT=1.0का मतलब है रोशनी का कोई नुकसान नहीं, औरT=0.0का मतलब है रोशनी पूरी तरह गायब हो गई - transmittance की गणना Beer's Law से होती है, और उदाहरण code
vec3 transmittance = exp(-rayleighBeta * viewOpticalDepth)का उपयोग करता है rayleighBetaRayleigh scattering coefficient है, जिसे shader मेंvec3(0.0058, 0.0135, 0.0331)के रूप में रखा गया है- सूर्यप्रकाश की दिशा और view ray के बीच के कोण को
3.0 / (16.0 * PI) * (1.0 + mu * mu)रूप वाले Rayleigh phase function से model किया जाता है - Rayleigh scattering coefficient के कारण लाल रंग लगभग scatter नहीं होता, हरा थोड़ा अधिक scatter होता है, और नीला सबसे अधिक scatter होता है, इसलिए दिन का आसमान नीला दिखता है
- जब इसे हर pixel के लिए एक किरण तक बढ़ाया जाता है, तो horizon की दिशा में ज़्यादा वातावरण पार होने के कारण वह चमकीले सफ़ेद haze जैसा दिखता है, जबकि ऊँचाई बढ़ने पर रंग और गहरा, अधिक dark blue हो जाता है
- optical depth से किसी विशेष बिंदु पर transmittance
Mie scattering और ozone absorption
-
Rayleigh alone से छूट जाने वाले प्रभाव
- सिर्फ़ Rayleigh scattering से भी ठीक-ठाक परिणाम मिल सकते हैं, लेकिन अधिक realistic आसमान के लिए अतिरिक्त atmospheric effects चाहिए
- Mie scattering धूल या aerosol जैसे बड़े particles और प्रकाश के interaction को दर्शाता है, और इसमें density function तथा दिशा-आधारित redistribution दिखाने वाला phase function होता है
- ozone absorption ऊपरी वातावरण से गुजरने वाली रोशनी की कुछ wavelengths को scatter किए बिना ही path से हटा देता है
- ozone absorption खासकर horizon, sunset, sunrise, और इनके आसपास की twilight में आसमान के रंग को और गहरा बनाता है तथा रंगों को shift करता है
-
Mie और ozone का accumulation
- Rayleigh, Mie, और ozone को साथ इस्तेमाल करने वाले implementation में
viewODR,viewODM,viewODOमें क्रमशः उनकी optical depth accumulate की जाती है - हर sample पर
dR = rayleighDensity(h),dM = mieDensity(h),dO = ozoneDensity(h)की गणना होती है, औरtauकोBETA_R * viewODR,BETA_M_EXT * viewODM,BETA_OZONE_ABS * viewODOके योग से बनाया जाता है - transmittance
exp(-tau)से निकाला जाता है, औरsumR,sumM,sumOमें संबंधित density, transmittance, औरstepSizeaccumulate होते हैं - अंतिम scattering की गणना
SUN_INTENSITY * (phaseR * BETA_R * sumR + phaseM * BETA_M_SCATTER * sumM + BETA_OZONE_SCATTER * sumO)के रूप में की जाती है
- Rayleigh, Mie, और ozone को साथ इस्तेमाल करने वाले implementation में
-
प्रमुख constants और प्रभाव
MIE_SCALE_HEIGHT, aerosol के लिएRAYLEIGH_SCALE_HEIGHTके बराबर है, और क्योंकि particles आम तौर पर horizon के पास केंद्रित होते हैं, इसे1.2kmजैसे छोटे मान पर सेट किया जाता हैMIE_BETA_SCATTERनियंत्रित करता है कि particles रोशनी को कैमरा की ओर कितना scatter करें, और क्योंकि यह अधिकतर wavelength-independent होता है, इसेvec3(0.003)पर सेट किया जाता हैMIE_BETA_EXTMie extinction coefficient है, जो दिखाता है कि path से कितनी रोशनी हटती है, और इससे दूर का वातावरण अधिक hazy दिखता हैMIE_Ganisotropy को नियंत्रित करता है, जहाँ0.0uniform scattering और1.0अधिक मजबूत forward-scattering bias को दर्शाता हैOZONE_BETA_ABSका मानvec3(0.00065, 0.00188, 0.00008)है, जो हरे और yellow-orange spectrum को अधिक absorb करके आसमान के रंग को नीले·लाल·बैंगनी की ओर shift करता है- Mie और ozone को साथ मिलाने पर अधिक प्राकृतिक “sky blue” रंग और सूर्य के आसपास hazy glow बनती है, और जब सूर्य horizon के क़रीब होता है तब Mie scattering effect और अधिक स्पष्ट हो जाता है
प्रकाश पथ और सूर्यास्त·सूर्योदय
-
मौजूदा implementation की सीमाएँ
- sky fragment shader अलग-अलग ऊँचाइयों पर प्राकृतिक रंग render कर सकता है और Mie, Rayleigh, ओज़ोन transmittance model को reflect कर सकता है
- लेकिन सूर्य को क्षितिज के पास ले जाने पर भी light attenuation या सूर्यास्त·सूर्योदय effect के बिना सिर्फ सफेद धुंधला प्रकाश-घेरा ही दिखाई देता है
- ऐसा इसलिए था क्योंकि मौजूदा raymarching loop सिर्फ कैमरे से हर sample तक जाने वाली view ray पर ही light attenuation की गणना करता था
- sample बिंदु तक पहुँचने से पहले, सूर्य का प्रकाश वायुमंडल से गुजरते हुए कितना loss होता है, इसकी भी गणना करनी होती है
-
light-march nested loop
- हर sample बिंदु पर light source की दिशा में अलग nested loop चलाकर उस path की transmittance को sample किया जाता है
- यह approach real-time cloudscapes और volumetric lighting में भी इस्तेमाल होती है
lightMarch(float start, float sunY)LIGHTMARCH_STEPSजितनी बार दोहराते हुएodR,odM,odOको accumulate करता है- मौजूदा implementation की optical depth
viewODR,viewODM,viewODOमें सूर्य दिशा की optical depthsunODजोड़ी जाती है - अंतिम
tauकोBETA_R * (viewODR + sunOD.x),BETA_M_EXT * (viewODM + sunOD.y),BETA_OZONE_ABS * (viewODO + sunOD.z)को जोड़कर बनाया जाता है - इस implementation से सूर्यास्त, सूर्योदय, सिर के ऊपर सूर्य, और इनके बीच की lighting conditions वाला आकाश render किया जा सकता है
sun angleuniform से पूरे दिन आकाश के नीले रंग में बदलाव बनाया जाता है, और Mie scattering सूर्यास्त और सूर्योदय के समय प्रकाश को क्षितिज के साथ प्राकृतिक ढंग से blend करती है- जब सूर्य नीचे होता है, तो ओज़ोन आकाश में बैंगनी टोन जोड़ता है
ग्रहों के वायुमंडल तक विस्तार
-
समतल background से post-processing effect तक
- पहले बनाया गया shader अच्छा sky background देता है, लेकिन यह React Three Fiber scene के समतल background के काफ़ी करीब है
- अगला चरण इसे post-processing effect में बदलना है, ताकि scene depth को ध्यान में रखने वाले volume और planetary mesh को घेरे हुए atmospheric shell के रूप में इसे render किया जा सके
- इसके लिए
screenUVनिर्देशांक से world space निर्देशांक को reconstruct किया जाता है और scene के depth buffer को raymarching में शामिल किया जाता है
-
world space reconstruction और 3D ray
- scene पर atmospheric scattering लागू करने के लिए सिर्फ आकाश draw करना काफ़ी नहीं है, बल्कि कैमरे और स्क्रीन पर render हुए objects के बीच की जगह भी भरनी होती है
- ज़रूरी data है scene का depth buffer, कैमरे का
projectionMatrixInverse,matrixWorld,position; और इन values को post-processing effect के uniform के रूप में pass किया जाता है getWorldPosition(vec2 uv, float depth)depth * 2.0 - 1.0सेclipZबनाता है,uv * 2.0 - 1.0से NDC coordinates बनाता है, और फिरprojectionMatrixInverseतथाviewMatrixInverseलागू करता है- यही प्रक्रिया On Shaping Light के volumetric lighting post-processing effect में भी इस्तेमाल होती है
- मौजूदा pixel का
worldPositionमिलने के बादrayOriginको कैमरे की position औरrayDirकोnormalize(worldPosition - rayOrigin)से calculate किया जाता है, ताकि स्क्रीन के हर pixel के लिए 3D ray के साथ आगे बढ़ा जा सके
-
depth buffer से raymarch range समायोजन
- scene geometry को ध्यान में रखने के लिए fixed
stepSizeकी जगह depth buffer से मौजूदा ray की raymarch range तय करनी होती है sceneDepth = depthToRayDistance(uv, depth)से ray पर scene depth निकाली जाती है- background pixel की पहचान
depth >= 1.0 - 1e-7से की जाती है, और “sky pixels” परsceneDepth = atmosphereHeight * SKY_MARCH_DISTANCE_MULTIPLIERलागू किया जाता है - अगर ray नीचे की ओर जा रही हो, तो
tGround = observerAltitude / max(-rayDir.y, 1e-4)से ground intersection निकाला जाता है औरrayEnd = min(rayEnd, tGround)से उसे सीमित किया जाता है - अंतिम
stepSizeको(rayEnd - rayStart) / float(PRIMARY_STEPS)से calculate किया जाता है - पास के objects या ज़मीन से टकराने वाली rays को छोटे
stepSizeके साथ ज़्यादा सटीक sample किया जाता है, जबकि दूर तक जाने वाली rays पर उतने ही samples लंबी दूरी में distribute किए जाते हैं
- scene geometry को ध्यान में रखने के लिए fixed
-
scene के अंदर atmospheric fog
- post-processing effect के रूप में implement किया गया shader scene के पूरे volume पर atmospheric scattering लागू करता है, और scene geometry को ध्यान में रखते हुए sky shader को background की तरह इस्तेमाल कर सकता है
- कैमरे के पास के objects ज़्यादा साफ़ दिखाई देते हैं, जबकि दूर के objects ज़्यादा धुंधले हो जाते हैं
Raycasterसे drag किए जा सकने वाले खगोलीय objects वाला interactive example MaximeHeckel की tweet में देखा जा सकता है
ग्रह rendering
-
ज़रूरी दो चरण
- ग्रह के आसपास यथार्थवादी atmosphere render करने के लिए बड़े scale को संभालने वाला logarithmic depth buffer और एक गोलाकार atmospheric shell चाहिए, जो यह परिभाषित करे कि light ray atmosphere में कहाँ से शुरू होती है और कहाँ खत्म होती है
-
logarithmic depth buffer
- ग्रह-स्तर के scale पर दूर से देखने पर shader के लिए atmosphere और planet shell के depth difference को अलग करना मुश्किल हो सकता है, जिससे depth fighting हो सकता है
- atmosphere की ऊँचाई सिर्फ कुछ km होती है, इसलिए scene के depth buffer की definition और post-processing effects में उसे पढ़ने के तरीके, दोनों को adjust करना पड़ता है
- React Three Fiber के
Canvasको wrap करने वालेglprop मेंlogarithmicDepthBuffer: trueसेट किया जाता है - example setting का रूप
<Canvas shadows gl={{ alpha: true, logarithmicDepthBuffer: true }}>है - shader में logarithmic depth buffer को ray पर distance में वापस बदलने के लिए
sceneDepthcalculation को फिर से define किया जाता है logDepthToViewZ(depth)मेंpow(2.0, depth * log2(cameraFar + 1.0)) - 1.0का उपयोग होता है और यह-dreturn करता है
-
ray-sphere intersection से atmospheric interval ढूँढना
- view ray atmospheric sphere में कहाँ प्रवेश करती है और कहाँ बाहर निकलती है, यह पता करने के लिए ray-sphere intersection test का उपयोग किया जाता है
- दो intersection points मिलने पर atmosphere के बाहर samples बेकार नहीं होते, और raymarching loop को सिर्फ उसी interval तक सीमित किया जा सकता है
- ग्रह एक spherical mesh है और उसके चारों ओर उससे थोड़ा बड़ा atmospheric sphere होता है, इसलिए वही intersection test ग्रह पर भी लागू किया जाता है
- अगर ray atmosphere से बाहर निकलने से पहले ground से टकराती है, तो ground intersection point को raymarching interval के end के रूप में इस्तेमाल किया जाता है
- इस्तेमाल किया गया
raySphereIntersectimplementation Inigo Quilez के Ray-Surface intersection functions से संदर्भित है
-
scene objects और atmosphere termination condition
- atmosphere को planet surface से टकराने पर, या ground तक पहुँचने से पहले किसी दूसरे scene object से मिलने पर समाप्त हो जाना चाहिए
- planet से टकराने के मामले में डिफ़ॉल्ट रूप से
atmosphereFar = min(atmosphereFar, planetHit.x)के साथ ground पर रुकता है - अगर कोई दूसरा mesh ground के सामने render हो रहा हो, तो
sceneDepth < planetHit.x - 2.0condition से उसे पहचाना जाता है औरatmosphereFar = min(atmosphereFar, sceneDepth)लागू किया जाता है - यह logic न हो तो planet surface object के सामने दिखाई देने लगती है
-
React Three Fiber demo और बाकी glitches
- इन दो adjustments को code में लागू करने पर atmosphere scattering को post-processing effect के रूप में implement किया जा सकता है और ग्रह के आसपास का atmosphere render किया जा सकता है
- demo scene React Three Fiber में एक साधारण “Sun - Earth system” render करता है और custom effect apply करता है
- सूरज की position adjust करके और zoom out करने पर जमीन से orbit तक अलग-अलग angles पर shader द्वारा बनाया गया sky color देखा जा सकता है
- यही effect अप्रैल की शुरुआत में आने वाले लेख के teaser poster image में भी इस्तेमाल हुआ था, और render image tweet के रूप में share की गई थी
- scene का torus सूर्यास्त के बाद भी “lit-up” state में दिख सकता है
- इसकी वजह यह है कि main directional light का shadow-map या shadow-camera scale छोटा है, इसलिए वह बहुत दूर मौजूद torus को cover नहीं कर पाता
- workaround के तौर पर volumetric lighting article वाले shadow-mapping approach को फिर से इस्तेमाल किया जा सकता है, लेकिन वास्तव में ऐसा किया नहीं गया
ग्रहण को handle करना
- जब कोई बड़ा खगोलीय पिंड सूरज को ढकता है, तो
lightMarchके बादsunVisibilityfunction को call करके और उसके return value[0, 1]को transmittance से multiply करके इसे जोड़ा जा सकता है - मूल विचार यह है कि current sample point से चाँद की दिशा और सूरज की दिशा के dot product की तुलना की जाए
- अगर दोनों दिशाएँ लगभग एक जैसी हों और dot product
1.0के करीब हो, तो चाँद सूरज को ढक रहा है; अगर वे orthogonal हों और0.0के करीब हों, तो ढकाव नहीं है - सिर्फ dot product से scene के objects के size और scale को reflect नहीं किया जा सकता, इसलिए implementation सूरज और चाँद की angular distance और उनके angular radius की तुलना करता है
sunVisibilityउन स्थितियों को handle करता है जहाँ चाँद सूरज को नहीं ढकता, जहाँ चाँद camera view से सूरज से बड़ा या लगभग बराबर दिखते हुए उसे ढकता है, और जहाँ चाँद camera view से सूरज की radius के अंदर आकर उसे ढकता है- demo में मौजूदा atmosphere scattering example के ऊपर
sunVisibilityऔर moon mesh जोड़ा गया है, ताकि चाँद को सूरज के साथ align करने पर कम रोशनी वाली स्थिति को Atmospheric Scattering shader संभाल सके - ज़्यादा परिष्कृत eclipse और corona simulation पर Physically Based Real-Time Rendering of Eclipses paper में चर्चा की गई है, लेकिन उस paper के implementation को WebGL में port नहीं किया गया
दूसरे ग्रहों के atmosphere
- इस्तेमाल किया गया atmosphere density और scattering model मुख्य रूप से ग्रह और atmosphere के radius,
RayleighScaleHeight,RayleighBeta,MieScaleHeight,MieBeta,mieBetaExt,mieG,OzoneHeight,OzoneWidthजैसे कुछ constants से तय होता है - इन values को adjust करके Mars atmosphere या दूसरे ग्रहों के atmosphere के करीब results बनाए जा सकते हैं
- Mars के लिए इस्तेमाल की गई values approximate हैं
planetRadius: 3390atmosphereRadius: 3500, लगभग110 kmthicknessrayleighScaleHeight: 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'
- मौजूदा constants को इन values से बदलने पर ज़्यादा धूलभरा और नारंगी-आभा वाला atmosphere मिलता है, और Mars की खास सूर्यास्त के समय की नीली आभा भी हासिल की जा सकती है
- संबंधित paper है Physically Based Rendering of the Martian Atmosphere
LUT-आधारित atmospheric scattering
-
अप्रोच और संक्षिप्त किए गए हिस्से
- मौजूदा shader छोटे scale और बड़े scale के atmosphere को सहज रूप से render कर सकता है, लेकिन
PRIMARY_STEPSवाले raymarching loop, nestedlightmarchingloop, और full-screen resolution calculation की वजह से इसकी execution cost बहुत अधिक है - Sebastian Hillaire का A Scalable and Production Ready Sky and Atmosphere Rendering Technique महंगे scattering calculation को texture में store करके, final render में पहले से compute किए गए texture को sample और composite करने वाला Look Up Tables(LUTs) आधारित तरीका प्रस्तावित करता है
- यहाँ जिन LUT का उपयोग किया गया है, वे हैं: atmosphere से गुजरते समय बची हुई रोशनी की मात्रा store करने वाला Transmittance LUT, किसी खास camera position से sky color store करने वाला Sky-view LUT, और camera तथा दिखने वाली scene geometry के बीच का atmospheric haze और scattered light store करने वाला Aerial Perspective LUT
- पूरे paper के implementation को ज्यों का त्यों नहीं अपनाया गया; LUT, WebGPU के compute shader के लिए उपयुक्त हैं, लेकिन समय की कमी और लेख की निरंतरता के कारण WebGL को बनाए रखा गया
- paper में Aerial Perspective LUT एक 3D texture है, लेकिन इस implementation में 2D render target का उपयोग किया गया है
- इस तरीके में camera के हिलने पर सही pixel values पाने के लिए texture को हर बार फिर से generate करना पड़ता है, इसलिए इसे पहले से precompute करना कठिन है
- Multi-Scattering को समय की कमी के कारण छोड़ा गया है
- मौजूदा shader छोटे scale और बड़े scale के atmosphere को सहज रूप से render कर सकता है, लेकिन
-
Transmittance LUT
- मौजूदा shader में हर sample point
lightmarchको call करके यह गणना करता था कि सूर्य का प्रकाश कितना पहुँचता है, और यह प्रक्रिया महंगी थी - Transmittance LUT इस data को कम resolution पर पहले से store करता है, ताकि बाद के LUT जब light data चाहें तो उसे पढ़कर उपयोग कर सकें
- implementation
250 x 64resolution वाला एक dedicated Frame Buffer Object define करता है, custom shader material को dedicated scenetransmittanceLUTSceneके full-screen quad पर apply करता है, और render result texture को downstream LUT के uniform के रूप में pass करता है - हर pixel पर
vec3(0.0, radius, 0.0)से raymarching शुरू होती है, जहाँradius,vUv.ycoordinate के साथplanetRadiusसेatmosphereRadiusतक बढ़ता है - LUT का x-अक्ष प्रकाश के angle को और y-अक्ष altitude को दर्शाता है; शुद्ध सफेद
100%transmittance है, जबकि काले या रंग वाले क्षेत्र जमीन या हवा के सबसे घने हिस्सों को दिखाते हैं - बाद के LUT अब “दिए गए angle और altitude पर atmosphere से गुजरकर बची हुई रोशनी की मात्रा” सिर्फ texture lookup से प्राप्त कर सकते हैं
- मौजूदा shader में हर sample point
-
Sky-view LUT
- Sky-view LUT यह गणना करता है कि जमीन से किसी विशेष दिशा में ऊपर देखने पर आसमान का रंग कैसा दिखेगा
getSkyViewRayDir,vUv.xको azimuth[-PI, PI]औरvUv.yको elevation[-PI/2, PI/2]में map करके raymarching direction define करता है- elevation के लिए
(vUv.y * vUv.y - 0.5) * PIवाली quadratic mapping का उपयोग किया गया है; यह दूर की दूरी पर Sky View के बहुत अधिक flicker होने से बचने के लिए एक workaround है - अगर ray atmosphere में प्रवेश नहीं करती, तो काला रंग return किया जाता है; और जो ray ग्रह से टकराती है, उसके लिए केवल दिखने वाले atmospheric segment तक raymarching की जाती है और ग्रह से टकराते ही पहले रोक दिया जाता है
- scattering loop पहले जैसा ही है, लेकिन यह Sky View direction के साथ आगे बढ़ता है और सूर्य के प्रकाश के लिए Transmittance LUT का उपयोग करता है
-
Aerial Perspective LUT
- Hillaire के paper के विपरीत, implementation का परिणाम 2D texture है, और हर pixel स्क्रीन पर दिखने वाले एक pixel के अनुरूप है
- scene depth buffer का उपयोग यह तय करने के लिए किया जाता है कि उस ray के साथ कितनी दूर तक march करना है और scattering को कितना accumulate करना है
- मौजूदा scattering code का लगभग पुन: उपयोग किया जाता है, लेकिन हर sample सूर्य-प्रकाश की visibility Transmittance LUT से लेता है
- output में RGB में accumulated atmospheric scattering store होती है, और alpha में compositing के समय उपयोग होने वाला packed view transmittance value store होता है
- implementation flow
depthBufferसे depth पढ़ता है,getWorldPosition(vUv, depth)से स्क्रीन pixel की world-space position reconstruct करता है, और फिर camera position से world position तक काrayDircalculate करता है - इसके बाद
logDepthToRayDistance(vUv, depth)से scene depth को ray distance में convert किया जाता है, atmosphere और ग्रह के intersection की गणना की जाती है, और फिर केवल दिखने वाले atmospheric segment को march किया जाता है
-
Compositing
- Sky-view LUT और Aerial Perspective LUT generate करने के बाद, अंतिम post-processing pass में दोनों को combine किया जाता है
- मुख्य काम वर्तमान
rayDirको Sky View UV coordinates में convert करना है - scene geometry पर Aerial Perspective LUT apply किया जाता है, जहाँ alpha channel को view transmittance और RGB channel को scattered light के रूप में उपयोग करके
color = color * aerialPerspective.a + aerialPerspective.rgbcalculate किया जाता है - background pixels के लिए Sky View LUT को sample किया जाता है, और
depth >= 1.0 - 1e-7होने पर उसे background माना जाता है तथाcolor = inputColor.rgb + sampleSkyViewLUT(rayDir, planetCenter)apply किया जाता है - अंत में
ACESFilm(color)औरpow(color, vec3(1.0 / 2.2))apply किए जाते हैं - पूरा LUT-आधारित atmosphere implementation code Github link में देखा जा सकता है
समापन
- LUT-आधारित atmospheric scattering का परिणाम पहले वाले पूर्ण raymarching version जैसा लगभग दिख सकता है, लेकिन इसकी अंदरूनी प्रक्रिया अलग है
- काम को छोटे LUTs में बाँटकर अंतिम effect में composite किया जाता है, और हर sample पर सूर्य की दिशा में बार-बार raymarching करके पहुँचने वाली रोशनी की गणना नहीं की जाती
- क्योंकि lighting information सीधे Transmittance LUT से ली जाती है, इसलिए महंगे nested loop को साधारण texture lookup से बदला जा सकता है, और अंतिम scene में नज़रअंदाज़ न की जा सकने वाली performance improvement मिलती है
- यह implementation Sébastian Hillaire और अन्य क्षेत्रों के implementation की तुलना में सीमित है; खासकर Sky View में banding और flickering है, और संक्षिप्त किए गए हिस्सों की वजह से यह optimal नहीं है
- संभव है कि शुरुआत से WebGPU का उपयोग करना चाहिए था
- वास्तविक production-grade implementation के रूप में Shoda Matsuda(@shotamatsuda) के three-geospatial की सिफारिश की गई है
- इसके अलावा volumetric clouds जोड़ने का काम भी किया गया, लेकिन परिणाम अभी भी mixed bag है, और उसे लेख में दिखाने लायक संतोषजनक बनाने के लिए अभी और काम चाहिए
1 टिप्पणियां
Hacker News की राय
visual effects को विकसित होते और धीरे-धीरे वास्तविक जैसा बनते देखना अपने-आप में खास मजेदार है, और कभी न कभी मैं भी इस क्षेत्र में खुद प्रयोग करना चाहूंगा
पहले उनके वीडियो पर लाखों views आते थे, अब 5 लाख पार करना भी मुश्किल से होता है। हो सकता है COVID के दौरान सब लोग घर पर थे और random चीजों में दिलचस्पी ले रहे थे
मैं आमतौर पर उन्हें सोते समय चला देता हूँ; ऐसा शांत लेकिन गहराई से technical topics में उतरने वाला content और होता तो अच्छा लगता, यहाँ तक कि मैंने खुद ऐसा कुछ बनाने का भी सोचा है
सूर्यास्त के बाद भी कुछ समय तक सिर के ऊपर का atmosphere और क्षितिज के ऊपर का क्षेत्र अब भी सूर्यप्रकाश पाता रहता है, और पृथ्वी के atmosphere में सूरज के क्षितिज से 18 degrees नीचे जाने तक noticeable twilight बना रहता है। ray tracing से इसे लागू करना व्यावहारिक न हो, लेकिन इसे model करने के लिए सामान्य algorithms मौजूद हैं
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 के उस paper को लागू करने की याद है, जो इस विषय का लगभग मूल काम है और काफी आसानी से पढ़ा जा सकता है, Nishita आदि का “Display of The Earth Taking into Account Atmospheric Scattering”: https://www.researchgate.net/publication/2933032_Display_of_...
जब यह काम करने लगा, तब एक ऐसा पल आया कि “इतनी जटिल वास्तविक-world phenomenon को कुछ अपेक्षाकृत सरल calculations से काफी अच्छी तरह model किया जा सकता है।” एक static blue skybox से मैं तुरंत पूरे day-night cycle तक पहुँच गया
मैंने पहले कभी सोचा था कि वेब पर आसमान को कई gradients एक-दूसरे पर चढ़ाकर render करने की कोशिश की जाए। शायद कुछ हद तक सफल होकर ठीक-ठाक नतीजा मिल भी जाता, लेकिन यहाँ जो बनाया गया है उसकी तुलना ही नहीं। परिणाम प्रभावशाली है और प्रेरित करता है
सिर्फ उससे ही काफ़ी भरोसेमंद sunset/sunrise cycle बनता देख मैं हैरान रह गया था, और अगर सही याद है तो सूरज भी किसी तरह उसी से स्वाभाविक रूप से निकलकर आ गया था। मैंने Microsoft के C# game development platform XNA का इस्तेमाल करते हुए Riemer की शानदार tutorial series को follow किया था, और उसका archive यहाँ है https://github.com/SimonDarksideJ/XNAGameStudio/wiki/Riemers...
हालांकि scattering वाला हिस्सा वहाँ दिख नहीं रहा, इसलिए संभव है वह भाग मैंने कहीं और से लिया हो। बस इतना याद है कि मैंने equations वाले papers पढ़े थे
https://spaceengine.org/
“SpaceEngine में कितने objects हैं?” के जवाब में पूरा Hipparcos star catalog, सभी ज्ञात exoplanets, 10 हज़ार से ज़्यादा galaxies, सौरमंडल की अधिकांश वस्तुएँ मिलाकर 1.3 लाख objects बताए जाते हैं। इसके ऊपर observable universe में वास्तव में मौजूद संख्या से भी ज़्यादा galaxies और stellar systems जोड़े जाते हैं। “water planet गर्म कैसे हो सकता है?” के जवाब में कहा गया है कि ऊपरी atmosphere का पानी गर्म water vapor होता है, लेकिन नीचे जाते हुए वह high pressure पर धीरे-धीरे liquid में बदलता है, और उससे भी गहराई में ice VII जैसी solid state बन जाती है। “कैसे move करें?” का जवाब है WASD keys
यह शानदार game है, और काफ़ी पुराना होने के बावजूद अभी तक मुझे इतना अच्छा कुछ और नहीं मिला
यह पोस्ट देखते ही मुझे भी SpaceEngine याद आ गया
मेरे पसंदीदा papers में से एक: http://www.graphics.stanford.edu/papers/bssrdf/bssrdf.pdf
शायद पहली बार मुझे यहीं से पता चला था कि दूध को render करना एक मुश्किल समस्या है
शायद मैं इसका सिर्फ 5% ही समझ पाया, लेकिन फिर भी सचमुच दंग रह गया
और अगर यह MIT license के तहत है, तो मेरे game की skybox समस्या मानो हल हो गई। perspective fixed रहेगा, इसलिए बस सूरज के आसमान में चलने वाला render चाहिए, और इसमें sine-wave period के साथ साल भर के solar angle बदलाव भी जोड़े जा सकते हैं