Feature/intel atmosphere (#1691)

* Add object names to atmosphere textures
* Fix for rendering atmospheres on Intel chips
* General cleanup of the atmosphere rendering code to make a it more modular
This commit is contained in:
Alexander Bock
2021-07-22 20:42:21 +02:00
committed by GitHub
parent ae339823e8
commit e994e900ee
21 changed files with 1124 additions and 1442 deletions

View File

@@ -42,7 +42,6 @@ local Atmosphere = {
G = 0.85
},
Debug = {
-- PreCalculatedTextureScale is a float from 1.0 to N, with N > 0.0 and N in Naturals (i.e., 1, 2, 3, 4, 5....)
PreCalculatedTextureScale = 1.0,
SaveCalculatedTextures = false
}

View File

@@ -42,7 +42,6 @@ local Atmosphere = {
G = 0.85
},
Debug = {
-- PreCalculatedTextureScale is a float from 1.0 to N, with N > 0.0 and N in Naturals (i.e., 1, 2, 3, 4, 5....)
PreCalculatedTextureScale = 1.0,
SaveCalculatedTextures = false
}

View File

@@ -51,8 +51,6 @@ public:
const DeferredcastData& /*deferredData*/,
ghoul::opengl::ProgramObject& /*program*/) {};
virtual std::filesystem::path deferredcastPath() const = 0;
virtual std::filesystem::path deferredcastVSPath() const = 0;
virtual std::filesystem::path deferredcastFSPath() const = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -57,16 +57,17 @@ struct ShadowRenderingStruct {
class AtmosphereDeferredcaster : public Deferredcaster {
public:
AtmosphereDeferredcaster(float textureScale,
std::vector<ShadowConfiguration> shadowConfigArray, bool saveCalculatedTextures);
virtual ~AtmosphereDeferredcaster() = default;
void initialize();
void deinitialize();
void preRaycast(const RenderData& renderData, const DeferredcastData& deferredData,
void preRaycast(const RenderData& data, const DeferredcastData& deferredData,
ghoul::opengl::ProgramObject& program) override;
void postRaycast(const RenderData& renderData, const DeferredcastData& deferredData,
void postRaycast(const RenderData& data, const DeferredcastData& deferredData,
ghoul::opengl::ProgramObject& program) override;
std::filesystem::path deferredcastPath() const override;
std::filesystem::path deferredcastVSPath() const override;
std::filesystem::path deferredcastFSPath() const override;
std::filesystem::path helperPath() const override;
@@ -75,82 +76,64 @@ public:
void update(const UpdateData&) override;
void preCalculateAtmosphereParam();
void calculateAtmosphereParameters();
void setModelTransform(glm::dmat4 transform);
void setTime(double time);
void setAtmosphereRadius(float atmRadius);
void setPlanetRadius(float planetRadius);
void setPlanetAverageGroundReflectance(float averageGReflectance);
void setPlanetGroundRadianceEmission(float groundRadianceEmission);
void setRayleighHeightScale(float rayleighHeightScale);
void enableOzone(bool enable);
void setOzoneHeightScale(float ozoneHeightScale);
void setMieHeightScale(float mieHeightScale);
void setMiePhaseConstant(float miePhaseConstant);
void setSunRadianceIntensity(float sunRadiance);
void setRayleighScatteringCoefficients(glm::vec3 rayScattCoeff);
void setOzoneExtinctionCoefficients(glm::vec3 ozoneExtCoeff);
void setMieScatteringCoefficients(glm::vec3 mieScattCoeff);
void setMieExtinctionCoefficients(glm::vec3 mieExtCoeff);
void setEllipsoidRadii(glm::dvec3 radii);
void setShadowConfigArray(std::vector<ShadowConfiguration> shadowConfigArray);
void setHardShadows(bool enabled);
void enableSunFollowing(bool enable);
void setPrecalculationTextureScale(float preCalculatedTexturesScale);
void enablePrecalculationTexturesSaving();
void setParameters(float atmosphereRadius, float planetRadius,
float averageGroundReflectance, float groundRadianceEmission,
float rayleighHeightScale, bool enableOzone, float ozoneHeightScale,
float mieHeightScale, float miePhaseConstant, float sunRadiance,
glm::vec3 rayScatteringCoefficients, glm::vec3 ozoneExtinctionCoefficients,
glm::vec3 mieScatteringCoefficients, glm::vec3 mieExtinctionCoefficients,
bool sunFollowing);
void setHardShadows(bool enabled);
private:
void loadComputationPrograms();
void unloadComputationPrograms();
void createComputationTextures();
void deleteComputationTextures();
void deleteUnusedComputationTextures();
void executeCalculations(GLuint quadCalcVAO, GLenum drawBuffers[1],
GLsizei vertexSize);
void step3DTexture(ghoul::opengl::ProgramObject& shaderProg, int layer,
bool doCalculation);
void loadAtmosphereDataIntoShaderProgram(ghoul::opengl::ProgramObject& shaderProg);
void step3DTexture(ghoul::opengl::ProgramObject& prg, int layer);
void calculateTransmittance(GLuint vao);
GLuint calculateDeltaE(GLuint vao);
std::pair<GLuint, GLuint> calculateDeltaS(GLuint vao);
void calculateIrradiance(GLuint vao);
void calculateInscattering(GLuint vao, GLuint deltaSRayleigh, GLuint deltaSMie);
void calculateDeltaJ(GLuint vao, int scatteringOrder,
ghoul::opengl::ProgramObject& program, GLuint deltaJ, GLuint deltaE,
GLuint deltaSRayleigh, GLuint deltaSMie);
void calculateDeltaE(GLuint vao, int scatteringOrder,
ghoul::opengl::ProgramObject& program, GLuint deltaE, GLuint deltaSRayleigh,
GLuint deltaSMie);
void calculateDeltaS(GLuint vao, int scatteringOrder,
ghoul::opengl::ProgramObject& program, GLuint deltaSRayleigh, GLuint deltaJ);
void calculateIrradiance(GLuint vao, int scatteringOrder,
ghoul::opengl::ProgramObject& program, GLuint deltaE);
void calculateInscattering(GLuint vao, int scatteringOrder,
ghoul::opengl::ProgramObject& program, GLuint deltaSRayleigh);
std::unique_ptr<ghoul::opengl::ProgramObject> _transmittanceProgramObject;
std::unique_ptr<ghoul::opengl::ProgramObject> _irradianceProgramObject;
std::unique_ptr<ghoul::opengl::ProgramObject> _irradianceSupTermsProgramObject;
std::unique_ptr<ghoul::opengl::ProgramObject> _irradianceFinalProgramObject;
std::unique_ptr<ghoul::opengl::ProgramObject> _inScatteringProgramObject;
std::unique_ptr<ghoul::opengl::ProgramObject> _inScatteringSupTermsProgramObject;
std::unique_ptr<ghoul::opengl::ProgramObject> _deltaEProgramObject;
std::unique_ptr<ghoul::opengl::ProgramObject> _deltaSProgramObject;
std::unique_ptr<ghoul::opengl::ProgramObject> _deltaSSupTermsProgramObject;
std::unique_ptr<ghoul::opengl::ProgramObject> _deltaJProgramObject;
UniformCache(cullAtmosphere, Rg, Rt, groundRadianceEmission, HR, betaRayleigh, HM,
betaMieExtinction, mieG, sunRadiance, ozoneLayerEnabled, HO, betaOzoneExtinction,
SAMPLES_R, SAMPLES_MU, SAMPLES_MU_S, SAMPLES_NU, inverseModelTransformMatrix,
modelTransformMatrix, projectionToModelTransformMatrix,
viewToWorldMatrix, camPosObj, sunDirectionObj, hardShadows,
transmittanceTexture, irradianceTexture, inscatterTexture) _uniformCache;
GLuint _transmittanceTableTexture = 0;
GLuint _irradianceTableTexture = 0;
GLuint _inScatteringTableTexture = 0;
GLuint _deltaETableTexture = 0;
GLuint _deltaSRayleighTableTexture = 0;
GLuint _deltaSMieTableTexture = 0;
GLuint _deltaJTableTexture = 0;
modelTransformMatrix, projectionToModelTransform, viewToWorldMatrix,
camPosObj, sunDirectionObj, hardShadows, transmittanceTexture, irradianceTexture,
inscatterTexture) _uniformCache;
ghoul::opengl::TextureUnit _transmittanceTableTextureUnit;
ghoul::opengl::TextureUnit _irradianceTableTextureUnit;
ghoul::opengl::TextureUnit _inScatteringTableTextureUnit;
GLuint _transmittanceTableTexture = 0;
GLuint _irradianceTableTexture = 0;
GLuint _inScatteringTableTexture = 0;
// Atmosphere Data
bool _atmosphereCalculated = false;
bool _ozoneEnabled = false;
bool _sunFollowingCameraEnabled = false;
float _atmosphereRadius = 0.f;
float _atmospherePlanetRadius = 0.f;
float _planetAverageGroundReflectance = 0.f;
float _planetGroundRadianceEmission = 0.f;
float _averageGroundReflectance = 0.f;
float _groundRadianceEmission = 0.f;
float _rayleighHeightScale = 0.f;
float _ozoneHeightScale = 0.f;
float _mieHeightScale = 0.f;
@@ -161,34 +144,33 @@ private:
glm::vec3 _ozoneExtinctionCoeff = glm::vec3(0.f);
glm::vec3 _mieScatteringCoeff = glm::vec3(0.f);
glm::vec3 _mieExtinctionCoeff = glm::vec3(0.f);
glm::dvec3 _ellipsoidRadii = glm::dvec3(0.0);
// Atmosphere Textures Dimmensions
glm::ivec2 _transmittanceTableSize = glm::ivec2(256, 64);
glm::ivec2 _irradianceTableSize = glm::ivec2(64, 16);
glm::ivec2 _deltaETableSize = glm::ivec2(64, 16);
int _r_samples = 32;
int _mu_samples = 128;
int _mu_s_samples = 32;
int _nu_samples = 8;
const glm::ivec2 _transmittanceTableSize;
const glm::ivec2 _irradianceTableSize;
const glm::ivec2 _deltaETableSize;
const int _muSSamples;
const int _nuSamples;
const int _muSamples;
const int _rSamples;
const glm::ivec3 _textureSize;
glm::dmat4 _modelTransform;
double _time = 0.0;
// Eclipse Shadows
std::vector<ShadowConfiguration> _shadowConfArray;
std::vector<ShadowRenderingStruct> _shadowDataArrayCache;
bool _hardShadowsEnabled = false;
// Atmosphere Debugging
bool _saveCalculationTextures = false;
const bool _saveCalculationTextures = false;
std::vector<ShadowRenderingStruct> _shadowDataArrayCache;
// Assuming < 1000 shadow casters, the longest uniform name that we are getting is
// shadowDataArray[999].casterPositionVec
// which needs to fit into the uniform buffer
char _uniformNameBuffer[40];
};
} // openspace
} // namespace openspace
#endif // __OPENSPACE_MODULE_ATMOSPHERE___ATMOSPHEREDEFERREDCASTER___H__

View File

@@ -244,7 +244,7 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary)
MieScatteringCoeffInfo,
glm::vec3(0.004f), glm::vec3(0.00001f), glm::vec3(1.f)
)
, _mieScatteringExtinctionPropCoefficient(
, _mieScatteringExtinctionPropCoeff(
MieScatteringExtinctionPropCoeffInfo,
0.9f, 0.01f, 1.f
)
@@ -328,16 +328,15 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary)
_miePhaseConstant.onChange(updateWithCalculation);
addProperty(_miePhaseConstant);
_mieScatteringExtinctionPropCoefficient =
_mieScatteringExtinctionPropCoeff =
_mieScattExtPropCoefProp != 1.f ? _mieScattExtPropCoefProp :
_mieScatteringCoeff.value().x / _mieExtinctionCoeff.x;
_mieScatteringExtinctionPropCoefficient.onChange(updateWithCalculation);
addProperty(_mieScatteringExtinctionPropCoefficient);
_mieScatteringExtinctionPropCoeff.onChange(updateWithCalculation);
addProperty(_mieScatteringExtinctionPropCoeff);
if (p.debug.has_value()) {
_preCalculatedTexturesScale =
p.debug->preCalculatedTextureScale.value_or(_preCalculatedTexturesScale);
_textureScale = p.debug->preCalculatedTextureScale.value_or(_textureScale);
_saveCalculationsToTexture =
p.debug->saveCalculatedTextures.value_or(_saveCalculationsToTexture);
@@ -364,15 +363,13 @@ void RenderableAtmosphere::deinitializeGL() {
}
void RenderableAtmosphere::initializeGL() {
_deferredcaster = std::make_unique<AtmosphereDeferredcaster>();
_deferredcaster = std::make_unique<AtmosphereDeferredcaster>(
_textureScale,
_shadowEnabled ? std::move(_shadowConfArray) : std::vector<ShadowConfiguration>(),
_saveCalculationsToTexture
);
_shadowConfArray.clear();
updateAtmosphereParameters();
if (_shadowEnabled) {
_deferredcaster->setShadowConfigArray(_shadowConfArray);
// We no longer need it
_shadowConfArray.clear();
}
_deferredcaster->initialize();
global::deferredcasterManager->attachDeferredcaster(*_deferredcaster);
@@ -382,13 +379,11 @@ bool RenderableAtmosphere::isReady() const {
return true;
}
glm::dmat4 RenderableAtmosphere::computeModelTransformMatrix(
const TransformData& transformData)
{
glm::dmat4 RenderableAtmosphere::computeModelTransformMatrix(const TransformData& data) {
// scale the planet to appropriate size since the planet is a unit sphere
return glm::translate(glm::dmat4(1.0), transformData.translation) *
glm::dmat4(transformData.rotation) *
glm::scale(glm::dmat4(1.0), glm::dvec3(transformData.scale));
return glm::translate(glm::dmat4(1.0), data.translation) *
glm::dmat4(data.rotation) *
glm::scale(glm::dmat4(1.0), glm::dvec3(data.scale));
}
void RenderableAtmosphere::render(const RenderData& data, RendererTasks& renderTask) {
@@ -404,11 +399,10 @@ void RenderableAtmosphere::update(const UpdateData& data) {
_deferredCasterNeedsUpdate = false;
}
if (_deferredCasterNeedsCalculation) {
_deferredcaster->preCalculateAtmosphereParam();
_deferredcaster->calculateAtmosphereParameters();
_deferredCasterNeedsCalculation = false;
}
_deferredcaster->setTime(data.time.j2000Seconds());
glm::dmat4 modelTransform = computeModelTransformMatrix(data.modelTransform);
_deferredcaster->setModelTransform(modelTransform);
_deferredcaster->update(data);
@@ -416,34 +410,26 @@ void RenderableAtmosphere::update(const UpdateData& data) {
void RenderableAtmosphere::updateAtmosphereParameters() {
_mieExtinctionCoeff =
_mieScatteringCoeff.value() / _mieScatteringExtinctionPropCoefficient.value();
_mieScatteringCoeff.value() / _mieScatteringExtinctionPropCoeff.value();
_deferredcaster->setAtmosphereRadius(_planetRadius + _atmosphereHeight);
_deferredcaster->setPlanetRadius(_planetRadius);
_deferredcaster->setPlanetAverageGroundReflectance(_groundAverageReflectance);
_deferredcaster->setPlanetGroundRadianceEmission(_groundRadianceEmission);
_deferredcaster->setRayleighHeightScale(_rayleighHeightScale);
_deferredcaster->enableOzone(_ozoneEnabled);
_deferredcaster->setOzoneHeightScale(_ozoneHeightScale);
_deferredcaster->setMieHeightScale(_mieHeightScale);
_deferredcaster->setMiePhaseConstant(_miePhaseConstant);
_deferredcaster->setSunRadianceIntensity(_sunIntensity);
_deferredcaster->setRayleighScatteringCoefficients(_rayleighScatteringCoeff);
_deferredcaster->setOzoneExtinctionCoefficients(_ozoneCoeff);
_deferredcaster->setMieScatteringCoefficients(_mieScatteringCoeff);
_deferredcaster->setMieExtinctionCoefficients(_mieExtinctionCoeff);
_deferredcaster->enableSunFollowing(_sunFollowingCameraEnabled);
// TODO: Fix the ellipsoid nature of the renderable globe (JCC)
//_deferredcaster->setEllipsoidRadii(_ellipsoid.radii());
_deferredcaster->setPrecalculationTextureScale(_preCalculatedTexturesScale);
if (_saveCalculationsToTexture) {
_deferredcaster->enablePrecalculationTexturesSaving();
}
if (_shadowEnabled) {
_deferredcaster->setHardShadows(_hardShadowsEnabled);
}
_deferredcaster->setParameters(
_planetRadius + _atmosphereHeight,
_planetRadius,
_groundAverageReflectance,
_groundRadianceEmission,
_rayleighHeightScale,
_ozoneEnabled,
_ozoneHeightScale,
_mieHeightScale,
_miePhaseConstant,
_sunIntensity,
_rayleighScatteringCoeff,
_ozoneCoeff,
_mieScatteringCoeff,
_mieExtinctionCoeff,
_sunFollowingCameraEnabled
);
_deferredcaster->setHardShadows(_hardShadowsEnabled);
}
} // namespace openspace

View File

@@ -72,7 +72,7 @@ public:
static documentation::Documentation Documentation();
private:
glm::dmat4 computeModelTransformMatrix(const openspace::TransformData& transformData);
glm::dmat4 computeModelTransformMatrix(const openspace::TransformData& data);
void updateAtmosphereParameters();
properties::FloatProperty _atmosphereHeight;
@@ -85,7 +85,7 @@ private:
properties::Vec3Property _ozoneCoeff;
properties::FloatProperty _mieHeightScale;
properties::Vec3Property _mieScatteringCoeff;
properties::FloatProperty _mieScatteringExtinctionPropCoefficient;
properties::FloatProperty _mieScatteringExtinctionPropCoeff;
properties::FloatProperty _miePhaseConstant;
properties::FloatProperty _sunIntensity;
properties::BoolProperty _sunFollowingCameraEnabled;
@@ -98,7 +98,7 @@ private:
// Atmosphere Debug
bool _saveCalculationsToTexture = false;
float _preCalculatedTexturesScale = 1.f;
float _textureScale = 1.f;
std::unique_ptr<AtmosphereDeferredcaster> _deferredcaster;

View File

@@ -54,85 +54,11 @@
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Atmosphere Rendering Parameters
uniform float Rg;
uniform float Rt;
uniform float AverageGroundReflectance;
uniform float groundRadianceEmission;
uniform float HR;
uniform vec3 betaRayleigh;
uniform float HO;
uniform vec3 betaOzoneExtinction;
uniform float HM;
uniform vec3 betaMieScattering;
uniform vec3 betaMieExtinction;
uniform float mieG;
uniform float sunRadiance;
uniform bool ozoneLayerEnabled;
uniform ivec2 TRANSMITTANCE;
uniform ivec2 SKY;
uniform ivec2 OTHER_TEXTURES;
uniform int SAMPLES_R;
uniform int SAMPLES_MU;
uniform int SAMPLES_MU_S;
uniform int SAMPLES_NU;
const int INSCATTER_INTEGRAL_SAMPLES = 50;
const float M_PI = 3.141592657;
const float ATM_EPSILON = 1.0;
// Integration steps
const int TRANSMITTANCE_STEPS = 500;
const int INSCATTER_INTEGRAL_SAMPLES = 50;
const int IRRADIANCE_INTEGRAL_SAMPLES = 32;
const int INSCATTER_SPHERICAL_INTEGRAL_SAMPLES = 16;
const float M_PI = 3.141592657;
const float M_2PI = 2.0 * M_PI;
uniform sampler2D transmittanceTexture;
float Rg2 = Rg * Rg;
float Rt2 = Rt * Rt;
float H = sqrt(Rt2 - Rg2);
float H2 = Rt2 - Rg2;
float invSamplesMu = 1.0 / float(SAMPLES_MU);
float invSamplesR = 1.0 / float(SAMPLES_R);
float invSamplesMuS = 1.0 / float(SAMPLES_MU_S);
float invSamplesNu = 1.0 / float(SAMPLES_NU);
float RtMinusRg = float(Rt - Rg);
float invRtMinusRg = 1.0 / RtMinusRg;
float opticalDepth(float localH, float r, float mu, 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);
vec2 a01sq = a01 * a01;
float x = a01s.y > a01s.x ? exp(a01sq.x) : 0.0;
vec2 y = a01s / (2.3193 * abs(a01) + sqrt(1.52 * a01sq + 4.0)) * vec2(1.0, exp(-d * invH * (d / (2.0 * r) + mu)));
return sqrt(M_2PI * H * r) * exp((Rg-r)*invH) * (x + dot(y, vec2(1.0, -1.0)));
}
vec3 analyticTransmittance(float r, float mu, float d) {
vec3 ozone = vec3(0.0);
if (ozoneLayerEnabled) {
ozone = betaOzoneExtinction * (0.0000006) * opticalDepth(HO, r, mu, d);
}
return exp(-betaRayleigh * opticalDepth(HR, r, mu, d) - ozone -
betaMieExtinction * opticalDepth(HM, r, mu, d));
}
vec3 irradiance(sampler2D sampler, float r, float muSun) {
float u_r = (r - Rg) * invRtMinusRg;
float u_muSun = (muSun + 0.2) / 1.2;
return texture(sampler, vec2(u_muSun, u_r)).rgb;
}
//================================================//
//=============== General Functions ==============//
//================================================//
// In the following shaders r (altitude) is the length of vector/position x in the
// atmosphere (or on the top of it when considering an observer in space), where the light
// is coming from the opposite direction of the view direction, here the vector v or
@@ -142,7 +68,7 @@ vec3 irradiance(sampler2D sampler, float r, float muSun) {
// or top of atmosphere
// r := || vec(x) || e [0, Rt]
// mu := cosine of the zeith angle of vec(v). Or mu = (vec(x) * vec(v))/r
float rayDistance(float r, float mu) {
float rayDistance(float r, float mu, float Rt, float Rg) {
// The light ray starting at the observer in/on the atmosphere can have to possible end
// points: the top of the atmosphere or the planet ground. So the shortest path is the
// one we are looking for, otherwise we may be passing through the ground
@@ -151,9 +77,8 @@ float rayDistance(float r, float mu) {
float atmRadiusEps2 = (Rt + ATM_EPSILON) * (Rt + ATM_EPSILON);
float mu2 = mu * mu;
float r2 = r * r;
float rg2 = Rg * Rg;
float rayDistanceAtmosphere = -r * mu + sqrt(r2 * (mu2 - 1.0) + atmRadiusEps2);
float delta = r2 * (mu2 - 1.0) + rg2;
float delta = r2 * (mu2 - 1.0) + Rg*Rg;
// Ray may be hitting ground
if (delta >= 0.0) {
@@ -173,19 +98,23 @@ float rayDistance(float r, float mu) {
// nu := cosone of the angle between vec(s) and vec(v)
// dhdH := it is a vec4. dhdH.x stores the dminT := Rt - r, dhdH.y stores the dH value
// (see paper), dhdH.z stores dminG := r - Rg and dhdH.w stores dh (see paper)
void unmappingMuMuSunNu(float r, vec4 dhdH, out float mu, out float muSun, out float nu) {
void unmappingMuMuSunNu(float r, vec4 dhdH, int SAMPLES_MU, float Rg, float Rt,
int SAMPLES_MU_S, int SAMPLES_NU,
out float mu, out float muSun, out float nu)
{
// Window coordinates of pixel (uncentering also)
vec2 fragment = gl_FragCoord.xy - vec2(0.5);
// Pre-calculations
float r2 = r * r;
float Rg2 = Rg * Rg;
float halfSAMPLE_MU = float(SAMPLES_MU) / 2.0;
// If the (vec(x) dot vec(v))/r is negative, i.e., the light ray has great probability
// to touch the ground, we obtain mu considering the geometry of the ground
if (fragment.y < halfSAMPLE_MU) {
float ud = 1.0 - (fragment.y / (halfSAMPLE_MU - 1.0));
float d = min(max(dhdH.z, ud * dhdH.w), dhdH.w * 0.999);
float d = min(max(dhdH.z, ud * dhdH.w), dhdH.w * 0.999);
// cosine law: Rg^2 = r^2 + d^2 - 2rdcos(pi-theta) where cosine(theta) = mu
mu = (Rg2 - r2 - d * d) / (2.0 * r * d);
// We can't handle a ray inside the planet, i.e., when r ~ Rg, so we check against it.
@@ -199,12 +128,12 @@ void unmappingMuMuSunNu(float r, vec4 dhdH, out float mu, out float muSun, out f
float d = (fragment.y - halfSAMPLE_MU) / (halfSAMPLE_MU - 1.0);
d = min(max(dhdH.x, d * dhdH.y), dhdH.y * 0.999);
// cosine law: Rt^2 = r^2 + d^2 - 2rdcos(pi-theta) where cosine(theta) = mu
mu = (Rt2 - r2 - d * d) / (2.0 * r * d);
mu = (Rt*Rt - r2 - d * d) / (2.0 * r * d);
}
float modValueMuSun = mod(fragment.x, float(SAMPLES_MU_S)) / (float(SAMPLES_MU_S) - 1.0);
// The following mapping is different from the paper. See Colliene for an details.
muSun = tan((2.0 * modValueMuSun - 1.0 + 0.26) * 1.1f) / tan(1.26 * 1.1);
// The following mapping is different from the paper. See Collienne for an details.
muSun = tan((2.0 * modValueMuSun - 1.0 + 0.26) * 1.1) / tan(1.26 * 1.1);
nu = -1.0 + floor(fragment.x / float(SAMPLES_MU_S)) / (float(SAMPLES_NU) - 1.0) * 2.0;
}
@@ -213,14 +142,14 @@ void unmappingMuMuSunNu(float r, vec4 dhdH, out float mu, out float muSun, out f
// hits the ground or the top of atmosphere.
// r := height of starting point vect(x)
// mu := cosine of the zeith angle of vec(v). Or mu = (vec(x) * vec(v))/r
vec3 transmittance(float r, float mu) {
vec3 transmittance(sampler2D tex, float r, float mu, float Rg, float Rt) {
// 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) * invRtMinusRg);
// See Colliene to understand the mapping
float u_r = sqrt((r - Rg) / (Rt - Rg));
// See Collienne to understand the mapping
float u_mu = atan((mu + 0.15) / 1.15 * tan(1.5)) / 1.5;
return texture(transmittanceTexture, vec2(u_mu, u_r)).rgb;
return texture(tex, vec2(u_mu, u_r)).rgb;
}
// Given a position r and direction mu, calculates de transmittance along the ray with
@@ -228,13 +157,13 @@ vec3 transmittance(float r, float mu) {
// T(a,b) = TableT(a,v)/TableT(b, v)
// r := height of starting point vect(x)
// mu := cosine of the zeith angle of vec(v). Or mu = (vec(x) * vec(v))/r
vec3 transmittance(float r, float mu, float d) {
vec3 transmittance(sampler2D tex, float r, float mu, float d, float Rg, float Rt) {
// Here we use the transmittance property: T(x,v) = T(x,d)*T(d,v) to, given a distance
// d, calculates that transmittance along that distance starting in x (height r):
// T(x,d) = T(x,v)/T(d,v).
//
// From cosine law: c^2 = a^2 + b^2 - 2*a*b*cos(ab)
float ri = sqrt(d * d + r * r + 2.0 * r * d * mu);
float ri = sqrt(d * d + r * r + 2.0 * r * d * mu);
// mu_i = (vec(d) dot vec(v)) / r_i
// = ((vec(x) + vec(d-x)) dot vec(v))/ r_i
// = (r*mu + d) / r_i
@@ -246,19 +175,21 @@ vec3 transmittance(float r, float mu, float d) {
// x --> x0, then x0-->x.
// Also, let's use the property: T(a,c) = T(a,b)*T(b,c)
// Because T(a,c) and T(b,c) are already in the table T, T(a,b) = T(a,c)/T(b,c).
vec3 res;
if (mu > 0.0) {
return min(transmittance(r, mu) / transmittance(ri, mui), 1.0);
res = transmittance(tex, r, mu, Rg, Rt) / transmittance(tex, ri, mui, Rg, Rt);
}
else {
return min(transmittance(ri, -mui) / transmittance(r, -mu), 1.0);
res = transmittance(tex, ri, -mui, Rg, Rt) / transmittance(tex, r, -mu, Rg, Rt);
}
return min(res, 1.0);
}
// Calculates Rayleigh phase function given the scattering cosine angle mu
// mu := cosine of the zeith angle of vec(v). Or mu = (vec(x) * vec(v))/r
float rayleighPhaseFunction(float mu) {
//return (3.0f / (16.0f * M_PI)) * (1.0f + mu * mu);
return 0.0596831036 * (1.0 + mu * mu);
// return (3.0 / (16.0 * M_PI)) * (1.0 + mu * mu);
return 0.0596831036 * (1.0 + mu * mu);
}
// Calculates Mie phase function given the scattering cosine angle mu
@@ -277,38 +208,30 @@ float miePhaseFunction(float mu, float mieG) {
// mu := cosine of the zeith angle of vec(v). Or mu = (vec(x) * vec(v))/r
// muSun := cosine of the zeith angle of vec(s). Or muSun = (vec(s) * vec(v))
// nu := cosine of the angle between vec(s) and vec(v)
vec4 texture4D(sampler3D table, float r, float mu, float muSun, float nu) {
vec4 texture4D(sampler3D table, float r, float mu, float muSun, float nu, float Rg,
int samplesMu, float Rt, int samplesR, int samplesMuS,
int samplesNu)
{
float r2 = r * r;
float Rg2 = Rg * Rg;
float Rt2 = Rt * Rt;
float rho = sqrt(r2 - Rg2);
float rmu = r * mu;
float delta = rmu * rmu - r2 + Rg2;
vec4 cst = rmu < 0.0 && delta > 0.0 ?
vec4(1.0, 0.0, 0.0, 0.5 - 0.5 * invSamplesMu) :
vec4(-1.0, H2, H, 0.5 + 0.5 * invSamplesMu);
vec4(1.0, 0.0, 0.0, 0.5 - 0.5 / float(samplesMu)) :
vec4(-1.0, Rt2 - Rg2, sqrt(Rt2 - Rg2), 0.5 + 0.5 / float(samplesMu));
float u_r = 0.5 * invSamplesR + rho / H * (1.0 - invSamplesR);
float u_mu = cst.w + (rmu * cst.x + sqrt(delta + cst.y)) / (rho + cst.z) * (0.5 - invSamplesMu);
float u_mu_s = 0.5 * invSamplesMuS +
(atan(max(muSun, -0.1975) * tan(1.386)) * 0.9090909090909090 + 0.74) * 0.5 * (1.0 - invSamplesMuS);
float lerp = (nu + 1.0) / 2.0 * (float(SAMPLES_NU) - 1.0);
float u_nu = floor(lerp);
lerp = lerp - u_nu;
float u_r = 0.5 / float(samplesR) + rho / sqrt(Rt2 - Rg2) * (1.0 - 1.0 / float(samplesR));
float u_mu = cst.w + (rmu * cst.x + sqrt(delta + cst.y)) / (rho + cst.z) * (0.5 - 1.0 / samplesMu);
float u_mu_s = 0.5 / float(samplesMuS) +
(atan(max(muSun, -0.1975) * tan(1.386)) * 0.9090909090909090 + 0.74) * 0.5 * (1.0 - 1.0 / float(samplesMuS));
float t = (nu + 1.0) / 2.0 * (float(samplesNu) - 1.0);
float u_nu = floor(t);
t = t - u_nu;
return texture(
table, vec3((u_nu + u_mu_s) * invSamplesNu, u_mu, u_r)) * (1.0 - lerp) +
texture(table, vec3((u_nu + u_mu_s + 1.0) * invSamplesNu, u_mu, u_r)) * lerp;
}
// Given the irradiance texture table, the cosine of zenith sun vector and the height of
// the observer (ray's stating point x), calculates the mapping for u_r and u_muSun and
// returns the value in the LUT
// lut := OpenGL texture2D sampler (the irradiance texture deltaE)
// muSun := cosine of the zeith angle of vec(s). Or muSun = (vec(s) * vec(v))
// r := height of starting point vect(x)
vec3 irradianceLUT(sampler2D lut, float muSun, float r) {
// See Bruneton paper and Coliene to understand the mapping
float u_muSun = (muSun + 0.2) / 1.2;
float u_r = (r - Rg) * invRtMinusRg;
return texture(lut, vec2(u_muSun, u_r)).rgb;
vec4 v1 = texture(table, vec3((u_nu + u_mu_s) / float(samplesNu), u_mu, u_r));
vec4 v2 = texture(table, vec3((u_nu + u_mu_s + 1.0) / float(samplesNu), u_mu, u_r));
return mix(v1, v2, t);
}

View File

@@ -64,27 +64,37 @@ out vec4 renderTarget;
uniform int cullAtmosphere;
uniform float Rg;
uniform float Rt;
uniform float groundRadianceEmission;
uniform float HR;
uniform vec3 betaRayleigh;
uniform float HO;
uniform vec3 betaOzoneExtinction;
uniform float HM;
uniform vec3 betaMieExtinction;
uniform float mieG;
uniform float sunRadiance;
uniform bool ozoneLayerEnabled;
uniform int SAMPLES_R;
uniform int SAMPLES_MU;
uniform int SAMPLES_MU_S;
uniform int SAMPLES_NU;
uniform sampler2D transmittanceTexture;
uniform sampler2D irradianceTexture;
uniform sampler3D inscatterTexture;
uniform sampler2D mainPositionTexture;
uniform sampler2D mainNormalTexture;
uniform sampler2D mainColorTexture;
uniform dmat4 inverseModelTransformMatrix;
uniform dmat4 modelTransformMatrix;
uniform dmat4 viewToWorldMatrix;
uniform dmat4 projectionToModelTransformMatrix;
uniform vec4 viewport;
uniform vec2 resolution;
uniform dvec3 camPosObj;
uniform dvec3 sunDirectionObj;
uniform dvec3 sunWorld;
uniform dvec3 viewDirWorld;
uniform dvec3 sunModel;
/*******************************************************************************
***** ALL CALCULATIONS FOR ECLIPSE ARE IN METERS AND IN WORLD SPACE SYSTEM ****
*******************************************************************************/
@@ -92,8 +102,10 @@ uniform dvec3 sunModel;
const uint numberOfShadows = 1;
struct ShadowRenderingStruct {
double xu, xp;
double rs, rc;
double xu;
double xp;
double rs;
double rc;
dvec3 sourceCasterVec;
dvec3 casterPositionVec;
bool isShadowing;
@@ -113,15 +125,15 @@ float calcShadow(ShadowRenderingStruct shadowInfoArray[numberOfShadows], dvec3 p
}
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;
dvec3 scNorm = shadowInfoArray[0].sourceCasterVec;
dvec3 pcProj = dot(pc, scNorm) * scNorm;
dvec3 d = pc - pcProj;
float length_d = float(length(d));
double length_pc_proj = length(pc_proj);
double lengthPcProj = length(pcProj);
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);
float r_p_pi = float(shadowInfoArray[0].rc * (lengthPcProj + shadowInfoArray[0].xp) / shadowInfoArray[0].xp);
float r_u_pi = float(shadowInfoArray[0].rc * (shadowInfoArray[0].xu - lengthPcProj) / shadowInfoArray[0].xu);
if (length_d < r_u_pi) {
// umbra
@@ -142,6 +154,33 @@ float calcShadow(ShadowRenderingStruct shadowInfoArray[numberOfShadows], dvec3 p
}
}
float opticalDepth(float localH, float r, float mu, float d, float Rg) {
float invH = 1.0 / localH;
float a = sqrt(0.5 * invH * r);
vec2 a01 = a * vec2(mu, mu + d / r);
vec2 a01s = sign(a01);
vec2 a01sq = a01 * a01;
float x = a01s.y > a01s.x ? exp(a01sq.x) : 0.0;
vec2 y = a01s / (2.3193 * abs(a01) + sqrt(1.52 * a01sq + 4.0)) *
vec2(1.0, exp(-d * invH * (d / (2.0 * r) + mu)));
return sqrt(2.0 * M_PI * sqrt(Rt*Rt - Rg*Rg) * r) * exp((Rg-r)*invH) * (x + dot(y, vec2(1.0, -1.0)));
}
vec3 analyticTransmittance(float r, float mu, float d) {
vec3 ozone = vec3(0.0);
if (ozoneLayerEnabled) {
ozone = betaOzoneExtinction * 0.0000006 * opticalDepth(HO, r, mu, d, Rg);
}
return exp(-betaRayleigh * opticalDepth(HR, r, mu, d, Rg) - ozone -
betaMieExtinction * opticalDepth(HM, r, mu, d, Rg));
}
vec3 irradiance(sampler2D s, float r, float muSun) {
float u_r = (r - Rg) / (Rt - Rg);
float u_muSun = (muSun + 0.2) / 1.2;
return texture(s, vec2(u_muSun, u_r)).rgb;
}
//////////////////////////////////////////////////////////////////////////////////////////
// ALL CALCULATIONS FOR ATMOSPHERE ARE KM AND IN WORLD SPACE SYSTEM //
//////////////////////////////////////////////////////////////////////////////////////////
@@ -173,10 +212,11 @@ bool atmosphereIntersection(Ray ray, double atmRadius, out double offset,
double l2 = dot(l, l);
double r2 = atmRadius * atmRadius; // avoiding surface acne
offset = 0.0;
maxLength = 0.0;
// Ray origin (eye position) is behind sphere
if ((s < 0.0) && (l2 > r2)) {
offset = 0.0;
maxLength = 0.0;
return false;
}
@@ -184,13 +224,9 @@ bool atmosphereIntersection(Ray ray, double atmRadius, out double offset,
// 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);
@@ -248,9 +284,9 @@ Ray calculateRayRenderableGlobe(vec2 st) {
* the reflectance R[L]
*/
vec3 inscatterRadiance(vec3 x, inout float t, inout float irradianceFactor, vec3 v, vec3 s,
float r, out float mu, out vec3 attenuation, vec3 fragPosObj,
out bool groundHit, double maxLength, double pixelDepth,
vec3 spaceColor, float sunIntensity)
float r, vec3 fragPosObj, double maxLength, double pixelDepth,
vec3 spaceColor, float sunIntensity,
out float mu, out vec3 attenuation, out bool groundHit)
{
const float INTERPOLATION_EPS = 0.004; // precision const from Brunetton
@@ -268,7 +304,11 @@ vec3 inscatterRadiance(vec3 x, inout float t, inout float irradianceFactor, vec3
// 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);
vec4 inscatterRadiance = max(
texture4D(inscatterTexture, r, mu, muSun, nu, Rg, SAMPLES_MU, Rt, SAMPLES_R,
SAMPLES_MU_S, SAMPLES_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
@@ -286,13 +326,14 @@ vec3 inscatterRadiance(vec3 x, inout float t, inout float irradianceFactor, vec3
// 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);
attenuation = transmittance(transmittanceTexture, r, mu, t, Rg, Rt);
// 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);
vec4 inscatterFromSurface = texture4D(inscatterTexture, r0, mu0, muSun0, nu, Rg,
SAMPLES_MU, Rt, SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU);
inscatterRadiance = max(inscatterRadiance - attenuation.rgbr * inscatterFromSurface, 0.0);
// We set the irradianceFactor to 1.0 so the reflected irradiance will be considered
@@ -307,7 +348,7 @@ vec3 inscatterRadiance(vec3 x, inout float t, inout float irradianceFactor, vec3
// 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);
float muHorizon = -sqrt(1.0 - Rg*Rg / r2);
// In order to avoid precision problems near horizon, we interpolate between two
// points: above and below horizon
@@ -318,10 +359,10 @@ vec3 inscatterRadiance(vec3 x, inout float t, inout float irradianceFactor, vec3
// Above Horizon
mu = muHorizon - INTERPOLATION_EPS;
// r0 = sqrt(r * r + t * t + 2.0f * r * t * mu);
// r0 = sqrt(r * r + t * t + 2.0 * 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.0 * r * t * mu);
float halfCosineLaw1 = r2 + (t * t);
float halfCosineLaw2 = 2.0 * r * t;
r0 = sqrt(halfCosineLaw1 + halfCosineLaw2 * mu);
@@ -332,20 +373,24 @@ vec3 inscatterRadiance(vec3 x, inout float t, inout float irradianceFactor, vec3
// 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);
vec4 inScatterAboveX = texture4D(inscatterTexture, r, mu, muSun, nu, Rg,
SAMPLES_MU, Rt, SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU);
vec4 inScatterAboveXs = texture4D(inscatterTexture, r0, mu0, muSun0, nu, Rg,
SAMPLES_MU, Rt, SAMPLES_R, SAMPLES_MU_S, SAMPLES_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(r2 + t2 + 2.0 * r * t * mu);
r0 = sqrt(halfCosineLaw1 + halfCosineLaw2 * mu);
mu0 = (r * mu + t) * (1.0 / r0);
vec4 inScatterBelowX = texture4D(inscatterTexture, r, mu, muSun, nu);
vec4 inScatterBelowXs = texture4D(inscatterTexture, r0, mu0, muSun0, nu);
vec4 inScatterBelowX = texture4D(inscatterTexture, r, mu, muSun, nu, Rg,
SAMPLES_MU, Rt, SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU);
vec4 inScatterBelowXs = texture4D(inscatterTexture, r0, mu0, muSun0, nu, Rg,
SAMPLES_MU, Rt, SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU);
// Attention for the attenuation.r value applied to the S_Mie
vec4 inScatterBelow = max(inScatterBelowX - attenuation.rgbr * inScatterBelowXs, 0.0);
@@ -370,13 +415,7 @@ vec3 inscatterRadiance(vec3 x, inout float t, inout float irradianceFactor, vec3
// 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 + finalScatteringRadiance;
}
return groundHit ? finalScatteringRadiance : spaceColor + finalScatteringRadiance;
}
/*
@@ -401,8 +440,6 @@ vec3 groundColor(vec3 x, float t, vec3 v, vec3 s, vec3 attenuationXtoX0, vec3 gr
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);
@@ -415,7 +452,7 @@ vec3 groundColor(vec3 x, float t, vec3 v, vec3 s, vec3 attenuationXtoX0, vec3 gr
// 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);
muSun < -sqrt(1.0 - (Rg*Rg / (r0 * r0))) ? vec3(0.0) : transmittance(transmittanceTexture, r0, muSun, Rg, Rt);
// E[L*] at x0
vec3 irradianceReflected = irradiance(irradianceTexture, r0, muSun) * irradianceFactor;
@@ -433,16 +470,14 @@ vec3 groundColor(vec3 x, float t, vec3 v, vec3 s, vec3 attenuationXtoX0, vec3 gr
// 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);
float waterBrdf = max(fresnel * pow(max(dot(h, normal), 0.0), 150.0), 0.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;
groundRadiance += waterReflectance * waterBrdf * 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.
vec3 reflectedRadiance = attenuationXtoX0 * groundRadiance;
return reflectedRadiance;
}
@@ -464,7 +499,7 @@ vec3 sunColor(vec3 v, vec3 s, float r, float mu, float irradianceFactor) {
// JCC: Change this function to a impostor texture with gaussian decay color weighted
// by the sunRadiance, transmittance and irradianceColor (11/03/2017)
// @TODO (abock, 2021-07-01) This value is hard-coded to our sun right now
// @TODO (abock, 2021-07-01) This value is hard-coded to our sun+earth right now
// Convert 0.3 degrees -> radians
const float SunAngularSize = (0.3 * M_PI / 180.0);
const float FuzzyFactor = 0.5; // How fuzzy should the edges be
@@ -474,7 +509,7 @@ vec3 sunColor(vec3 v, vec3 s, float r, float mu, float irradianceFactor) {
float t = (angle - p1) / (p2 - p1);
float scale = clamp(t, 0.0, 1.0);
return scale * transmittance(r, mu) * sunRadiance * (1.0 - irradianceFactor);
return scale * transmittance(transmittanceTexture, r, mu, Rg, Rt) * sunRadiance * (1.0 - irradianceFactor);
}
void main() {
@@ -588,24 +623,22 @@ void main() {
bool groundHit = false;
vec3 attenuation;
vec3 inscatterColor = inscatterRadiance(x, tF, irradianceFactor, v, s, r, mu,
attenuation, vec3(positionObjectsCoords), groundHit, maxLength, pixelDepth,
color, sunIntensityInscatter);
vec3 inscatterColor = inscatterRadiance(x, tF, irradianceFactor, v, s, r,
vec3(positionObjectsCoords), maxLength, pixelDepth, color, sunIntensityInscatter, mu,
attenuation, groundHit);
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, normal.xyz,
irradianceFactor, normal.w, sunIntensityGround);
atmColor = groundColor(x, tF, v, s, attenuation, color, 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;
renderTarget = vec4(inscatterColor + atmColor, 1.0);;
}

View File

@@ -24,8 +24,8 @@
#version __CONTEXT__
layout(location = 0) in vec3 in_position;
layout(location = 0) in vec2 in_position;
void main() {
gl_Position = vec4(in_position, 1.0);
gl_Position = vec4(in_position, 0.0, 1.0);
}

View File

@@ -24,8 +24,6 @@
#version __CONTEXT__
#include "atmosphere_common.glsl"
out vec4 renderTableColor;
void main() {

View File

@@ -28,19 +28,45 @@
out vec4 renderTarget;
uniform float Rg;
uniform float Rt;
uniform float AverageGroundReflectance;
uniform float HR;
uniform vec3 betaRayleigh;
uniform float HM;
uniform vec3 betaMieScattering;
uniform float mieG;
uniform int SAMPLES_R;
uniform int SAMPLES_MU;
uniform int SAMPLES_MU_S;
uniform int SAMPLES_NU;
uniform sampler2D transmittanceTexture;
uniform float r;
uniform vec4 dhdH;
uniform sampler2D deltaETexture;
uniform sampler3D deltaSRTexture;
uniform sampler3D deltaSMTexture;
uniform int firstIteration;
uniform int firstIteraction;
const int INSCATTER_SPHERICAL_INTEGRAL_SAMPLES = 16;
// -- Spherical Coordinates Steps. phi e [0,2PI] and theta e [0, PI]
const float stepPhi = (2.0 * M_PI) / float(INSCATTER_SPHERICAL_INTEGRAL_SAMPLES);
const float stepTheta = M_PI / float(INSCATTER_SPHERICAL_INTEGRAL_SAMPLES);
// Given the irradiance texture table, the cosine of zenith sun vector and the height of
// the observer (ray's stating point x), calculates the mapping for u_r and u_muSun and
// returns the value in the LUT
// lut := OpenGL texture2D sampler (the irradiance texture deltaE)
// muSun := cosine of the zeith angle of vec(s). Or muSun = (vec(s) * vec(v))
// r := height of starting point vect(x)
vec3 irradianceLUT(sampler2D lut, float muSun, float r) {
// See Bruneton paper and Coliene to understand the mapping
float u_muSun = (muSun + 0.2) / 1.2;
float u_r = (r - Rg) / (Rt - Rg);
return texture(lut, vec2(u_muSun, u_r)).rgb;
}
vec3 inscatter(float r, float mu, float muSun, float nu) {
// Be sure to not get a cosine or height out of bounds
r = clamp(r, Rg, Rt);
@@ -59,7 +85,7 @@ vec3 inscatter(float r, float mu, float muSun, float nu) {
float muSun2 = muSun * muSun;
float sinThetaSinSigma = sqrt(1.0 - mu2) * sqrt(1.0 - muSun2);
// cos(sigma + theta) = cos(theta)cos(sigma)-sin(theta)sin(sigma)
// cos(ni) = nu = mu * muSun - sqrt(1.0f - mu*mu)*sqrt(1.0 - muSun*muSun) // sin(theta) = sqrt(1.0 - mu*mu)
// cos(ni) = nu = mu * muSun - sqrt(1.0 - mu*mu)*sqrt(1.0 - muSun*muSun) // sin(theta) = sqrt(1.0 - mu*mu)
// Now we make sure the angle between vec(s) and vec(v) is in the right range:
nu = clamp(nu, muSun * mu - sinThetaSinSigma, muSun * mu + sinThetaSinSigma);
@@ -69,7 +95,7 @@ vec3 inscatter(float r, float mu, float muSun, float nu) {
// -cos(theta) = sqrt(r*r-Rg*Rg)/r
float Rg2 = Rg * Rg;
float r2 = r * r;
float cosHorizon = -sqrt(r2 - Rg2)/r;
float cosHorizon = -sqrt(r2 - Rg2) / r;
// Now we get vec(v) and vec(s) from mu, muSun and nu:
// Assuming:
@@ -97,6 +123,7 @@ vec3 inscatter(float r, float mu, float muSun, float nu) {
// In order to integrate over 4PI, we scan the sphere using the spherical coordinates
// previously defined
vec3 radianceJAcc = vec3(0.0);
for (int theta_i = 0; theta_i < INSCATTER_SPHERICAL_INTEGRAL_SAMPLES; theta_i++) {
float theta = (float(theta_i) + 0.5) * stepTheta;
float cosineTheta = cos(theta);
@@ -131,7 +158,7 @@ vec3 inscatter(float r, float mu, float muSun, float nu) {
// float muGround = (r2 - distanceToGround*distanceToGround - Rg2)/(2*distanceToGround*Rg);
// Access the Transmittance LUT in order to calculate the transmittance from the
// ground point Rg, thorugh the atmosphere, at a distance: distanceToGround
groundTransmittance = transmittance(Rg, muGround, distanceToGround);
groundTransmittance = transmittance(transmittanceTexture, Rg, muGround, distanceToGround, Rg, Rt);
}
for (int phi_i = 0; phi_i < INSCATTER_SPHERICAL_INTEGRAL_SAMPLES; ++phi_i) {
@@ -161,43 +188,48 @@ vec3 inscatter(float r, float mu, float muSun, float nu) {
// We calculate the Rayleigh and Mie phase function for the new scattering angle:
// cos(angle between vec(s) and vec(w)), ||s|| = ||w|| = 1
float nuSW = dot(s, w);
// The first iteraction is different from the others. In the first iteraction all
// The first iteration is different from the others. In the first iteration all
// the light InScattered is coming from the initial pre-computed single InScattered
// light. We stored these values in the deltaS textures (Ray and Mie), and in order
// to avoid problems with the high angle dependency in the phase functions, we don't
// include the phase functions on those tables (that's why we calculate them now).
if (firstIteraction == 1) {
if (firstIteration == 1) {
float phaseRaySW = rayleighPhaseFunction(nuSW);
float phaseMieSW = miePhaseFunction(nuSW, mieG);
// We can now access the values for the single InScattering in the textures deltaS textures.
vec3 singleRay = texture4D(deltaSRTexture, r, w.z, muSun, nuSW).rgb;
vec3 singleMie = texture4D(deltaSMTexture, r, w.z, muSun, nuSW).rgb;
vec3 singleRay = texture4D(deltaSRTexture, r, w.z, muSun, nuSW, Rg, SAMPLES_MU,
Rt, SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU).rgb;
vec3 singleMie = texture4D(deltaSMTexture, r, w.z, muSun, nuSW, Rg, SAMPLES_MU,
Rt, SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU).rgb;
// Initial InScattering including the phase functions
radianceJ1 += singleRay * phaseRaySW + singleMie * phaseMieSW;
}
else {
// On line 9 of the algorithm, the texture table deltaSR is updated, so when we
// are not in the first iteraction, we are getting the updated result of deltaSR
// are not in the first iteration, we are getting the updated result of deltaSR
// (not the single inscattered light but the accumulated (higher order)
// inscattered light.
// w.z is the cosine(theta) = mu for vec(w)
radianceJ1 += texture4D(deltaSRTexture, r, w.z, muSun, nuSW).rgb;
radianceJ1 += texture4D(deltaSRTexture, r, w.z, muSun, nuSW, Rg, SAMPLES_MU, Rt,
SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU).rgb;
}
// Finally, we add the atmospheric scale height (See: Radiation Transfer on the
// Atmosphere and Ocean from Thomas and Stamnes, pg 9-10.
return radianceJ1 * (betaRayleigh * exp(-(r - Rg) / HR) * phaseRayleighWV +
radianceJAcc += radianceJ1 * (betaRayleigh * exp(-(r - Rg) / HR) * phaseRayleighWV +
betaMieScattering * exp(-(r - Rg) / HM) * phaseMieWV) * dw;
}
}
return radianceJAcc;
}
void main() {
// InScattering Radiance to be calculated at different points in the ray path
// Unmapping the variables from texture texels coordinates to mapped coordinates
float mu, muSun, nu;
unmappingMuMuSunNu(r, dhdH, mu, muSun, nu);
unmappingMuMuSunNu(r, dhdH, SAMPLES_MU, Rg, Rt, SAMPLES_MU_S, SAMPLES_NU, mu, muSun, nu);
// Calculate the the light inScattered in direction
// -vec(v) for the point at height r (vec(y) following Bruneton and Neyret's paper

View File

@@ -28,6 +28,10 @@
out vec4 renderTarget;
uniform int SAMPLES_R;
uniform int SAMPLES_MU;
uniform int SAMPLES_MU_S;
uniform int SAMPLES_NU;
uniform int layer;
uniform sampler3D deltaSRTexture;
uniform sampler3D deltaSMTexture;

View File

@@ -28,6 +28,10 @@
out vec4 renderTarget;
uniform int SAMPLES_R;
uniform int SAMPLES_MU;
uniform int SAMPLES_MU_S;
uniform int SAMPLES_NU;
uniform int layer;
uniform sampler3D deltaSTexture;
@@ -35,10 +39,9 @@ void main() {
vec2 p = gl_FragCoord.xy - vec2(0.5);
float nu = -1.0 + floor(p.x / float(SAMPLES_MU_S)) / (float(SAMPLES_NU) - 1.0) * 2.0;
vec3 uvw = vec3(
gl_FragCoord.xy,
float(layer) + 0.5) / vec3(ivec3(SAMPLES_MU_S * SAMPLES_NU, SAMPLES_MU, SAMPLES_R)
);
vec3 uvw =
vec3(gl_FragCoord.xy, float(layer) + 0.5) /
vec3(ivec3(SAMPLES_MU_S * SAMPLES_NU, SAMPLES_MU, SAMPLES_R));
// See Bruneton and Neyret paper, "Angular Precision" paragraph to understanding why we
// are dividing the S[L*] by the Rayleigh phase function.

View File

@@ -29,6 +29,18 @@
layout(location = 0) out vec4 renderTarget1;
layout(location = 1) out vec4 renderTarget2;
uniform float Rg;
uniform float Rt;
uniform float HR;
uniform vec3 betaRayleigh;
uniform float HO;
uniform float HM;
uniform vec3 betaMieScattering;
uniform bool ozoneLayerEnabled;
uniform int SAMPLES_MU;
uniform int SAMPLES_MU_S;
uniform int SAMPLES_NU;
uniform sampler2D transmittanceTexture;
uniform float r;
uniform vec4 dhdH;
@@ -60,7 +72,9 @@ void integrand(float r, float mu, float muSun, float nu, float y, out vec3 S_R,
if (muSun_i >= -sqrt(1.0 - Rg * Rg / (ri * ri))) {
// It's the transmittance from the point y (ri) to the top of atmosphere in direction
// of the sun (muSun_i) and the transmittance from the observer at x (r) to y (ri).
vec3 transmittanceY = transmittance(r, mu, y) * transmittance(ri, muSun_i);
vec3 transmittanceY =
transmittance(transmittanceTexture, r, mu, y, Rg, Rt) *
transmittance(transmittanceTexture, ri, muSun_i, Rg, Rt);
// exp(-h/H)*T(x,v)
if (ozoneLayerEnabled) {
S_R = (exp(-(ri - Rg) / HO) + exp(-(ri - Rg) / HR)) * transmittanceY;
@@ -83,7 +97,7 @@ void inscatter(float r, float mu, float muSun, float nu, out vec3 S_R, out vec3
S_R = vec3(0.0);
S_M = vec3(0.0);
float rayDist = rayDistance(r, mu);
float rayDist = rayDistance(r, mu, Rt, Rg);
float dy = rayDist / float(INSCATTER_INTEGRAL_SAMPLES);
vec3 S_Ri;
vec3 S_Mi;
@@ -103,13 +117,10 @@ void inscatter(float r, float mu, float muSun, float nu, out vec3 S_R, out vec3
}
void main() {
vec3 S_R; // First Order Rayleigh InScattering
vec3 S_M; // First Order Mie InScattering
// From the layer interpolation (see C++ code for layer to r) and the textures
// parameters (uv), we unmapping mu, muSun and nu.
float mu, muSun, nu;
unmappingMuMuSunNu(r, dhdH, mu, muSun, nu);
unmappingMuMuSunNu(r, dhdH, SAMPLES_MU, Rg, Rt, SAMPLES_MU_S, SAMPLES_NU, mu, muSun, nu);
// Here we calculate the single inScattered light. Because this is a single
// inscattering, the light that arrives at a point y in the path from the eye to the
@@ -122,6 +133,8 @@ void main() {
// S[L0] = P_R*S_R[L0] + P_M*S_M[L0]
// In order to save memory, we just store the red component of S_M[L0], and later we use
// the proportionality rule to calcule the other components.
vec3 S_R; // First Order Rayleigh InScattering
vec3 S_M; // First Order Mie InScattering
inscatter(r, mu, muSun, nu, S_R, S_M);
renderTarget1 = vec4(S_R, 1.0);
renderTarget2 = vec4(S_M, 1.0);

View File

@@ -28,6 +28,13 @@
out vec4 renderTarget;
uniform float Rg;
uniform float Rt;
uniform int SAMPLES_R;
uniform int SAMPLES_MU;
uniform int SAMPLES_MU_S;
uniform int SAMPLES_NU;
uniform sampler2D transmittanceTexture;
uniform float r;
uniform vec4 dhdH;
uniform sampler3D deltaJTexture;
@@ -35,7 +42,7 @@ uniform sampler3D deltaJTexture;
// The integrand here is the f(y) of the trapezoidal rule:
vec3 integrand(float r, float mu, float muSun, float nu, float dist) {
// We can calculate r_i by the cosine law: r_i^2=dist^2 + r^2 - 2*r*dist*cos(PI-theta)
float r_i = sqrt(r * r + dist * dist + 2.0f * r * dist * mu);
float r_i = sqrt(r * r + dist * dist + 2.0 * r * dist * mu);
// r_i can be found using the dot product:
// vec(y_i) dot vec(dist) = cos(theta_i) * ||vec(y_i)|| * ||vec(dist)||
// But vec(y_i) = vec(x) + vec(dist), also: vec(x) dot vec(dist) = cos(theta) = mu
@@ -46,12 +53,15 @@ vec3 integrand(float r, float mu, float muSun, float nu, float dist) {
// But vec(y_i) = vec(x) + vec(dist), and vec(x) dot vec(s) = muSun, cos(sigma_i + theta_i) = nu
float muSun_i = (r * muSun + dist * nu) / r_i;
// The irradiance attenuated from point r until y (y-x = dist)
return transmittance(r, mu, dist) * texture4D(deltaJTexture, r_i, mu_i, muSun_i, nu).rgb;
return
transmittance(transmittanceTexture, r, mu, dist, Rg, Rt) *
texture4D(deltaJTexture, r_i, mu_i, muSun_i, nu, Rg, SAMPLES_MU, Rt, SAMPLES_R,
SAMPLES_MU_S, SAMPLES_NU).rgb;
}
vec3 inscatter(float r, float mu, float muSun, float nu) {
vec3 inScatteringRadiance = vec3(0.0);
float dy = rayDistance(r, mu) / float(INSCATTER_INTEGRAL_SAMPLES);
float dy = rayDistance(r, mu, Rt, Rg) / float(INSCATTER_INTEGRAL_SAMPLES);
vec3 inScatteringRadiance_i = integrand(r, mu, muSun, nu, 0.0);
// In order to solve the integral from equation (11) we use the trapezoidal rule:
@@ -71,7 +81,7 @@ void main() {
float muSun = 0.0;
float nu = 0.0;
// Unmapping the variables from texture texels coordinates to mapped coordinates
unmappingMuMuSunNu(r, dhdH, mu, muSun, nu);
unmappingMuMuSunNu(r, dhdH, SAMPLES_MU, Rg, Rt, SAMPLES_MU_S, SAMPLES_NU, mu, muSun, nu);
// Write to texture deltaSR
renderTarget = vec4(inscatter(r, mu, muSun, nu), 1.0);

View File

@@ -28,16 +28,24 @@
out vec4 renderTableColor;
void main() {
// See Bruneton and Colliene to understand the mapping
float muSun = -0.2 + (gl_FragCoord.x - 0.5) / (float(OTHER_TEXTURES.x) - 1.0) * 1.2;
float r = Rg + (gl_FragCoord.y - 0.5) / (float(OTHER_TEXTURES.y) ) * RtMinusRg;
uniform float Rg;
uniform float Rt;
uniform ivec2 OTHER_TEXTURES;
uniform sampler2D transmittanceTexture;
// We are calculating the Irradiance for L0, i.e., only the radiance coming from Sun
// direction is accounted:
void main() {
// See Bruneton and Collienne to understand the mapping
float muSun = -0.2 + (gl_FragCoord.x - 0.5) / (float(OTHER_TEXTURES.x) - 1.0) * 1.2;
float r = Rg + (gl_FragCoord.y - 0.5) / (float(OTHER_TEXTURES.y)) * (Rt - Rg);
// We are calculating the Irradiance for L0, i.e., only the radiance coming from the Sun
// direction is accounted for:
// E[L0](x,s) = L0*dot(w,n) or 0 (if v!=s or the sun is occluded).
// Because we consider the Planet as a perfect sphere and we are considering only single
// Because we consider the planet as a perfect sphere and we are considering only single
// scattering here, the dot product dot(w,n) is equal to dot(s,n) that is equal to
// dot(s, r/||r||) = muSun.
renderTableColor = vec4(transmittance(r, muSun) * max(muSun, 0.0), 0.0);
renderTableColor = vec4(
transmittance(transmittanceTexture, r, muSun, Rg, Rt) * max(muSun, 0.0),
0.0
);
}

View File

@@ -24,10 +24,9 @@
#version __CONTEXT__
#include "atmosphere_common.glsl"
out vec4 renderTableColor;
uniform ivec2 OTHER_TEXTURES;
uniform sampler2D deltaETexture;
void main() {

View File

@@ -28,22 +28,32 @@
out vec4 renderTableColor;
uniform int firstIteraction;
uniform float Rg;
uniform float Rt;
uniform float mieG;
uniform ivec2 SKY;
uniform int SAMPLES_R;
uniform int SAMPLES_MU;
uniform int SAMPLES_MU_S;
uniform int SAMPLES_NU;
uniform int firstIteration;
uniform sampler3D deltaSRTexture;
uniform sampler3D deltaSMTexture;
const int IRRADIANCE_INTEGRAL_SAMPLES = 32;
// Spherical Coordinates Steps. phi e [0,2PI] and theta e [0, PI/2]
const float stepPhi = (2.0 * M_PI) / float(IRRADIANCE_INTEGRAL_SAMPLES);
const float stepTheta = M_PI / (2.0 * float(IRRADIANCE_INTEGRAL_SAMPLES));
void main() {
// See Bruneton and Colliene to understand the mapping.
// See Bruneton and Collienne to understand the mapping.
float muSun = -0.2 + (gl_FragCoord.x - 0.5) / (float(SKY.x) - 1.0) * 1.2;
float r = Rg + (gl_FragCoord.y - 0.5) / (float(SKY.y) - 1.0) * RtMinusRg;
float r = Rg + (gl_FragCoord.y - 0.5) / (float(SKY.y) - 1.0) * (Rt - Rg);
// We know that muSun = cos(sigma) = s.z/||s||
// But, ||s|| = 1, so s.z = muSun. Also,
// ||s|| = 1, so s.x = sin(sigma) = sqrt(1-muSun^2) and s.y = 0.0f
// ||s|| = 1, so s.x = sin(sigma) = sqrt(1-muSun^2) and s.y = 0.0
vec3 s = vec3(max(sqrt(1.0 - muSun * muSun), 0.0), 0.0, muSun);
// In order to solve the integral from equation (15) we use the trapezoidal rule:
@@ -60,30 +70,32 @@ void main() {
vec3 w = vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), cos(theta));
float nu = dot(s, w);
// The first iteraction is different from the others, that's because in the first
// iteraction all the light arriving are coming from the initial pre-computed
// single scattered light. We stored these values in the deltaS textures (Ray and
// Mie), and in order to avoid problems with the high angle dependency in the phase
// functions, we don't include the phase functions on those tables (that's why we
// calculate them now)
if (firstIteraction == 1) {
// The first iteration is different from the others as in the first iteration all
// the light arriving is coming from the initial pre-computed single scattered
// light. We stored these values in the deltaS textures (Ray and Mie), and in order
// to avoid problems with the high angle dependency in the phase functions, we don't
// include the phase functions on those tables (that's why we calculate them now)
if (firstIteration == 1) {
float phaseRay = rayleighPhaseFunction(nu);
float phaseMie = miePhaseFunction(nu, mieG);
vec3 singleRay = texture4D(deltaSRTexture, r, w.z, muSun, nu).rgb;
vec3 singleMie = texture4D(deltaSMTexture, r, w.z, muSun, nu).rgb;
vec3 singleRay = texture4D(deltaSRTexture, r, w.z, muSun, nu, Rg, SAMPLES_MU, Rt,
SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU).rgb;
vec3 singleMie = texture4D(deltaSMTexture, r, w.z, muSun, nu, Rg, SAMPLES_MU, Rt,
SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU).rgb;
// w.z is the cosine(theta) = mu for vec(w) and also vec(w) dot vec(n(xo))
irradianceE += (singleRay * phaseRay + singleMie * phaseMie) * w.z * dw;
}
else {
// On line 10 of the algorithm, the texture table deltaE is updated, so when we
// are not in the first iteraction, we are getting the updated result of deltaE
// are not in the first iteration, we are getting the updated result of deltaE
// (not the single irradiance light but the accumulated (higher order) irradiance
// light. w.z is the cosine(theta) = mu for vec(w) and also vec(w) dot vec(n(xo))
irradianceE += texture4D(deltaSRTexture, r, w.z, muSun, nu).rgb * w.z * dw;
irradianceE += texture4D(deltaSRTexture, r, w.z, muSun, nu, Rg, SAMPLES_MU, Rt,
SAMPLES_R, SAMPLES_MU_S, SAMPLES_NU).rgb * w.z * dw;
}
}
}
// Write the higher oder irradiance to texture deltaE
// Write the higher order irradiance to texture deltaE
renderTableColor = vec4(irradianceE, 0.0);
}

View File

@@ -28,6 +28,19 @@
out vec4 renderTableColor;
uniform float Rg;
uniform float Rt;
uniform float HR;
uniform vec3 betaRayleigh;
uniform float HO;
uniform vec3 betaOzoneExtinction;
uniform float HM;
uniform vec3 betaMieExtinction;
uniform bool ozoneLayerEnabled;
uniform ivec2 TRANSMITTANCE;
const int TRANSMITTANCE_STEPS = 500;
// Optical depth by integration, from ray starting at point vec(x), i.e, height r and
// angle mu (cosine of vec(v)) until top of atmosphere or planet's ground.
// r := height of starting point vect(x)
@@ -42,14 +55,14 @@ float opticalDepth(float r, float mu, float H) {
// direction and starting and ending points.
// cosine law for triangles: y_i^2 = a^2 + b^2 - 2abcos(alpha)
float cosZenithHorizon = -sqrt(1.0 - (Rg * Rg / r2));
float cosZenithHorizon = -sqrt(1.0 - ((Rg * Rg) / r2));
if (mu < cosZenithHorizon) {
return 1e9;
}
// Integrating using the Trapezoidal rule:
// Integral(f(y)dy)(from a to b) = ((b-a)/2n_steps)*(Sum(f(y_i+1)+f(y_i)))
float b_a = rayDistance(r, mu);
float b_a = rayDistance(r, mu, Rt, Rg);
float deltaStep = b_a / float(TRANSMITTANCE_STEPS);
// cosine law
float y_i = exp(-(r - Rg) / H);
@@ -72,11 +85,11 @@ void main() {
// In the paper u_r^2 = (r^2-Rg^2)/(Rt^2-Rg^2)
// So, extracting r from u_r in the above equation:
float r = Rg + (u_r * u_r) * RtMinusRg;
float r = Rg + (u_r * u_r) * (Rt - Rg);
// 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))
// But the below one is better. See Colliene.
// But the below one is better. See Collienne.
// One must remember that mu is defined from 0 to PI/2 + epsilon
float muSun = -0.15 + tan(1.5 * u_mu) / tan(1.5) * 1.15;

View File

@@ -1067,7 +1067,6 @@ void FramebufferRenderer::updateDeferredcastData() {
std::filesystem::path vsPath = caster->deferredcastVSPath();
std::filesystem::path fsPath = caster->deferredcastFSPath();
std::filesystem::path deferredShaderPath = caster->deferredcastPath();
ghoul::Dictionary dict;
dict.setValue("rendererData", _rendererData);
@@ -1086,17 +1085,10 @@ void FramebufferRenderer::updateDeferredcastData() {
_deferredcastPrograms[caster] = ghoul::opengl::ProgramObject::Build(
"Deferred " + std::to_string(data.id) + " raycast",
vsPath,
deferredShaderPath,
fsPath,
dict
);
_deferredcastPrograms[caster]->setIgnoreSubroutineUniformLocationError(
ghoul::opengl::ProgramObject::IgnoreError::Yes
);
_deferredcastPrograms[caster]->setIgnoreUniformLocationError(
ghoul::opengl::ProgramObject::IgnoreError::Yes
);
caster->initializeCachedVariables(*_deferredcastPrograms[caster]);
}
catch (ghoul::RuntimeError& e) {