paysages3d/src/experiments/bruneton/earth.glsl

233 lines
9.1 KiB
GLSL

/**
* Precomputed Atmospheric Scattering
* Copyright (c) 2008 INRIA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Author: Eric Bruneton
*/
#define FIX
const float ISun = 100.0;
uniform vec3 c;
uniform vec3 s;
uniform mat4 projInverse;
uniform mat4 viewInverse;
uniform float exposure;
uniform sampler2D reflectanceSampler;//ground reflectance texture
uniform sampler2D irradianceSampler;//precomputed skylight irradiance (E table)
uniform sampler3D inscatterSampler;//precomputed inscattered light (S table)
uniform sampler2D debug2DSampler;
uniform sampler3D debug3DSampler;
varying vec2 coords;
varying vec3 ray;
#ifdef _VERTEX_
void main() {
coords = gl_Vertex.xy * 0.5 + 0.5;
ray = (viewInverse * vec4((projInverse * gl_Vertex).xyz, 0.0)).xyz;
gl_Position = gl_Vertex;
}
#else
//inscattered light along ray x+tv, when sun in direction s (=S[L]-T(x,x0)S[L]|x0)
vec3 inscatter(inout vec3 x, inout float t, vec3 v, vec3 s, out float r, out float mu, out vec3 attenuation) {
vec3 result;
r = length(x);
mu = dot(x, v) / r;
float d = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rt * Rt);
if (d > 0.0) { // if x in space and ray intersects atmosphere
// move x to nearest intersection of ray with top atmosphere boundary
x += d * v;
t -= d;
mu = (r * mu + d) / Rt;
r = Rt;
}
if (r <= Rt) { // if ray intersects atmosphere
float nu = dot(v, s);
float muS = dot(x, s) / r;
float phaseR = phaseFunctionR(nu);
float phaseM = phaseFunctionM(nu);
vec4 inscatter = max(texture4D(inscatterSampler, r, mu, muS, nu), 0.0);
if (t > 0.0) {
vec3 x0 = x + t * v;
float r0 = length(x0);
float rMu0 = dot(x0, v);
float mu0 = rMu0 / r0;
float muS0 = dot(x0, s) / r0;
#ifdef FIX
// avoids imprecision problems in transmittance computations based on textures
attenuation = analyticTransmittance(r, mu, t);
#else
attenuation = transmittance(r, mu, v, x0);
#endif
if (r0 > Rg + 0.01) {
// computes S[L]-T(x,x0)S[L]|x0
inscatter = max(inscatter - attenuation.rgbr * texture4D(inscatterSampler, r0, mu0, muS0, nu), 0.0);
#ifdef FIX
// avoids imprecision problems near horizon by interpolating between two points above and below horizon
const float EPS = 0.004;
float muHoriz = -sqrt(1.0 - (Rg / r) * (Rg / r));
if (abs(mu - muHoriz) < EPS) {
float a = ((mu - muHoriz) + EPS) / (2.0 * EPS);
mu = muHoriz - EPS;
r0 = sqrt(r * r + t * t + 2.0 * r * t * mu);
mu0 = (r * mu + t) / r0;
vec4 inScatter0 = texture4D(inscatterSampler, r, mu, muS, nu);
vec4 inScatter1 = texture4D(inscatterSampler, r0, mu0, muS0, nu);
vec4 inScatterA = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0);
mu = muHoriz + EPS;
r0 = sqrt(r * r + t * t + 2.0 * r * t * mu);
mu0 = (r * mu + t) / r0;
inScatter0 = texture4D(inscatterSampler, r, mu, muS, nu);
inScatter1 = texture4D(inscatterSampler, r0, mu0, muS0, nu);
vec4 inScatterB = max(inScatter0 - attenuation.rgbr * inScatter1, 0.0);
inscatter = mix(inScatterA, inScatterB, a);
}
#endif
}
}
#ifdef FIX
// avoids imprecision problems in Mie scattering when sun is below horizon
inscatter.w *= smoothstep(0.00, 0.02, muS);
#endif
result = max(inscatter.rgb * phaseR + getMie(inscatter) * phaseM, 0.0);
} else { // x in space and ray looking in space
result = vec3(0.0);
}
return result * ISun;
}
//ground radiance at end of ray x+tv, when sun in direction s
//attenuated bewteen ground and viewer (=R[L0]+R[L*])
vec3 groundColor(vec3 x, float t, vec3 v, vec3 s, float r, float mu, vec3 attenuation)
{
vec3 result;
if (t > 0.0) { // if ray hits ground surface
// ground reflectance at end of ray, x0
vec3 x0 = x + t * v;
float r0 = length(x0);
vec3 n = x0 / r0;
vec2 coords = vec2(atan(n.y, n.x), acos(n.z)) * vec2(0.5, 1.0) / M_PI + vec2(0.5, 0.0);
vec4 reflectance = texture2D(reflectanceSampler, coords) * vec4(0.2, 0.2, 0.2, 1.0);
if (r0 > Rg + 0.01) {
reflectance = vec4(0.4, 0.4, 0.4, 0.0);
}
// direct sun light (radiance) reaching x0
float muS = dot(n, s);
vec3 sunLight = transmittanceWithShadow(r0, muS);
// precomputed sky light (irradiance) (=E[L*]) at x0
vec3 groundSkyLight = irradiance(irradianceSampler, r0, muS);
// light reflected at x0 (=(R[L0]+R[L*])/T(x,x0))
vec3 groundColor = reflectance.rgb * (max(muS, 0.0) * sunLight + groundSkyLight) * ISun / M_PI;
// water specular color due to sunLight
if (reflectance.w > 0.0) {
vec3 h = normalize(s - v);
float fresnel = 0.02 + 0.98 * pow(1.0 - dot(-v, h), 5.0);
float waterBrdf = fresnel * pow(max(dot(h, n), 0.0), 150.0);
groundColor += reflectance.w * max(waterBrdf, 0.0) * sunLight * ISun;
}
result = attenuation * groundColor; //=R[L0]+R[L*]
} else { // ray looking at the sky
result = vec3(0.0);
}
return result;
}
// direct sun light for ray x+tv, when sun in direction s (=L0)
vec3 sunColor(vec3 x, float t, vec3 v, vec3 s, float r, float mu) {
if (t > 0.0) {
return vec3(0.0);
} else {
vec3 transmittance = r <= Rt ? transmittanceWithShadow(r, mu) : vec3(1.0); // T(x,xo)
float isun = step(cos(M_PI / 180.0), dot(v, s)) * ISun; // Lsun
return transmittance * isun; // Eq (9)
}
}
vec3 HDR(vec3 L) {
L = L * exposure;
L.r = L.r < 1.413 ? pow(L.r * 0.38317, 1.0 / 2.2) : 1.0 - exp(-L.r);
L.g = L.g < 1.413 ? pow(L.g * 0.38317, 1.0 / 2.2) : 1.0 - exp(-L.g);
L.b = L.b < 1.413 ? pow(L.b * 0.38317, 1.0 / 2.2) : 1.0 - exp(-L.b);
return L;
}
void main() {
vec3 x = c;
vec3 v = normalize(ray);
float r = length(x);
float mu = dot(x, v) / r;
float t = -r * mu - sqrt(r * r * (mu * mu - 1.0) + Rg * Rg);
vec3 g = x - vec3(0.0, 0.0, Rg + 10.0);
float a = v.x * v.x + v.y * v.y - v.z * v.z;
float b = 2.0 * (g.x * v.x + g.y * v.y - g.z * v.z);
float c = g.x * g.x + g.y * g.y - g.z * g.z;
float d = -(b + sqrt(b * b - 4.0 * a * c)) / (2.0 * a);
bool cone = d > 0.0 && abs(x.z + d * v.z - Rg) <= 10.0;
if (t > 0.0) {
if (cone && d < t) {
t = d;
}
} else if (cone) {
t = d;
}
vec3 attenuation;
vec3 inscatterColor = inscatter(x, t, v, s, r, mu, attenuation); //S[L]-T(x,xs)S[l]|xs
vec3 groundColor = groundColor(x, t, v, s, r, mu, attenuation); //R[L0]+R[L*]
vec3 sunColor = sunColor(x, t, v, s, r, mu); //L0
gl_FragColor = vec4(HDR(sunColor + groundColor + inscatterColor), 1.0); // Eq (16)
//gl_FragColor = texture3D(inscatterSampler,vec3(coords,(s.x+1.0)/2.0));
//gl_FragColor = vec4(texture2D(irradianceSampler,coords).rgb*5.0, 1.0);
//gl_FragColor = texture2D(transmittanceSampler,coords);
//gl_FragColor = vec4(texture2D(debug2DSampler,coords).rgb * 1.0, 1.0);
//gl_FragColor = texture3D(debug3DSampler,vec3(coords,0.5))*1000.0;
}
#endif