156 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			156 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| 
								 | 
							
								/* Various sky functions
							 | 
						||
| 
								 | 
							
								 * =====================
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Nishita model is based on https://github.com/wwwtyro/glsl-atmosphere (Unlicense License)
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 *   Changes to the original implementation:
							 | 
						||
| 
								 | 
							
								 *     - r and pSun parameters of nishita_atmosphere() are already normalized
							 | 
						||
| 
								 | 
							
								 *     - Some original parameters of nishita_atmosphere() are replaced with pre-defined values
							 | 
						||
| 
								 | 
							
								 *     - Implemented air, dust and ozone density node parameters (see Blender source)
							 | 
						||
| 
								 | 
							
								 *     - Replaced the inner integral calculation with a LUT lookup
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Reference for the sun's limb darkening and ozone calculations:
							 | 
						||
| 
								 | 
							
								 * [Hill] Sebastien Hillaire. Physically Based Sky, Atmosphere and Cloud Rendering in Frostbite
							 | 
						||
| 
								 | 
							
								 * (https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/s2016-pbs-frostbite-sky-clouds-new.pdf)
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * Cycles code used for reference: blender/intern/sky/source/sky_nishita.cpp
							 | 
						||
| 
								 | 
							
								 * (https://github.com/blender/blender/blob/4429b4b77ef6754739a3c2b4fabd0537999e9bdc/intern/sky/source/sky_nishita.cpp)
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef _SKY_GLSL_
							 | 
						||
| 
								 | 
							
								#define _SKY_GLSL_
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "std/math.glsl"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uniform sampler2D nishitaLUT;
							 | 
						||
| 
								 | 
							
								uniform vec2 nishitaDensity;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef PI
							 | 
						||
| 
								 | 
							
									#define PI 3.141592
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								#ifndef HALF_PI
							 | 
						||
| 
								 | 
							
									#define HALF_PI 1.570796
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define nishita_iSteps 16
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// These values are taken from Cycles code if they
							 | 
						||
| 
								 | 
							
								// exist there, otherwise they are taken from the example
							 | 
						||
| 
								 | 
							
								// in the glsl-atmosphere repo
							 | 
						||
| 
								 | 
							
								#define nishita_sun_intensity 22.0
							 | 
						||
| 
								 | 
							
								#define nishita_atmo_radius 6420e3
							 | 
						||
| 
								 | 
							
								#define nishita_rayleigh_scale 8e3
							 | 
						||
| 
								 | 
							
								#define nishita_rayleigh_coeff vec3(5.5e-6, 13.0e-6, 22.4e-6)
							 | 
						||
| 
								 | 
							
								#define nishita_mie_scale 1.2e3
							 | 
						||
| 
								 | 
							
								#define nishita_mie_coeff 2e-5
							 | 
						||
| 
								 | 
							
								#define nishita_mie_dir 0.76 // Aerosols anisotropy ("direction")
							 | 
						||
| 
								 | 
							
								#define nishita_mie_dir_sq 0.5776 // Squared aerosols anisotropy
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Values from [Hill: 60]
							 | 
						||
| 
								 | 
							
								#define sun_limb_darkening_col vec3(0.397, 0.503, 0.652)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								vec3 nishita_lookupLUT(const float height, const float sunTheta) {
							 | 
						||
| 
								 | 
							
									vec2 coords = vec2(
							 | 
						||
| 
								 | 
							
										sqrt(height * (1 / nishita_atmo_radius)),
							 | 
						||
| 
								 | 
							
										0.5 + 0.5 * sign(sunTheta - HALF_PI) * sqrt(abs(sunTheta * (1 / HALF_PI) - 1))
							 | 
						||
| 
								 | 
							
									);
							 | 
						||
| 
								 | 
							
									return textureLod(nishitaLUT, coords, 0.0).rgb;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* See raySphereIntersection() in leenkx/Sources/renderpath/Nishita.hx */
							 | 
						||
| 
								 | 
							
								vec2 nishita_rsi(const vec3 r0, const vec3 rd, const float sr) {
							 | 
						||
| 
								 | 
							
									float a = dot(rd, rd);
							 | 
						||
| 
								 | 
							
									float b = 2.0 * dot(rd, r0);
							 | 
						||
| 
								 | 
							
									float c = dot(r0, r0) - (sr * sr);
							 | 
						||
| 
								 | 
							
									float d = (b*b) - 4.0*a*c;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// If d < 0.0 the ray does not intersect the sphere
							 | 
						||
| 
								 | 
							
									return (d < 0.0) ? vec2(1e5,-1e5) : vec2((-b - sqrt(d))/(2.0*a), (-b + sqrt(d))/(2.0*a));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								 * r: normalized ray direction
							 | 
						||
| 
								 | 
							
								 * r0: ray origin
							 | 
						||
| 
								 | 
							
								 * pSun: normalized sun direction
							 | 
						||
| 
								 | 
							
								 * rPlanet: planet radius
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								vec3 nishita_atmosphere(const vec3 r, const vec3 r0, const vec3 pSun, const float rPlanet) {
							 | 
						||
| 
								 | 
							
									// Calculate the step size of the primary ray
							 | 
						||
| 
								 | 
							
									vec2 p = nishita_rsi(r0, r, nishita_atmo_radius);
							 | 
						||
| 
								 | 
							
									if (p.x > p.y) return vec3(0.0);
							 | 
						||
| 
								 | 
							
									p.y = min(p.y, nishita_rsi(r0, r, rPlanet).x);
							 | 
						||
| 
								 | 
							
									float iStepSize = (p.y - p.x) / float(nishita_iSteps);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Primary ray time
							 | 
						||
| 
								 | 
							
									float iTime = 0.0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Accumulators for Rayleigh and Mie scattering.
							 | 
						||
| 
								 | 
							
									vec3 totalRlh = vec3(0,0,0);
							 | 
						||
| 
								 | 
							
									vec3 totalMie = vec3(0,0,0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Optical depth accumulators for the primary ray
							 | 
						||
| 
								 | 
							
									float iOdRlh = 0.0;
							 | 
						||
| 
								 | 
							
									float iOdMie = 0.0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Calculate the Rayleigh and Mie phases
							 | 
						||
| 
								 | 
							
									float mu = dot(r, pSun);
							 | 
						||
| 
								 | 
							
									float mumu = mu * mu;
							 | 
						||
| 
								 | 
							
									float pRlh = 3.0 / (16.0 * PI) * (1.0 + mumu);
							 | 
						||
| 
								 | 
							
									float pMie = 3.0 / (8.0 * PI) * ((1.0 - nishita_mie_dir_sq) * (mumu + 1.0)) / (pow(1.0 + nishita_mie_dir_sq - 2.0 * mu * nishita_mie_dir, 1.5) * (2.0 + nishita_mie_dir_sq));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Sample the primary ray
							 | 
						||
| 
								 | 
							
									for (int i = 0; i < nishita_iSteps; i++) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Calculate the primary ray sample position and height
							 | 
						||
| 
								 | 
							
										vec3 iPos = r0 + r * (iTime + iStepSize * 0.5);
							 | 
						||
| 
								 | 
							
										float iHeight = length(iPos) - rPlanet;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Calculate the optical depth of the Rayleigh and Mie scattering for this step
							 | 
						||
| 
								 | 
							
										float odStepRlh = exp(-iHeight / nishita_rayleigh_scale) * nishitaDensity.x * iStepSize;
							 | 
						||
| 
								 | 
							
										float odStepMie = exp(-iHeight / nishita_mie_scale) * nishitaDensity.y * iStepSize;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Accumulate optical depth
							 | 
						||
| 
								 | 
							
										iOdRlh += odStepRlh;
							 | 
						||
| 
								 | 
							
										iOdMie += odStepMie;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Idea behind this: "Rotate" everything by iPos (-> iPos is the new zenith) and then all calculations for the
							 | 
						||
| 
								 | 
							
										// inner integral only depend on the sample height (iHeight) and sunTheta (angle between sun and new zenith).
							 | 
						||
| 
								 | 
							
										float sunTheta = safe_acos(dot(normalize(iPos), normalize(pSun)));
							 | 
						||
| 
								 | 
							
										vec3 jAttn = nishita_lookupLUT(iHeight, sunTheta);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Calculate attenuation
							 | 
						||
| 
								 | 
							
										vec3 iAttn = exp(-(
							 | 
						||
| 
								 | 
							
											nishita_mie_coeff * iOdMie
							 | 
						||
| 
								 | 
							
											+ nishita_rayleigh_coeff * iOdRlh
							 | 
						||
| 
								 | 
							
											// + 0 for ozone
							 | 
						||
| 
								 | 
							
										));
							 | 
						||
| 
								 | 
							
										vec3 attn = iAttn * jAttn;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Apply dithering to reduce visible banding
							 | 
						||
| 
								 | 
							
										attn *= 0.98 + rand(r.xy) * 0.04;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Accumulate scattering
							 | 
						||
| 
								 | 
							
										totalRlh += odStepRlh * attn;
							 | 
						||
| 
								 | 
							
										totalMie += odStepMie * attn;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										iTime += iStepSize;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return nishita_sun_intensity * (pRlh * nishita_rayleigh_coeff * totalRlh + pMie * nishita_mie_coeff * totalMie);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								vec3 sun_disk(const vec3 n, const vec3 light_dir, const float disk_size, const float intensity) {
							 | 
						||
| 
								 | 
							
									// Normalized SDF
							 | 
						||
| 
								 | 
							
									float dist = distance(n, light_dir) / disk_size;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Darken the edges of the sun
							 | 
						||
| 
								 | 
							
									// [Hill: 28, 60] (according to [Nec96])
							 | 
						||
| 
								 | 
							
									float invDist = 1.0 - dist;
							 | 
						||
| 
								 | 
							
									float mu = sqrt(invDist * invDist);
							 | 
						||
| 
								 | 
							
									vec3 limb_darkening = 1.0 - (1.0 - pow(vec3(mu), sun_limb_darkening_col));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return 1 + (1.0 - step(1.0, dist)) * nishita_sun_intensity * intensity * limb_darkening;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 |