mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-04-23 20:50:59 -05:00
744ba0dc9b
* Make atmosphere, raycasting, and trails work with side_by_side stereo
608 lines
25 KiB
GLSL
608 lines
25 KiB
GLSL
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2021 *
|
|
* *
|
|
* 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 "atmosphere_common.glsl"
|
|
|
|
in vec2 texCoord;
|
|
out vec4 renderTarget;
|
|
|
|
uniform int nAaSamples;
|
|
uniform int cullAtmosphere;
|
|
|
|
uniform sampler2D irradianceTexture;
|
|
uniform sampler3D inscatterTexture;
|
|
uniform sampler2D mainPositionTexture;
|
|
uniform sampler2D mainNormalTexture;
|
|
uniform sampler2D mainColorTexture;
|
|
|
|
uniform dmat4 dInverseModelTransformMatrix;
|
|
uniform dmat4 dModelTransformMatrix;
|
|
uniform dmat4 dSGCTViewToWorldMatrix;
|
|
uniform dmat4 dSgctProjectionToModelTransformMatrix;
|
|
|
|
uniform vec4 viewport;
|
|
uniform vec2 resolution;
|
|
|
|
uniform dvec4 dCamPosObj;
|
|
uniform dvec3 sunDirectionObj;
|
|
|
|
/*******************************************************************************
|
|
***** ALL CALCULATIONS FOR ECLIPSE ARE IN METERS AND IN WORLD SPACE SYSTEM ****
|
|
*******************************************************************************/
|
|
// JCC: Remove and use dictionary to decide 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 decide the number of shadows
|
|
uniform ShadowRenderingStruct shadowDataArray[numberOfShadows];
|
|
uniform int shadows;
|
|
uniform bool hardShadows;
|
|
|
|
float calcShadow(ShadowRenderingStruct shadowInfoArray[numberOfShadows], dvec3 position,
|
|
bool ground)
|
|
{
|
|
if (!shadowInfoArray[0].isShadowing) {
|
|
return 1.0;
|
|
}
|
|
|
|
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 (hardShadows) {
|
|
return ground ? 0.2 : 0.5;
|
|
}
|
|
else {
|
|
// butterworth function
|
|
return sqrt(r_u_pi / (r_u_pi + pow(length_d, 4.0)));
|
|
}
|
|
}
|
|
else if (length_d < r_p_pi) {
|
|
// penumbra
|
|
return hardShadows ? 0.5 : length_d / r_p_pi;
|
|
}
|
|
else {
|
|
return 1.0;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
// ALL CALCULATIONS FOR ATMOSPHERE ARE KM AND IN WORLD SPACE SYSTEM //
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
struct Ray {
|
|
dvec3 origin;
|
|
dvec3 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):
|
|
* - ray direction (normalized)
|
|
* - atmosphere radius
|
|
* Out: true if an intersection happens, false otherwise
|
|
* - return: 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 atmosphereIntersection(Ray ray, double atmRadius, out double offset,
|
|
out double maxLength)
|
|
{
|
|
dvec3 l = -ray.origin;
|
|
double s = dot(l, ray.direction);
|
|
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)) {
|
|
offset = 0.0;
|
|
maxLength = 0.0;
|
|
return false;
|
|
}
|
|
|
|
double m2 = l2 - s * s;
|
|
|
|
// Ray misses atmosphere
|
|
if (m2 > r2) {
|
|
offset = 0.0;
|
|
maxLength = 0.0;
|
|
return false;
|
|
}
|
|
|
|
// We already now the ray hits the atmosphere
|
|
|
|
// If q = 0.0, there is only one intersection
|
|
double q = sqrt(r2 - m2);
|
|
|
|
// If l2 < r2, the ray origin is inside the sphere
|
|
if (l2 > r2) {
|
|
offset = s - q;
|
|
maxLength = s + q;
|
|
}
|
|
else {
|
|
offset = 0.0;
|
|
maxLength = s + q;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Calculates Intersection Ray by walking through all the graphic pipeline 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.
|
|
*/
|
|
Ray calculateRayRenderableGlobe(vec2 st) {
|
|
vec2 interpolatedNDCPos = (st - 0.5) * 2.0;
|
|
dvec4 clipCoords = dvec4(interpolatedNDCPos, 1.0, 1.0);
|
|
|
|
// Clip to Object Coords
|
|
dvec4 objectCoords = dSgctProjectionToModelTransformMatrix * clipCoords;
|
|
objectCoords /= objectCoords.w;
|
|
|
|
// Building Ray
|
|
// Ray in object space (in KM)
|
|
Ray ray;
|
|
ray.origin = dvec3(dCamPosObj * dvec4(0.001, 0.001, 0.001, 1.0));
|
|
ray.direction = normalize(objectCoords.xyz * dvec3(0.001) - ray.origin);
|
|
return ray;
|
|
}
|
|
|
|
/*
|
|
* 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(vec3 x, inout float t, out float irradianceFactor, vec3 v, vec3 s,
|
|
out float r, out float mu, out vec3 attenuation, vec3 fragPosObj,
|
|
out bool groundHit, double maxLength, double pixelDepth,
|
|
vec4 spaceColor, float sunIntensity)
|
|
{
|
|
const float INTERPOLATION_EPS = 0.004; // precision const from Brunetton
|
|
|
|
vec3 radiance;
|
|
|
|
r = length(x);
|
|
mu = dot(x, v) / r;
|
|
|
|
float r2 = r * r;
|
|
float nu = dot(v, s);
|
|
float muSun = dot(x, s) / r;
|
|
float rayleighPhase = rayleighPhaseFunction(nu);
|
|
float miePhase = miePhaseFunction(nu, mieG);
|
|
|
|
// 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
|
|
float r0 = length(fragPosObj);
|
|
float invr0 = 1.0 / r0;
|
|
float muSun0 = dot(fragPosObj, s) * invr0;
|
|
float mu0 = dot(fragPosObj, 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);
|
|
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.0 - 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 heavy weight if from above or
|
|
// below horizon
|
|
float interpolationValue = (mu - muHorizon + INTERPOLATION_EPS) / (2.0 * INTERPOLATION_EPS);
|
|
|
|
// 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.0 * r * t;
|
|
r0 = sqrt(halfCossineLaw1 + halfCossineLaw2 * mu);
|
|
|
|
// 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) * (1.0 / r0);
|
|
|
|
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.0);
|
|
|
|
// Below Horizon
|
|
mu = muHorizon + INTERPOLATION_EPS;
|
|
//r0 = sqrt(r2 + t2 + 2.0f * r * t * mu);
|
|
r0 = sqrt(halfCossineLaw1 + halfCossineLaw2 * mu);
|
|
|
|
mu0 = (r * mu + t) * (1.0 / r0);
|
|
|
|
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.0, 0.02, muSun);
|
|
vec3 inscatterMie =
|
|
inscatterRadiance.rgb * inscatterRadiance.a / max(inscatterRadiance.r, 1e-4) *
|
|
(betaRayleigh.r / betaRayleigh);
|
|
|
|
radiance = max(inscatterRadiance.rgb * rayleighPhase + inscatterMie * miePhase, 0.0);
|
|
|
|
// Finally we add the Lsun (all calculations are done with no Lsun so we can change it
|
|
// on the fly with no precomputations)
|
|
vec3 finalScatteringRadiance = radiance * sunIntensity;
|
|
|
|
if (groundHit) {
|
|
return finalScatteringRadiance;
|
|
}
|
|
else {
|
|
return spaceColor.rgb + 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 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)
|
|
* mu := cosine of the zenith view angle
|
|
* attenuationXtoX0 := transmittance T(x,x0)
|
|
*/
|
|
vec3 groundColor(vec3 x, float t, vec3 v, vec3 s, vec3 attenuationXtoX0, vec3 groundColor,
|
|
vec3 normal, float irradianceFactor, float waterReflectance,
|
|
float sunIntensity)
|
|
{
|
|
vec3 reflectedRadiance = vec3(0.0);
|
|
|
|
// First we obtain the ray's end point on the surface
|
|
float r0 = length(x + t * v);
|
|
|
|
vec3 groundReflectance = groundColor * groundRadianceEmission;
|
|
|
|
// 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(normal, s);
|
|
float muSun = max(dotNS, 0.0);
|
|
|
|
// Is direct Sun light arriving at x0? If not, there is no direct light from Sun (shadowed)
|
|
vec3 transmittanceL0 =
|
|
muSun < -sqrt(1.0 - (Rg2 / (r0 * r0))) ? vec3(0.0) : transmittance(r0, muSun);
|
|
|
|
// E[L*] at x0
|
|
vec3 irradianceReflected = irradiance(irradianceTexture, r0, muSun) * irradianceFactor;
|
|
|
|
// R[L0] + R[L*]
|
|
vec3 RLStar = (muSun * transmittanceL0 + irradianceReflected) * sunIntensity / M_PI;
|
|
vec3 groundRadiance =
|
|
dotNS < 0.05 ?
|
|
groundReflectance * mix(30.0, 1.0, smoothstep(-1.0, 0.05, dotNS)) * RLStar :
|
|
groundReflectance * RLStar;
|
|
|
|
// Specular reflection from sun on oceans and rivers
|
|
if ((waterReflectance > 0.1) && (muSun > 0.0)) {
|
|
vec3 h = normalize(s - v);
|
|
// Fresnell Schlick's approximation
|
|
float fresnel = 0.02 + 0.98 * pow(1.0 - dot(-v, h), 5.0);
|
|
// Walter BRDF approximation
|
|
float waterBrdf = fresnel * pow(max(dot(h, normal), 0.0), 150.0);
|
|
// 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;
|
|
}
|
|
|
|
// Finally, we attenuate the surface Radiance from 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 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:
|
|
* 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(vec3 v, vec3 s, float r, float mu, float irradianceFactor) {
|
|
vec3 tm = vec3(1.0);
|
|
if (r <= Rt) {
|
|
tm = mu < -sqrt(1.0 - Rg2 / (r * r)) ? vec3(0.0) : transmittance(r, mu);
|
|
}
|
|
// JCC: Change this function to a impostor texture with gaussian decay color weighted
|
|
// by the sunRadiance, transmittance and irradianceColor (11/03/2017)
|
|
float sunFinalColor = smoothstep(cos(M_PI / 500.0), cos(M_PI / 900.0), dot(v, s)) *
|
|
sunRadiance * (1.0 - irradianceFactor);
|
|
|
|
return tm * sunFinalColor;
|
|
}
|
|
|
|
void main() {
|
|
// Modify the texCoord based on the Viewport and Resolution. This modification is
|
|
// necessary in case of side-by-side stereo as we only want to access the part of the
|
|
// feeding texture that we are currently responsible for. Otherwise we would map the
|
|
// entire feeding texture into our half of the result texture, leading to a doubling
|
|
// of the "missing" half. If you don't believe me, load a configuration file with the
|
|
// side_by_side stereo mode enabled, disable FXAA, and remove this modification.
|
|
// The same calculation is done in the FXAA shader and the HDR resolving
|
|
vec2 st = texCoord;
|
|
st.x = st.x / (resolution.x / viewport[2]) + (viewport[0] / resolution.x);
|
|
st.y = st.y / (resolution.y / viewport[3]) + (viewport[1] / resolution.y);
|
|
|
|
if (cullAtmosphere == 1) {
|
|
renderTarget = texture(mainColorTexture, st);
|
|
return;
|
|
}
|
|
|
|
vec4 atmosphereFinalColor = vec4(0.0);
|
|
int nSamples = 1;
|
|
|
|
// Color from G-Buffer
|
|
vec4 color = texture(mainColorTexture, st);
|
|
|
|
// Get the ray from camera to atm in object space
|
|
Ray ray = calculateRayRenderableGlobe(texCoord);
|
|
|
|
double offset = 0.0; // in KM
|
|
double maxLength = 0.0; // in KM
|
|
bool intersect = atmosphereIntersection(ray, Rt - (ATM_EPSILON * 0.001), offset, maxLength);
|
|
if (!intersect) {
|
|
renderTarget = color;
|
|
return;
|
|
}
|
|
|
|
// 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
|
|
|
|
// Normal is stored in SGCT View Space and transformed to the current object space
|
|
vec4 normalViewSpaceAndWaterReflectance = texture(mainNormalTexture, st);
|
|
dvec4 normalViewSpace = vec4(normalViewSpaceAndWaterReflectance.xyz, 0.0);
|
|
dvec4 normalWorldSpace = dSGCTViewToWorldMatrix * normalViewSpace;
|
|
vec4 normal = vec4(dInverseModelTransformMatrix * normalWorldSpace);
|
|
normal.xyz = normalize(normal.xyz);
|
|
normal.w = normalViewSpaceAndWaterReflectance.w;
|
|
|
|
// Data in the mainPositionTexture are written in view space (view plus camera rig)
|
|
vec4 position = texture(mainPositionTexture, st);
|
|
|
|
// 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(dCamPosObj.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(dCamPosObj.xyz));
|
|
const float x1 = 1e8;
|
|
if (dC > x1) {
|
|
pixelDepth += 1000.0;
|
|
const float alpha = 1000.0;
|
|
const float beta = 1000000.0;
|
|
const float x2 = 1e9;
|
|
const float diffGreek = beta - alpha;
|
|
const float diffDist = x2 - x1;
|
|
const float varA = diffGreek / diffDist;
|
|
const float varB = (alpha - varA * x1);
|
|
pixelDepth += double(varA * dC + varB);
|
|
}
|
|
|
|
// All calculations are done in KM:
|
|
pixelDepth *= 0.001;
|
|
positionObjectsCoords.xyz *= 0.001;
|
|
|
|
if (pixelDepth < offset) {
|
|
// ATM Occluded - Something in front of ATM
|
|
renderTarget = color;
|
|
return;
|
|
}
|
|
|
|
// 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 + t * ray.direction);
|
|
float r = 0.0; // length(x);
|
|
vec3 v = vec3(ray.direction);
|
|
float mu = 0.0; // 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;
|
|
|
|
dvec3 onATMPos = (dModelTransformMatrix * dvec4(x * 1000.0, 1.0)).xyz;
|
|
float eclipseShadowATM = calcShadow(shadowDataArray, onATMPos, false);
|
|
float sunIntensityInscatter = sunRadiance * eclipseShadowATM;
|
|
|
|
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 atmColor = vec3(0.0);
|
|
if (groundHit) {
|
|
float eclipseShadowPlanet = calcShadow(shadowDataArray, positionWorldCoords.xyz, true);
|
|
float sunIntensityGround = sunRadiance * eclipseShadowPlanet;
|
|
atmColor = groundColor(x, tF, v, s, attenuation, color.rgb, normal.xyz,
|
|
irradianceFactor, normal.w, sunIntensityGround);
|
|
}
|
|
else {
|
|
// In order to get better performance, we are not tracing multiple rays per pixel
|
|
// when the ray doesn't intersect the ground
|
|
atmColor = sunColor(v, s, r, mu, irradianceFactor);
|
|
}
|
|
|
|
// Final Color of ATM plus terrain:
|
|
vec4 finalRadiance = vec4(inscatterColor + atmColor, 1.0);
|
|
renderTarget = finalRadiance;
|
|
}
|