mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-03 01:09:34 -05:00
cf8d2db914
* Testing new improvements. * Torturing shaders for performance. * Killing some bits... * A bit or two were killed in this commit.
717 lines
32 KiB
GLSL
717 lines
32 KiB
GLSL
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2018 *
|
|
* *
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
|
* software and associated documentation files (the "Software"), to deal in the Software *
|
|
* without restriction, including without limitation the rights to use, copy, modify, *
|
|
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
|
* permit persons to whom the Software is furnished to do so, subject to the following *
|
|
* conditions: *
|
|
* *
|
|
* The above copyright notice and this permission notice shall be included in all copies *
|
|
* or substantial portions of the Software. *
|
|
* *
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
|
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
|
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
|
****************************************************************************************/
|
|
|
|
/*****************************************************************************************
|
|
* Modified parts of the code (4D texture mechanism) from Eric Bruneton is used in the *
|
|
* following code. *
|
|
****************************************************************************************/
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
|
|
#version __CONTEXT__
|
|
|
|
#include "floatoperations.glsl"
|
|
|
|
#include "hdr.glsl"
|
|
#include "atmosphere_common.glsl"
|
|
|
|
out vec4 renderTarget;
|
|
in vec3 interpolatedNDCPos;
|
|
|
|
uniform int nAaSamples;
|
|
uniform double msaaSamplePatter[48];
|
|
uniform int cullAtmosphere;
|
|
|
|
// The following uniforms are
|
|
// set into the current Renderer
|
|
// Background exposure hack
|
|
uniform float backgroundConstant;
|
|
uniform bool firstPaint;
|
|
uniform float atmExposure;
|
|
|
|
uniform sampler2D irradianceTexture;
|
|
uniform sampler3D inscatterTexture;
|
|
uniform sampler2DMS mainPositionTexture;
|
|
uniform sampler2DMS mainNormalTexture;
|
|
uniform sampler2DMS mainColorTexture;
|
|
|
|
uniform dmat4 dInverseModelTransformMatrix;
|
|
uniform dmat4 dModelTransformMatrix;
|
|
uniform dmat4 dSGCTViewToWorldMatrix;
|
|
uniform dmat4 dSgctProjectionToModelTransformMatrix;
|
|
|
|
uniform dvec4 dCamPosObj;
|
|
uniform dvec3 sunDirectionObj;
|
|
|
|
/*******************************************************************************
|
|
***** ALL CALCULATIONS FOR ECLIPSE ARE IN METERS AND IN WORLD SPACE SYSTEM ****
|
|
*******************************************************************************/
|
|
// JCC: Remove and use dictionary to
|
|
// decides the number of shadows
|
|
const uint numberOfShadows = 1;
|
|
|
|
struct ShadowRenderingStruct {
|
|
double xu, xp;
|
|
double rs, rc;
|
|
dvec3 sourceCasterVec;
|
|
dvec3 casterPositionVec;
|
|
bool isShadowing;
|
|
};
|
|
|
|
// Eclipse shadow data
|
|
// JCC: Remove and use dictionary to
|
|
// decides the number of shadows
|
|
uniform ShadowRenderingStruct shadowDataArray[numberOfShadows];
|
|
uniform int shadows;
|
|
uniform bool hardShadows;
|
|
|
|
vec4 butterworthFunc(const float d, const float r, const float n) {
|
|
return vec4(vec3(sqrt(r/(r + pow(d, 2*n)))), 1.0);
|
|
}
|
|
|
|
vec4 calcShadow(const ShadowRenderingStruct shadowInfoArray[numberOfShadows], const dvec3 position,
|
|
const bool ground) {
|
|
if (shadowInfoArray[0].isShadowing) {
|
|
dvec3 pc = shadowInfoArray[0].casterPositionVec - position;
|
|
dvec3 sc_norm = shadowInfoArray[0].sourceCasterVec;
|
|
dvec3 pc_proj = dot(pc, sc_norm) * sc_norm;
|
|
dvec3 d = pc - pc_proj;
|
|
|
|
float length_d = float(length(d));
|
|
double length_pc_proj = length(pc_proj);
|
|
|
|
float r_p_pi = float(shadowInfoArray[0].rc * (length_pc_proj + shadowInfoArray[0].xp) / shadowInfoArray[0].xp);
|
|
float r_u_pi = float(shadowInfoArray[0].rc * (shadowInfoArray[0].xu - length_pc_proj) / shadowInfoArray[0].xu);
|
|
|
|
if ( length_d < r_u_pi ) { // umbra
|
|
if (ground) {
|
|
if (hardShadows) {
|
|
return vec4(0.2, 0.2, 0.2, 1.0);
|
|
} else {
|
|
return butterworthFunc(length_d, r_u_pi, 4.0);
|
|
}
|
|
}
|
|
else {
|
|
if (hardShadows) {
|
|
return vec4(0.5, 0.5, 0.5, 1.0);
|
|
} else {
|
|
return vec4(vec3(length_d/r_p_pi), 1.0);
|
|
}
|
|
}
|
|
}
|
|
else if ( length_d < r_p_pi ) {// penumbra
|
|
if (hardShadows) {
|
|
return vec4(0.5, 0.5, 0.5, 1.0);
|
|
} else {
|
|
return vec4(vec3(length_d/r_p_pi), 1.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
return vec4(1.0);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
******* ALL CALCULATIONS FOR ATMOSPHERE ARE KM AND IN WORLD SPACE SYSTEM ******
|
|
*******************************************************************************/
|
|
|
|
struct dRay {
|
|
dvec4 origin;
|
|
dvec4 direction;
|
|
};
|
|
|
|
/* Function to calculate the initial intersection of the eye (camera) ray
|
|
* with the atmosphere.
|
|
* In (all parameters in the same coordinate system and same units):
|
|
* - planet position
|
|
* - ray direction (normalized)
|
|
* - eye position
|
|
* - atmosphere radius
|
|
* Out: true if an intersection happens, false otherwise
|
|
* - inside: true if the ray origin is inside atmosphere, false otherwise
|
|
* - offset: the initial intersection distance from eye position when
|
|
* the eye is outside the atmosphere
|
|
* - maxLength : the second intersection distance from eye position when the
|
|
* eye is outside the atmosphere or the initial (and only)
|
|
* intersection of the ray with atmosphere when the eye position
|
|
* is inside atmosphere.
|
|
*/
|
|
bool dAtmosphereIntersection(const dvec3 planetPosition, const dRay ray, const double atmRadius,
|
|
out bool inside, out double offset, out double maxLength ) {
|
|
dvec3 l = planetPosition - ray.origin.xyz;
|
|
double s = dot(l, ray.direction.xyz);
|
|
double l2 = dot(l, l);
|
|
double r2 = atmRadius * atmRadius; // avoiding surface acne
|
|
|
|
// Ray origin (eye position) is behind sphere
|
|
if ((s < 0.0) && (l2 > r2)) {
|
|
inside = false;
|
|
offset = 0.0;
|
|
maxLength = 0.0;
|
|
return false;
|
|
}
|
|
|
|
double m2 = l2 - s*s;
|
|
|
|
// Ray misses atmospere
|
|
if (m2 > r2) {
|
|
inside = false;
|
|
offset = 0.0;
|
|
maxLength = 0.0;
|
|
return false;
|
|
}
|
|
|
|
// We already now the ray hits the atmosphere
|
|
|
|
// If q = 0.0f, there is only one intersection
|
|
double q = sqrt(r2 - m2);
|
|
|
|
// If l2 < r2, the ray origin is inside the sphere
|
|
if (l2 > r2) {
|
|
inside = false;
|
|
offset = s - q;
|
|
maxLength = s + q;
|
|
} else {
|
|
inside = true;
|
|
offset = 0.0;
|
|
maxLength = s + q;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Calculates Intersection Ray by walking through
|
|
* all the graphic pipile transformations in the
|
|
* opposite direction.
|
|
* Instead of passing through all the pipeline,
|
|
* it starts at NDC from the interpolated
|
|
* positions from the screen quad.
|
|
* This method avoids matrices multiplications
|
|
* wherever is possible.
|
|
*/
|
|
void dCalculateRayRenderableGlobe(in int mssaSample, out dRay ray,
|
|
out dvec4 planetPositionObjectCoords,
|
|
out dvec4 cameraPositionInObject) {
|
|
// ======================================
|
|
// ======= Avoiding Some Matrices =======
|
|
|
|
// Compute positions and directions in object space.
|
|
dvec2 samplePos = dvec2(msaaSamplePatter[mssaSample],
|
|
msaaSamplePatter[mssaSample+1]);
|
|
//dvec4 clipCoords = dvec4(interpolatedNDCPos.xy + samplePos, 0.0, 1.0);
|
|
dvec4 clipCoords = dvec4(interpolatedNDCPos.xy, 0.0, 1.0);
|
|
|
|
// Clip to Object Coords
|
|
dvec4 objectCoords = dSgctProjectionToModelTransformMatrix * clipCoords;
|
|
|
|
// Planet Position in Object Space
|
|
// JCC: Applying the inverse of the model transformation on the object postion in World
|
|
// space results in imprecision.
|
|
planetPositionObjectCoords = dvec4(0.0, 0.0, 0.0, 1.0);
|
|
|
|
// Camera Position in Object Space (in meters)
|
|
cameraPositionInObject = dCamPosObj;
|
|
|
|
// ============================
|
|
// ====== Building Ray ========
|
|
// Ray in object space (in KM)
|
|
ray.origin = cameraPositionInObject * dvec4(0.001, 0.001, 0.001, 1.0);
|
|
//ray.direction = dvec4(normalize(objectCoords.xyz - cameraPositionInObject.xyz), 0.0);
|
|
ray.direction = dvec4(normalize((objectCoords.xyz * dvec3(0.001))- ray.origin.xyz), 0.0);
|
|
}
|
|
|
|
/*
|
|
* Calculates the light scattering in the view direction comming from other
|
|
* light rays scattered in the atmosphere.
|
|
* Following the paper: S[L]|x - T(x,xs) * S[L]|xs
|
|
* The view direction here is the ray: x + tv, s is the sun direction,
|
|
* r and mu the position and zenith cosine angle as in the paper.
|
|
* Arguments:
|
|
* x := camera position
|
|
* t := ray displacement variable after calculating the intersection with the
|
|
* atmosphere. It is the distance from the camera to the last intersection with
|
|
* the atmosphere. If the ray hits the ground, t is updated to the correct value
|
|
* v := view direction (ray's direction) (normalized)
|
|
* s := Sun direction (normalized)
|
|
* r := out of ||x|| inside atmosphere (or top of atmosphere)
|
|
* mu := out of cosine of the zenith view angle
|
|
* attenuation := out of transmittance T(x,x0). This will be used later when
|
|
* calculating the reflectance R[L].
|
|
*/
|
|
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 bool groundHit,
|
|
const double maxLength, const double pixelDepth,
|
|
const vec4 spaceColor, const float sunIntensity) {
|
|
|
|
const float INTERPOLATION_EPS = 0.004f; // precision const from Brunetton
|
|
|
|
vec3 radiance;
|
|
|
|
r = length(x);
|
|
mu = dot(x, v) / r;
|
|
|
|
float mu2 = mu * mu;
|
|
float r2 = r * r;
|
|
float nu = dot(v, s);
|
|
float muSun = dot(x, s) / r;
|
|
float rayleighPhase = rayleighPhaseFunction(nu);
|
|
float miePhase = miePhaseFunction(nu);
|
|
|
|
// S[L](x,s,v)
|
|
// I.e. the next line has the scattering light for the "infinite" ray passing
|
|
// through the atmosphere. If this ray hits something inside the atmosphere,
|
|
// we will subtract the attenuated scattering light from that path in the
|
|
// current path.
|
|
vec4 inscatterRadiance = max(texture4D(inscatterTexture, r, mu, muSun, nu), 0.0);
|
|
|
|
// After removing the initial path from camera pos to top of atmosphere (for an
|
|
// observer in the space) we test if the light ray is hitting the atmosphere
|
|
vec3 x0 = fragPosObj;
|
|
float r0 = length(fragPosObj);
|
|
float invr0 = 1.0/r0;
|
|
float muSun0 = dot(fragPosObj, s) * invr0;
|
|
//vec3 x0 = x + float(pixelDepth) * v;
|
|
float mu0 = dot(x0, v) * invr0;
|
|
|
|
if ((pixelDepth > INTERPOLATION_EPS) && (pixelDepth < maxLength)) {
|
|
t = float(pixelDepth);
|
|
groundHit = true;
|
|
|
|
// Transmittance from point r, direction mu, distance t
|
|
// By Analytical calculation
|
|
//attenuation = analyticTransmittance(r, mu, t);
|
|
// JCC: change from analytical to LUT transmittance to avoid
|
|
// acme on planet surface when looking from far away. (11/02/2017)
|
|
attenuation = transmittance(r, mu, t);
|
|
|
|
// Here we use the idea of S[L](a->b) = S[L](b->a), and get the S[L](x0, v, s)
|
|
// Then we calculate S[L] = S[L]|x - T(x, x0)*S[L]|x0
|
|
// The "infinite" ray hist something inside the atmosphere, so we need to remove
|
|
// the unsused contribution to the final radiance.
|
|
vec4 inscatterFromSurface = texture4D(inscatterTexture, r0, mu0, muSun0, nu);
|
|
inscatterRadiance = max(inscatterRadiance - attenuation.rgbr * inscatterFromSurface, 0.0);
|
|
|
|
// We set the irradianceFactor to 1.0 so the reflected irradiance will be considered
|
|
// when calculating the reflected light on the ground.
|
|
irradianceFactor = 1.0;
|
|
} else {
|
|
attenuation = analyticTransmittance(r, mu, t);
|
|
//attenuation = transmittance(r, mu, t);
|
|
groundHit = false;
|
|
}
|
|
|
|
// cos(PI-thetaH) = dist/r
|
|
// cos(thetaH) = - dist/r
|
|
// muHorizon = -sqrt(r^2-Rg^2)/r = -sqrt(1-(Rg/r)^2)
|
|
float muHorizon = -sqrt(1.0f - (Rg2 / r2));
|
|
|
|
// In order to avoid imprecision problems near horizon,
|
|
// we interpolate between two points: above and below horizon
|
|
if (abs(mu - muHorizon) < INTERPOLATION_EPS) {
|
|
// We want an interpolation value close to 1/2, so the
|
|
// contribution of each radiance value is almost the same
|
|
// 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;
|
|
|
|
// 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);
|
|
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
|
|
vec4 inScatterAbove = max(inScatterAboveX - attenuation.rgbr * inScatterAboveXs, 0.0f);
|
|
|
|
// Below Horizon
|
|
mu = muHorizon + INTERPOLATION_EPS;
|
|
//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
|
|
vec4 inScatterBelow = max(inScatterBelowX - attenuation.rgbr * inScatterBelowXs, 0.0);
|
|
|
|
// Interpolate between above and below inScattering radiance
|
|
inscatterRadiance = mix(inScatterAbove, inScatterBelow, interpolationValue);
|
|
}
|
|
|
|
// The w component of inscatterRadiance has stored the Cm,r value (Cm = Sm[L0])
|
|
// So, we must reintroduce the Mie inscatter by the proximity rule as described in the
|
|
// paper by Bruneton and Neyret in "Angular precision" paragraph:
|
|
|
|
// Hermite interpolation between two values
|
|
// This step is done because imprecision problems happen when the Sun is slightly below
|
|
// 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);
|
|
|
|
radiance = max(inscatterRadiance.rgb * rayleighPhase + inscatterMie * miePhase, 0.0f);
|
|
|
|
// Finally we add the Lsun (all calculations are done with no Lsun so
|
|
// we can change it on the fly with no precomputations)
|
|
// return radiance * sunRadiance;
|
|
vec3 finalScatteringRadiance = radiance * sunIntensity;
|
|
if (groundHit) {
|
|
return finalScatteringRadiance;
|
|
} else {
|
|
return ((r-Rg) * invRtMinusRg)*spaceColor.rgb * backgroundConstant + finalScatteringRadiance;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Calculates the light reflected in the view direction comming from other
|
|
* light rays integrated over the hemispehre plus the direct light (L0) from Sun.
|
|
* Following the paper: R[L]= R[L0]+R[L*]
|
|
* The the ray is x + tv, v the view direction, s is the sun direction,
|
|
* r and mu the position and zenith cosine angle as in the paper.
|
|
* As for all calculations in the atmosphere, the center of the coordinate system
|
|
* is the planet's center of coordiante system, i.e., the planet's position is (0,0,0).
|
|
* Arguments:
|
|
* x := camera position
|
|
* t := ray displacement variable. Here, differently from the inScatter light calculation,
|
|
* the position of the camera is already offset (on top of atmosphere) or inside
|
|
* the atmosphere.
|
|
* v := view direction (ray's direction) (normalized)
|
|
* s := Sun direction (normalized)
|
|
* r := ||x|| inside atmosphere (or top of atmosphere). r <= Rt here.
|
|
* mu := cosine of the zenith view angle
|
|
* attenuationXtoX0 := transmittance T(x,x0)
|
|
*/
|
|
vec3 groundColor(const vec3 x, const float t, const vec3 v, const vec3 s, const float r,
|
|
const float mu, const vec3 attenuationXtoX0, const vec4 groundColor,
|
|
const vec3 normal, const float irradianceFactor,
|
|
const float waterReflectance, const float sunIntensity)
|
|
{
|
|
vec3 reflectedRadiance = vec3(0.0f);
|
|
|
|
// First we obtain the ray's end point on the surface
|
|
vec3 x0 = x + t * v;
|
|
float r0 = length(x0);
|
|
// Normal of intersection point.
|
|
// Normal must be normalized.
|
|
vec3 n = normal;
|
|
//vec4 groundReflectance = groundColor * vec4(.37);
|
|
vec4 groundReflectance = groundColor *
|
|
vec4(groundRadianceEmittion, groundRadianceEmittion, groundRadianceEmittion, 1.0f);
|
|
|
|
// L0 is not included in the irradiance texture.
|
|
// We first calculate the light attenuation from the top of the atmosphere
|
|
// to x0.
|
|
float dotNS = dot(n, s);
|
|
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 - (Rg2 / (r0 * r0))) ?
|
|
vec3(0.0f) : transmittanceLUT(r0, muSun);
|
|
// E[L*] at x0
|
|
vec3 irradianceReflected = irradiance(irradianceTexture, r0, muSun) * irradianceFactor;
|
|
|
|
// R[L0] + R[L*]
|
|
// vec3 groundRadiance = (dotNS < -0.2f ? groundReflectance.rgb * 15 : groundReflectance.rgb) *
|
|
// (muSun * transmittanceL0 + irradianceReflected) * sunIntensity / M_PI;
|
|
|
|
vec3 groundRadiance;
|
|
vec3 RLStar = (muSun * transmittanceL0 + irradianceReflected) * sunIntensity / M_PI;
|
|
if (dotNS < 0.05f) {
|
|
groundRadiance = groundReflectance.rgb * mix(30.0f, 1.0f, smoothstep(-1.0f, 0.05f, dotNS)) * RLStar;
|
|
} else {
|
|
groundRadiance = groundReflectance.rgb * RLStar;
|
|
}
|
|
|
|
// Specular reflection from sun on oceans and rivers
|
|
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);
|
|
// Walter BRDF approximation
|
|
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.0f) * transmittanceL0 * sunIntensity;
|
|
}
|
|
//return groundRadiance;
|
|
// Finally, we attenuate the surface Radiance from the the point x0 to the camera location.
|
|
reflectedRadiance = attenuationXtoX0 * groundRadiance;
|
|
|
|
// Returns reflectedRadiance = 0.0 if the ray doesn't hit the ground.
|
|
return reflectedRadiance;
|
|
}
|
|
|
|
/*
|
|
* Calculates the Sun color.
|
|
* The the ray is x + tv, v the view direction, s is the sun direction,
|
|
* r and mu the position and zenith cosine angle as in the paper.
|
|
* As for all calculations in the atmosphere, the center of the coordinate system
|
|
* is the planet's center of coordiante system, i.e., the planet's position is (0,0,0).
|
|
* Arguments:
|
|
* x := camera position
|
|
* t := ray displacement variable. Here, differently from the inScatter light calculation,
|
|
* the position of the camera is already offset (on top of atmosphere) or inside
|
|
* the atmosphere.
|
|
* v := view direction (ray's direction) (normalized)
|
|
* s := Sun direction (normalized)
|
|
* r := ||x|| inside atmosphere (or top of atmosphere). r <= Rt here.
|
|
* mu := cosine of the zenith view angle
|
|
* attenuation := transmittance T(x,x0)
|
|
*/
|
|
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 - 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.0f), dot(v, s)) * sunRadiance * (1.0f- irradianceFactor);
|
|
|
|
return transmittance * sunFinalColor;
|
|
}
|
|
|
|
void main() {
|
|
ivec2 fragCoords = ivec2(gl_FragCoord);
|
|
|
|
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];
|
|
|
|
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 = colorArray[i];
|
|
|
|
// Ray in object space
|
|
dRay ray;
|
|
dvec4 planetPositionObjectCoords = dvec4(0.0);
|
|
dvec4 cameraPositionInObject = dvec4(0.0);
|
|
|
|
// Get the ray from camera to atm in object space
|
|
dCalculateRayRenderableGlobe(i * 3, ray, planetPositionObjectCoords,
|
|
cameraPositionInObject);
|
|
|
|
bool insideATM = false;
|
|
double offset = 0.0; // in Km
|
|
double maxLength = 0.0; // in Km
|
|
|
|
bool intersectATM = false;
|
|
|
|
intersectATM = dAtmosphereIntersection(planetPositionObjectCoords.xyz, ray,
|
|
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 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
|
|
|
|
// Get data from G-Buffer
|
|
vec4 normal = texelFetch(mainNormalTexture, fragCoords, i);
|
|
// Data in the mainPositionTexture are written in view space (view plus camera rig)
|
|
vec4 position = texelFetch(mainPositionTexture, fragCoords, i);
|
|
|
|
// OS Eye to World coords
|
|
dvec4 positionWorldCoords = dSGCTViewToWorldMatrix * position;
|
|
|
|
// World to Object (Normal and Position in meters)
|
|
dvec4 positionObjectsCoords = dInverseModelTransformMatrix * positionWorldCoords;
|
|
|
|
|
|
// Distance of the pixel in the gBuffer to the observer
|
|
// JCC (12/12/2017): AMD distance function is buggy.
|
|
//double pixelDepth = distance(cameraPositionInObject.xyz, positionObjectsCoords.xyz);
|
|
double pixelDepth = length(cameraPositionInObject.xyz - positionObjectsCoords.xyz);
|
|
|
|
// JCC (12/13/2017): Trick to remove floating error in texture.
|
|
// We see a squared noise on planet's surface when seeing the planet
|
|
// from far away.
|
|
float dC = float(length(cameraPositionInObject.xyz));
|
|
float x1 = 1e8;
|
|
if (dC > x1) {
|
|
pixelDepth += 1000.0;
|
|
float alpha = 1000.0;
|
|
float beta = 1000000.0;
|
|
float x2 = 1e9;
|
|
float diffGreek = beta - alpha;
|
|
float diffDist = x2 - x1;
|
|
float varA = diffGreek/diffDist;
|
|
float varB = (alpha - varA * x1);
|
|
pixelDepth += double(varA * dC + varB);
|
|
}
|
|
|
|
// All calculations are done in Km:
|
|
pixelDepth *= 0.001;
|
|
positionObjectsCoords.xyz *= 0.001;
|
|
|
|
if (position.xyz != vec3(0.0) && (pixelDepth < offset)) {
|
|
// ATM Occluded - Something in fron of ATM.
|
|
atmosphereFinalColor += vec4(HDR(color.xyz * backgroundConstant, atmExposure), color.a);
|
|
} else {
|
|
// Following paper nomenclature
|
|
double t = offset;
|
|
vec3 attenuation;
|
|
|
|
// Moving observer from camera location to top atmosphere
|
|
// If the observer is already inside the atm, offset = 0.0
|
|
// and no changes at all.
|
|
vec3 x = vec3(ray.origin.xyz + t*ray.direction.xyz);
|
|
float r = 0.0f;//length(x);
|
|
vec3 v = vec3(ray.direction.xyz);
|
|
float mu = 0.0f;//dot(x, v) / r;
|
|
vec3 s = vec3(sunDirectionObj);
|
|
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 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);
|
|
float sunIntensityInscatter = sunRadiance * eclipseShadowATM.x;
|
|
|
|
float irradianceFactor = 0.0;
|
|
|
|
bool groundHit = false;
|
|
vec3 inscatterColor = inscatterRadiance(x, tF, irradianceFactor, v,
|
|
s, r, mu, attenuation,
|
|
vec3(positionObjectsCoords.xyz),
|
|
groundHit, maxLength, pixelDepth,
|
|
color, sunIntensityInscatter);
|
|
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 + groundColorV + sunColorV, atmExposure), 1.0);
|
|
|
|
atmosphereFinalColor += finalRadiance;
|
|
}
|
|
}
|
|
else { // no intersection
|
|
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) {
|
|
vec4 bColor = vec4(0.0f);
|
|
for (int f = 0; f < nAaSamples; f++) {
|
|
bColor += texelFetch(mainColorTexture, fragCoords, f);
|
|
}
|
|
bColor /= float(nAaSamples);
|
|
renderTarget = vec4(HDR(bColor.xyz * backgroundConstant, atmExposure), bColor.a);
|
|
}
|
|
else {
|
|
discard;
|
|
}
|
|
//renderTarget = vec4(1.0, 0.0, 0.0, 1.0);
|
|
|
|
}
|
|
}
|
|
|