vec3 getLunarRadiance(const float moonAngularRadius) { // Not a physical number but the order of 10^-6 relative to the sun may fit. vec3 radiance = u_solar_irradiance * 0.000002 / (PI * moonAngularRadius * moonAngularRadius); #ifdef PHOTOMETRIC radiance *= SUN_SPECTRAL_RADIANCE_TO_LUMINANCE; #endif // PHOTOMETRIC return radiance; } float intersectSphere(const vec3 ray, const vec3 point, const float radius) { vec3 P = -point; float PoR = dot(P, ray); float D = dot(P, P) - radius * radius; return -PoR - sqrt(PoR * PoR - D); } float orenNayarDiffuse(const vec3 L, const vec3 V, const vec3 N) { float NoL = dot(N, L); float NoV = dot(N, V); float s = dot(L, V) - NoL * NoV; float t = mix(1.0, max(NoL, NoV), step(0.0, s)); return max(0.0, NoL) * (0.62406015 + 0.41284404 * s / t); } vec3 getSkyRadiance( const vec3 cameraPosition, const vec3 rayDirection, const float shadowLength, const vec3 sunDirection, const vec3 moonDirection, const float moonAngularRadius, const float lunarRadianceScale ) { vec3 transmittance; vec3 radiance = GetSkyRadiance( cameraPosition, rayDirection, shadowLength, sunDirection, transmittance ); // Rendering celestial objects without perspective doesn't make sense. #ifdef PERSPECTIVE_CAMERA #if defined(SUN) || defined(MOON) vec3 ddx = dFdx(rayDirection); vec3 ddy = dFdy(rayDirection); float fragmentAngle = length(ddx + ddy) / length(rayDirection); #endif // defined(SUN) || defined(MOON) #ifdef SUN float viewDotSun = dot(rayDirection, sunDirection); if (viewDotSun > cos(u_sun_angular_radius)) { float angle = acos(clamp(viewDotSun, -1.0, 1.0)); float antialias = smoothstep(u_sun_angular_radius, u_sun_angular_radius - fragmentAngle, angle); radiance += transmittance * GetSolarRadiance() * antialias; } #endif // SUN #ifdef MOON float intersection = intersectSphere(rayDirection, moonDirection, moonAngularRadius); if (intersection > 0.0) { vec3 normal = normalize(moonDirection - rayDirection * intersection); float diffuse = orenNayarDiffuse(-sunDirection, rayDirection, normal); float viewDotMoon = dot(rayDirection, moonDirection); float angle = acos(clamp(viewDotMoon, -1.0, 1.0)); float antialias = smoothstep(moonAngularRadius, moonAngularRadius - fragmentAngle, angle); radiance += transmittance * getLunarRadiance(moonAngularRadius) * lunarRadianceScale * diffuse * antialias; } #endif // MOON #endif // PERSPECTIVE_CAMERA return radiance; }