mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-10 05:32:18 -06:00
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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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__
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "atmosphere_common.glsl"
|
||||
|
||||
out vec4 renderTableColor;
|
||||
|
||||
void main() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,10 +24,9 @@
|
||||
|
||||
#version __CONTEXT__
|
||||
|
||||
#include "atmosphere_common.glsl"
|
||||
|
||||
out vec4 renderTableColor;
|
||||
|
||||
uniform ivec2 OTHER_TEXTURES;
|
||||
uniform sampler2D deltaETexture;
|
||||
|
||||
void main() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user