Performance Atmosphere (#746)

* Testing new improvements.
* Torturing shaders for performance.
* Killing some bits...
* A bit or two were killed in this commit.
This commit is contained in:
Alexander Bock
2018-10-30 17:10:02 -04:00
committed by GitHub
parent 9a44a42f4c
commit cf8d2db914
3 changed files with 121 additions and 89 deletions
@@ -98,8 +98,19 @@ const float M_PI = 3.141592657;
uniform sampler2D transmittanceTexture;
float opticalDepth(const float H, const float r, const float mu, const float d) {
float invH = 1.0/H;
float Rg2 = Rg * Rg;
float Rt2 = Rt * Rt;
float H = sqrt(Rt2 - Rg2);
float H2 = Rt2 - Rg2;
float invSamplesMu = 1.0f / float(SAMPLES_MU);
float invSamplesR = 1.0f / float(SAMPLES_R);
float invSamplesMuS = 1.0f / float(SAMPLES_MU_S);
float invSamplesNu = 1.0f / float(SAMPLES_NU);
float RtMinusRg = float(Rt - Rg);
float invRtMinusRg = 1.0f / RtMinusRg;
float opticalDepth(const float localH, const float r, const float mu, const float d) {
float invH = 1.0/localH;
float a = sqrt((0.5 * invH)*r);
vec2 a01 = a*vec2(mu, mu + d / r);
vec2 a01s = sign(a01);
@@ -121,7 +132,7 @@ vec3 analyticTransmittance(const float r, const float mu, const float d) {
}
vec3 irradiance(sampler2D sampler, const float r, const float muSun) {
float u_r = (r - Rg) / (Rt - Rg);
float u_r = (r - Rg) * invRtMinusRg;
float u_muSun = (muSun + 0.2) / (1.0 + 0.2);
return texture(sampler, vec2(u_muSun, u_r)).rgb;
}
@@ -174,7 +185,7 @@ void unmappingRAndMu(out float r, out float mu) {
// In the paper u_r^2 = (r^2-Rg^2)/(Rt^2-Rg^2)
// So, extracting r from u_r in the above equation:
//r = sqrt( Rg * Rg + (u_r * u_r) * (Rt * Rt - Rg * Rg) );
r = Rg + (u_r * u_r) * (Rt - Rg);
r = Rg + (u_r * u_r) * RtMinusRg;
// In the paper the Bruneton suggest mu = dot(v,x)/||x|| with ||v|| = 1.0
// Later he proposes u_mu = (1-exp(-3mu-0.6))/(1-exp(-3.6))
@@ -191,7 +202,7 @@ void unmappingRAndMuSun(out float r, out float muSun) {
// See Bruneton and Colliene to understand the mapping.
muSun = -0.2f + (gl_FragCoord.x - 0.5f) / (float(OTHER_TEXTURES_W) - 1.0f) * (1.0f + 0.2f);
//r = Rg + (gl_FragCoord.y - 0.5f) / (float(OTHER_TEXTURES_H) - 1.0f) * (Rt - Rg);
r = Rg + (gl_FragCoord.y - 0.5f) / (float(OTHER_TEXTURES_H) ) * (Rt - Rg);
r = Rg + (gl_FragCoord.y - 0.5f) / (float(OTHER_TEXTURES_H) ) * RtMinusRg;
}
//-- Given the windows's fragment coordinates, for a defined view port,
@@ -202,7 +213,7 @@ void unmappingRAndMuSun(out float r, out float muSun) {
void unmappingRAndMuSunIrradiance(out float r, out float muSun) {
// See Bruneton and Colliene to understand the mapping.
muSun = -0.2f + (gl_FragCoord.x - 0.5f) / (float(SKY_W) - 1.0f) * (1.0f + 0.2f);
r = Rg + (gl_FragCoord.y - 0.5f) / (float(SKY_H) - 1.0f) * (Rt - Rg);
r = Rg + (gl_FragCoord.y - 0.5f) / (float(SKY_H) - 1.0f) * RtMinusRg;
}
//-- Given the windows's fragment coordinates, for a defined view port,
@@ -219,8 +230,8 @@ void unmappingMuMuSunNu(const float r, vec4 dhdH, out float mu, out float muSun,
float fragmentY = gl_FragCoord.y - 0.5f;
// Pre-calculations
float Rg2 = Rg * Rg;
float Rt2 = Rt * Rt;
//float Rg2 = Rg * Rg;
//float Rt2 = Rt * Rt;
float r2 = r * r;
float halfSAMPLE_MU = float(SAMPLES_MU) / 2.0f;
@@ -268,7 +279,7 @@ void unmappingMuMuSunNu(const float r, vec4 dhdH, out float mu, out float muSun,
vec3 transmittanceLUT(const float r, const float mu) {
// Given the position x (here the altitude r) and the view
// angle v (here the cosine(v)= mu), we map this
float u_r = sqrt((r - Rg) / (Rt - Rg));
float u_r = sqrt((r - Rg) * invRtMinusRg);
//float u_r = sqrt((r*r - Rg*Rg) / (Rt*Rt - Rg*Rg));
// See Colliene to understand the different mapping.
float u_mu = atan((mu + 0.15f) / (1.0f + 0.15f) * tan(1.5f)) / 1.5f;
@@ -314,7 +325,8 @@ vec3 transmittance(const float r, const float mu, const float d) {
// scattering cosine angle mu --
// mu := cosine of the zeith angle of vec(v). Or mu = (vec(x) * vec(v))/r
float rayleighPhaseFunction(const float mu) {
return (3.0f / (16.0f * M_PI)) * (1.0f + mu * mu);
//return (3.0f / (16.0f * M_PI)) * (1.0f + mu * mu);
return 0.0596831036 * (1.0f + mu * mu);
}
// -- Calculates Mie phase function given the
@@ -325,8 +337,12 @@ float miePhaseFunction(const float mu) {
// ( ( (1.0f - (mieG * mieG) ) * (1.0f + mu * mu) ) /
// ( (2.0f + mieG * mieG) *
// pow(1.0f + mieG * mieG - 2.0f * mieG * mu, 3.0f/2.0f) ) );
return 1.5f * 1.0f / (4.0f * M_PI) * (1.0f - mieG * mieG) *
pow(1.0f + (mieG * mieG) - 2.0f * mieG * mu, -3.0f/2.0f) * (1.0f + mu * mu) / (2.0f + mieG*mieG);
// return 1.5f * 1.0f / (4.0f * M_PI) * (1.0f - mieG * mieG) *
// pow(1.0f + (mieG * mieG) - 2.0f * mieG * mu, -3.0f/2.0f) * (1.0f + mu * mu) / (2.0f + mieG*mieG);
float mieG2 = mieG * mieG;
return 0.1193662072 * (1.0f - mieG2) *
pow(1.0f + mieG2 - 2.0f * mieG * mu, -1.5f) * (1.0f + mu * mu) / (2.0f + mieG2);
}
// -- Given the height rm view-zenith angle (cosine) mu,
@@ -341,25 +357,42 @@ float miePhaseFunction(const float mu) {
vec4 texture4D(sampler3D table, const float r, const float mu,
const float muSun, const float nu)
{
float Rg2 = Rg * Rg;
float Rt2 = Rt * Rt;
//float Rg2 = Rg * Rg;
//float Rt2 = Rt * Rt;
float r2 = r * r;
float H = sqrt(Rt2 - Rg2);
//float H = sqrt(Rt2 - Rg2);
float rho = sqrt(r2 - Rg2);
float rmu = r * mu;
float delta = rmu * rmu - r2 + Rg2;
//float invSamplesMu = 1.0f / float(SAMPLES_MU);
//float invSamplesR = 1.0f / float(SAMPLES_R);
//float invSamplesMuS = 1.0f / float(SAMPLES_MU_S);
//float invSamplesNu = 1.0f / float(SAMPLES_NU);
// vec4 cst = rmu < 0.0f && delta > 0.0f ?
// vec4(1.0f, 0.0f, 0.0f, 0.5f - 0.5f / float(SAMPLES_MU)) :
// vec4(-1.0f, H * H, H, 0.5f + 0.5f / float(SAMPLES_MU));
vec4 cst = rmu < 0.0f && delta > 0.0f ?
vec4(1.0f, 0.0f, 0.0f, 0.5f - 0.5f / float(SAMPLES_MU)) :
vec4(-1.0f, H * H, H, 0.5f + 0.5f / float(SAMPLES_MU));
float u_r = 0.5f / float(SAMPLES_R) + rho / H * (1.0f - 1.0f / float(SAMPLES_R));
float u_mu = cst.w + (rmu * cst.x + sqrt(delta + cst.y)) / (rho + cst.z) * (0.5f - 1.0f / float(SAMPLES_MU));
float u_mu_s = 0.5f / float(SAMPLES_MU_S) +
(atan(max(muSun, -0.1975) * tan(1.26f * 1.1f)) / 1.1f + (1.0f - 0.26f)) * 0.5f * (1.0f - 1.0f / float(SAMPLES_MU_S));
vec4(1.0f, 0.0f, 0.0f, 0.5f - 0.5f * invSamplesMu) :
vec4(-1.0f, H2, H, 0.5f + 0.5f * invSamplesMu);
//float u_r = 0.5f / float(SAMPLES_R) + rho / H * (1.0f - 1.0f / float(SAMPLES_R));
float u_r = 0.5f * invSamplesR + rho / H * (1.0f - invSamplesR);
//float u_mu = cst.w + (rmu * cst.x + sqrt(delta + cst.y)) / (rho + cst.z) * (0.5f - 1.0f / float(SAMPLES_MU));
float u_mu = cst.w + (rmu * cst.x + sqrt(delta + cst.y)) / (rho + cst.z) * (0.5f - invSamplesMu);
// float u_mu_s = 0.5f / float(SAMPLES_MU_S) +
// (atan(max(muSun, -0.1975) * tan(1.26f * 1.1f)) / 1.1f + (1.0f - 0.26f)) * 0.5f * (1.0f - 1.0f / float(SAMPLES_MU_S));
float u_mu_s = 0.5f * invSamplesMuS +
(atan(max(muSun, -0.1975) * tan(1.386f)) * 0.9090909090909090 + (0.74f)) * 0.5f * (1.0f - invSamplesMuS);
float lerp = (nu + 1.0f) / 2.0f * (float(SAMPLES_NU) - 1.0f);
float u_nu = floor(lerp);
lerp = lerp - u_nu;
return texture(table, vec3((u_nu + u_mu_s) / float(SAMPLES_NU), u_mu, u_r)) * (1.0f - lerp) +
texture(table, vec3((u_nu + u_mu_s + 1.0f) / float(SAMPLES_NU), u_mu, u_r)) * lerp;
// return texture(table, vec3((u_nu + u_mu_s) / float(SAMPLES_NU), u_mu, u_r)) * (1.0f - lerp) +
// texture(table, vec3((u_nu + u_mu_s + 1.0f) / float(SAMPLES_NU), u_mu, u_r)) * lerp;
return texture(table, vec3((u_nu + u_mu_s) * invSamplesNu, u_mu, u_r)) * (1.0f - lerp) +
texture(table, vec3((u_nu + u_mu_s + 1.0f) * invSamplesNu, u_mu, u_r)) * lerp;
}
// -- Given the irradiance texture table, the cosine of zenith sun vector
@@ -371,6 +404,6 @@ vec4 texture4D(sampler3D table, const float r, const float mu,
vec3 irradianceLUT(sampler2D lut, const float muSun, const float r) {
// See Bruneton paper and Coliene to understand the mapping
float u_muSun = (muSun + 0.2f) / (1.0f + 0.2f);
float u_r = (r - Rg) / (Rt - Rg);
float u_r = (r - Rg) * invRtMinusRg;
return texture(lut, vec2(u_muSun, u_r)).rgb;
}
@@ -290,7 +290,7 @@ void dCalculateRayRenderableGlobe(in int mssaSample, out dRay ray,
*/
vec3 inscatterRadiance(inout vec3 x, inout float t, inout float irradianceFactor,
const vec3 v, const vec3 s, out float r, out float mu,
out vec3 attenuation, const vec3 fragPosObj,
out vec3 attenuation, const vec3 fragPosObj, out bool groundHit,
const double maxLength, const double pixelDepth,
const vec4 spaceColor, const float sunIntensity) {
@@ -303,8 +303,6 @@ vec3 inscatterRadiance(inout vec3 x, inout float t, inout float irradianceFactor
float mu2 = mu * mu;
float r2 = r * r;
float Rt2 = Rt * Rt;
float Rg2 = Rg * Rg;
float nu = dot(v, s);
float muSun = dot(x, s) / r;
float rayleighPhase = rayleighPhaseFunction(nu);
@@ -326,7 +324,6 @@ vec3 inscatterRadiance(inout vec3 x, inout float t, inout float irradianceFactor
//vec3 x0 = x + float(pixelDepth) * v;
float mu0 = dot(x0, v) * invr0;
bool groundHit = false;
if ((pixelDepth > INTERPOLATION_EPS) && (pixelDepth < maxLength)) {
t = float(pixelDepth);
groundHit = true;
@@ -351,6 +348,7 @@ vec3 inscatterRadiance(inout vec3 x, inout float t, inout float irradianceFactor
} else {
attenuation = analyticTransmittance(r, mu, t);
//attenuation = transmittance(r, mu, t);
groundHit = false;
}
// cos(PI-thetaH) = dist/r
@@ -366,20 +364,25 @@ vec3 inscatterRadiance(inout vec3 x, inout float t, inout float irradianceFactor
// or it has a havey weight if from above or below horizon
float interpolationValue = ((mu - muHorizon) + INTERPOLATION_EPS) / (2.0f * INTERPOLATION_EPS);
float t2 = t * t;
//float t2 = t * t;
// Above Horizon
mu = muHorizon - INTERPOLATION_EPS;
//r0 = sqrt(r * r + t * t + 2.0f * r * t * mu);
// From cosine law where t = distance between x and x0
// r0^2 = r^2 + t^2 - 2 * r * t * cos(PI-theta)
r0 = sqrt(r2 + t2 + 2.0f * r * t * mu);
//r0 = sqrt(r2 + t2 + 2.0f * r * t * mu);
float halfCossineLaw1 = r2 + (t * t);
float halfCossineLaw2 = 2.0f * r * t;
r0 = sqrt(halfCossineLaw1 + halfCossineLaw2 * mu);
float invr0 = 1.0/r0;
// From the dot product: cos(theta0) = (x0 dot v)/(||ro||*||v||)
// mu0 = ((x + t) dot v) / r0
// mu0 = (x dot v + t dot v) / r0
// mu0 = (r*mu + t) / r0
mu0 = (r * mu + t) * invr0;
vec4 inScatterAboveX = texture4D(inscatterTexture, r, mu, muSun, nu);
vec4 inScatterAboveXs = texture4D(inscatterTexture, r0, mu0, muSun0, nu);
// Attention for the attenuation.r value applied to the S_Mie
@@ -387,8 +390,12 @@ vec3 inscatterRadiance(inout vec3 x, inout float t, inout float irradianceFactor
// Below Horizon
mu = muHorizon + INTERPOLATION_EPS;
r0 = sqrt(r2 + t2 + 2.0f * r * t * mu);
//r0 = sqrt(r2 + t2 + 2.0f * r * t * mu);
r0 = sqrt(halfCossineLaw1 + halfCossineLaw2 * mu);
invr0 = 1.0/r0;
mu0 = (r * mu + t) * invr0;
vec4 inScatterBelowX = texture4D(inscatterTexture, r, mu, muSun, nu);
vec4 inScatterBelowXs = texture4D(inscatterTexture, r0, mu0, muSun0, nu);
// Attention for the attenuation.r value applied to the S_Mie
@@ -404,7 +411,7 @@ vec3 inscatterRadiance(inout vec3 x, inout float t, inout float irradianceFactor
// Hermite interpolation between two values
// This step is done because imprecision problems happen when the Sun is slightly below
// the horizon. When this happen, we avoid the Mie scattering contribution.
// the horizon. When this happens, we avoid the Mie scattering contribution.
inscatterRadiance.w *= smoothstep(0.0f, 0.02f, muSun);
vec3 inscatterMie = inscatterRadiance.rgb * inscatterRadiance.a / max(inscatterRadiance.r, 1e-4) *
(betaRayleigh.r / betaRayleigh);
@@ -418,7 +425,7 @@ vec3 inscatterRadiance(inout vec3 x, inout float t, inout float irradianceFactor
if (groundHit) {
return finalScatteringRadiance;
} else {
return ((r-Rg)/(Rt-Rg))*spaceColor.rgb * backgroundConstant + finalScatteringRadiance;
return ((r-Rg) * invRtMinusRg)*spaceColor.rgb * backgroundConstant + finalScatteringRadiance;
}
}
@@ -466,7 +473,7 @@ vec3 groundColor(const vec3 x, const float t, const vec3 v, const vec3 s, const
float muSun = max(dotNS, 0.0f);
// Is direct Sun light arriving at x0? If not, there is no direct light from Sun (shadowed)
vec3 transmittanceL0 = muSun < -sqrt(1.0f - ((Rg * Rg) / (r0 * r0))) ?
vec3 transmittanceL0 = muSun < -sqrt(1.0f - (Rg2 / (r0 * r0))) ?
vec3(0.0f) : transmittanceLUT(r0, muSun);
// E[L*] at x0
vec3 irradianceReflected = irradiance(irradianceTexture, r0, muSun) * irradianceFactor;
@@ -483,10 +490,8 @@ vec3 groundColor(const vec3 x, const float t, const vec3 v, const vec3 s, const
groundRadiance = groundReflectance.rgb * RLStar;
}
//groundRadiance = groundReflectance.rgb * RLStar;
// Specular reflection from sun on oceans and rivers
if ((waterReflectance > 0.1) && /*(dotNS > -0.2f)*/(muSun > 0.0)) {
if ((waterReflectance > 0.1f) && /*(dotNS > -0.2f)*/(muSun > 0.0f)) {
vec3 h = normalize(s - v);
// Fresnell Schlick's approximation
float fresnel = 0.02f + 0.98f * pow(1.0f - dot(-v, h), 5.0f);
@@ -494,7 +499,7 @@ vec3 groundColor(const vec3 x, const float t, const vec3 v, const vec3 s, const
float waterBrdf = fresnel * pow(max(dot(h, n), 0.0f), 150.0f);
// Adding Fresnell and Water BRDFs approximation to the final surface color
// (After adding the sunRadiance and the attenuation of the Sun through atmosphere)
groundRadiance += waterReflectance * max(waterBrdf, 0.0) * transmittanceL0 * sunIntensity;
groundRadiance += waterReflectance * max(waterBrdf, 0.0f) * transmittanceL0 * sunIntensity;
}
//return groundRadiance;
// Finally, we attenuate the surface Radiance from the the point x0 to the camera location.
@@ -523,11 +528,11 @@ vec3 groundColor(const vec3 x, const float t, const vec3 v, const vec3 s, const
*/
vec3 sunColor(const vec3 x, const float t, const vec3 v, const vec3 s, const float r,
const float mu, const float irradianceFactor) {
vec3 transmittance = (r <= Rt) ? ( mu < -sqrt(1.0f - (Rg*Rg)/(r*r)) ?
vec3 transmittance = (r <= Rt) ? ( mu < -sqrt(1.0f - Rg2/(r*r)) ?
vec3(0.0f) : transmittanceLUT(r, mu)) : vec3(1.0f);
// JCC: Change this function to a impostor texture with gaussian decay color weighted
// by tge sunRadiance, transmittance and irradianceColor (11/03/2017)
float sunFinalColor = step(cos(M_PI / 650.0), dot(v, s)) * sunRadiance * (1.0 - irradianceFactor);
float sunFinalColor = step(cos(M_PI / 650.0f), dot(v, s)) * sunRadiance * (1.0f- irradianceFactor);
return transmittance * sunFinalColor;
}
@@ -538,45 +543,30 @@ void main() {
if (cullAtmosphere == 0) {
vec4 atmosphereFinalColor = vec4(0.0f);
int nSamples = 1;
// First we determine if the pixel is complex (different fragments on it)
bool complex = false;
vec4 oldColor, currentColor;
//vec4 colorArray[16];
//int colorIndexArray[16];
oldColor = texelFetch(mainColorTexture, fragCoords, 0);
//colorArray[0] = oldColor;
//colorIndexArray[0] = 0;
for (int i = 1; i < nAaSamples; i++) {
//vec4 normal = texelFetch(mainNormalTexture, fragCoords, i);
vec4 currentColor = texelFetch(mainColorTexture, fragCoords, i);
//colorArray[i] = currentColor;
if (currentColor != oldColor) {
complex = true;
//nSamples = nAaSamples;
nSamples = nAaSamples > 1 ? nAaSamples / 2 : nAaSamples;
break;
// for (int c = 0; c < nAaSamples; c++) {
// if (currentColor == colorArray[c]) {
// colorIndexArray[i] = c;
// break;
// }
// }
}
//else {
// for (int c = 0; c < nAaSamples; c++) {
// if (currentColor == colorArray[c]) {
// colorIndexArray[i] = c;
// break;
// }
// }
// }
oldColor = currentColor;
}
vec4 colorArray[16];
colorArray[0] = texelFetch(mainColorTexture, fragCoords, 0);
for (int i = 1; i < nAaSamples; i++) {
colorArray[i] = texelFetch(mainColorTexture, fragCoords, i);
if (colorArray[i] != colorArray[i-1]) {
complex = true;
}
}
nSamples = complex ? nAaSamples / 2 : 1;
// Performance variables:
//float Rt2 = Rt * Rt; // in Km
//float Rg2 = Rg * Rg; // in Km
for (int i = 0; i < nSamples; i++) {
// Color from G-Buffer
vec4 color = texelFetch(mainColorTexture, fragCoords, i);
//vec4 color = texelFetch(mainColorTexture, fragCoords, i);
vec4 color = colorArray[i];
// Ray in object space
dRay ray;
@@ -594,11 +584,11 @@ void main() {
bool intersectATM = false;
intersectATM = dAtmosphereIntersection(planetPositionObjectCoords.xyz, ray,
Rt - (ATM_EPSILON * 0.001), insideATM, offset, maxLength );
Rt - (ATM_EPSILON * 0.001), insideATM, offset, maxLength);
if ( intersectATM ) {
// Now we check is if the atmosphere is occluded, i.e., if the distance to the pixel
// in the depth buffer is less than the distance to the atmosphere then the atmosphere
// in the G-Buffer positions is less than the distance to the atmosphere then the atmosphere
// is occluded
// Fragments positions into G-Buffer are written in SGCT Eye Space (View plus Camera Rig Coords)
// when using their positions later, one must convert them to the planet's coords
@@ -642,8 +632,8 @@ void main() {
positionObjectsCoords.xyz *= 0.001;
if (position.xyz != vec3(0.0) && (pixelDepth < offset)) {
atmosphereFinalColor += vec4(HDR(color.xyz * backgroundConstant, atmExposure), color.a);
//discard;
// ATM Occluded - Something in fron of ATM.
atmosphereFinalColor += vec4(HDR(color.xyz * backgroundConstant, atmExposure), color.a);
} else {
// Following paper nomenclature
double t = offset;
@@ -660,42 +650,52 @@ void main() {
float tF = float(maxLength - t);
// Because we may move the camera origin to the top of atmosphere
// we also need to adjust the pixelDepth for tdCalculateRayRenderableGlobehis offset so the
// we also need to adjust the pixelDepth for tdCalculateRayRenderableGlobe' offset so the
// next comparison with the planet's ground make sense:
pixelDepth -= offset;
dvec4 onATMPos = dModelTransformMatrix * dvec4(x * 1000.0, 1.0);
vec4 eclipseShadowATM = calcShadow(shadowDataArray, onATMPos.xyz, false);
vec4 eclipseShadowPlanet = calcShadow(shadowDataArray, positionWorldCoords.xyz, true);
float sunIntensityInscatter = sunRadiance * eclipseShadowATM.x;
float sunIntensityGround = sunRadiance * eclipseShadowPlanet.x;
float irradianceFactor = 0.0;
bool groundHit = false;
vec3 inscatterColor = inscatterRadiance(x, tF, irradianceFactor, v,
s, r, mu, attenuation,
vec3(positionObjectsCoords.xyz),
maxLength, pixelDepth,
groundHit, maxLength, pixelDepth,
color, sunIntensityInscatter);
vec3 groundColor = groundColor(x, tF, v, s, r, mu, attenuation,
color, normal.xyz, irradianceFactor,
normal.a, sunIntensityGround);
vec3 sunColor = sunColor(x, tF, v, s, r, mu, irradianceFactor);
vec3 groundColorV = vec3(0.0);
vec3 sunColorV = vec3(0.0);
if (groundHit) {
vec4 eclipseShadowPlanet = calcShadow(shadowDataArray, positionWorldCoords.xyz, true);
float sunIntensityGround = sunRadiance * eclipseShadowPlanet.x;
groundColorV = groundColor(x, tF, v, s, r, mu, attenuation,
color, normal.xyz, irradianceFactor,
normal.a, sunIntensityGround);
} else {
// In order to get better performance, we are not tracing
// multiple rays per pixel when the ray doesn't intersect
// the ground.
sunColorV = sunColor(x, tF, v, s, r, mu, irradianceFactor);
}
// Final Color of ATM plus terrain:
vec4 finalRadiance = vec4(HDR(inscatterColor + groundColor + sunColor, atmExposure), 1.0);
vec4 finalRadiance = vec4(HDR(inscatterColor + groundColorV + sunColorV, atmExposure), 1.0);
atmosphereFinalColor += finalRadiance;
}
}
else { // no intersection
//discard;
atmosphereFinalColor += vec4(HDR(color.xyz * backgroundConstant, atmExposure), color.a);
}
}
renderTarget = atmosphereFinalColor / float(nSamples);
// if (complex)
// renderTarget = vec4(1.0, 0.0, 0.0, 1.0);
}
else { // culling
if (firstPaint) {