From d9c071a2a9a6ed4c471a0efa498330b942724baf Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Tue, 10 Mar 2015 00:47:27 -0700 Subject: [PATCH] trying to put the atmospheric effect in a shader header and use it on the directional lighting pass --- libraries/gpu/src/gpu/Pipeline.h | 2 +- libraries/model/src/model/Atmosphere.slh | 244 ++++++++++++++++++ libraries/model/src/model/Stage.cpp | 50 ++++ libraries/model/src/model/Stage.h | 56 ++++ .../render-utils/src/DeferredGlobalLight.slh | 10 + .../src/DeferredLightingEffect.cpp | 31 +++ .../render-utils/src/DeferredLightingEffect.h | 4 + tools/scribe/src/main.cpp | 12 +- 8 files changed, 406 insertions(+), 3 deletions(-) create mode 100755 libraries/model/src/model/Atmosphere.slh diff --git a/libraries/gpu/src/gpu/Pipeline.h b/libraries/gpu/src/gpu/Pipeline.h index c2fc944bb7..faa671c30f 100755 --- a/libraries/gpu/src/gpu/Pipeline.h +++ b/libraries/gpu/src/gpu/Pipeline.h @@ -44,7 +44,7 @@ protected: friend class Backend; }; -typedef QSharedPointer< Pipeline > PipelinePointer; +typedef std::shared_ptr< Pipeline > PipelinePointer; typedef std::vector< PipelinePointer > Pipelines; }; diff --git a/libraries/model/src/model/Atmosphere.slh b/libraries/model/src/model/Atmosphere.slh new file mode 100755 index 0000000000..11b64dde70 --- /dev/null +++ b/libraries/model/src/model/Atmosphere.slh @@ -0,0 +1,244 @@ + +<@if not MODEL_ATMOSPHERE_SLH@> +<@def MODEL_ATMOSPHERE_SLH@> + + + +struct Atmosphere { + vec4 _invWaveLength; + vec4 _radiuses; + vec4 _scales; + vec4 _scatterings; + vec4 _control; +}; + +const int numSamples = 2; + +vec3 getAtmosphereInvWaveLength(Atmosphere a) { return a._invWaveLength.xyz; } // 1 / pow(wavelength, 4) for the red, green, and blue channels + +float getAtmosphereInnerRadius(Atmosphere a) { return a._radiuses.x; } // The inner (planetary) radius +float getAtmosphereOuterRadius(Atmosphere a) { return a._radiuses.y; } // The outer (atmosphere) radius + +float getAtmosphereScale(Atmosphere a) { return a._scales.x; } // 1 / (outerRadius - innerRadius) +float getAtmosphereScaleDepth(Atmosphere a) { return a._scales.y; } // The scale depth (i.e. the altitude at which the atmosphere's average density is found) +float getAtmosphereScaleOverScaleDepth(Atmosphere a) { return a._scales.z; } // scale / scaleDepth + +vec4 getAtmosphereScattering(Atmosphere a) { return a._scatterings; } // The full Mie and Rayleigh scattering coefficients +float getAtmosphereKrESun(Atmosphere a) { return a._scatterings.x; } // Kr * ESun +float getAtmosphereKmESun(Atmosphere a) { return a._scatterings.y; } // Km * ESun +float getAtmosphereKr4PI(Atmosphere a) { return a._scatterings.z; } // Kr * 4 * PI +float getAtmosphereKm4PI(Atmosphere a) { return a._scatterings.w; } // Km * 4 * PI + +float getAtmosphereNumSamples(Atmosphere a) { return a._control.x; } // numSamples +vec2 getAtmosphereGAndG2(Atmosphere a) { return a._control.yz; } // g and g2 + +float atmosphereScale(float scaleDepth, float fCos) +{ + float x = 1.0 - fCos; + return scaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); +} + +vec4 evalAtmosphereContribution(Atmosphere atmospheric, vec3 position, vec3 cameraPos, vec3 lightPos) { + float fInnerRadius = getAtmosphereInnerRadius(atmospheric); + float fSamples = getAtmosphereNumSamples(atmospheric); + + vec3 v3InvWavelength = getAtmosphereInvWaveLength(atmospheric); + vec4 scatteringCoefs = getAtmosphereScattering(atmospheric); + float fKrESun = scatteringCoefs.x; + float fKmESun = scatteringCoefs.y; + float fKr4PI = scatteringCoefs.z; + float fKm4PI = scatteringCoefs.w; + + vec2 gAndg2 = getAtmosphereGAndG2(atmospheric); + float g = gAndg2.x; + float g2 = gAndg2.y; + + float fScale = getAtmosphereScale(atmospheric); + float fScaleDepth = getAtmosphereScaleDepth(atmospheric); + float fScaleOverScaleDepth = getAtmosphereScaleOverScaleDepth(atmospheric); + + // Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere) + vec3 v3Pos = position; + vec3 v3Ray = v3Pos - cameraPos; + float fFar = length(v3Ray); + v3Ray /= fFar; + + // Calculate the ray's starting position, then calculate its scattering offset + vec3 v3Start = cameraPos; + float fHeight = length(v3Start); + float fDepthStart = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); + float fStartAngle = dot(v3Ray, v3Start) / fHeight; + float fStartOffset = fDepthStart * atmosphereScale(fScaleDepth, fStartAngle); + + // Initialize the scattering loop variables + //gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0); + float fSampleLength = fFar / fSamples; + float fScaledLength = fSampleLength * fScale; + vec3 v3SampleRay = v3Ray * fSampleLength; + vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; + + // Now loop through the sample rays + vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); + int nSamples = numSamples; + // int nSamples = int(fSamples); + for(int i=0; i +uniform atmosphereBuffer { + Atmosphere _atmosphere; +}; +Atmosphere getAtmosphere() { + return _atmosphere; +} +<@else@> +uniform vec4 atmosphereBuffer[9]; +Atmosphere getAtmosphere() { + Atmosphere atmosphere; + atmosphere._invWaveLength = atmosphereBuffer[0]; + atmosphere._radiuses = atmosphereBuffer[1]; + atmosphere._scales = atmosphereBuffer[2]; + atmosphere._scatterings = atmosphereBuffer[3]; + atmosphere._control = atmosphereBuffer[4]; + + return atmosphere; +} +<@endif@> + + + +<@endif@> diff --git a/libraries/model/src/model/Stage.cpp b/libraries/model/src/model/Stage.cpp index 473d3c7613..970539a908 100644 --- a/libraries/model/src/model/Stage.cpp +++ b/libraries/model/src/model/Stage.cpp @@ -134,6 +134,56 @@ void EarthSunModel::setSunLongitude(float lon) { _sunLongitude = validateLongitude(lon); invalidate(); } + +Atmosphere::Atmosphere() { + // only if created from nothing shall we create the Buffer to store the properties + Data data; + _dataBuffer = gpu::BufferView(new gpu::Buffer(sizeof(Data), (const gpu::Buffer::Byte*) &data)); + + setScatteringWavelength(_scatteringWavelength); + setRayleighScattering(_rayleighScattering); + setInnerOuterRadiuses(getInnerRadius(), getOuterRadius()); +} + +void Atmosphere::setScatteringWavelength(Vec3 wavelength) { + _scatteringWavelength = wavelength; + Data& data = editData(); + data._invWaveLength = Vec4(1.0f / powf(wavelength.x, 4.0f), 1.0f / powf(wavelength.y, 4.0f), 1.0f / powf(wavelength.z, 4.0f), 0.0f); +} + +void Atmosphere::setRayleighScattering(float scattering) { + _rayleighScattering = scattering; + updateScattering(); +} + +void Atmosphere::setMieScattering(float scattering) { + _mieScattering = scattering; + updateScattering(); +} + +void Atmosphere::setSunBrightness(float brightness) { + _sunBrightness = brightness; + updateScattering(); +} + +void Atmosphere::updateScattering() { + Data& data = editData(); + + data._scatterings.x = getRayleighScattering() * getSunBrightness(); + data._scatterings.y = getMieScattering() * getSunBrightness(); + + data._scatterings.z = getRayleighScattering() * 4.0f * glm::pi(); + data._scatterings.w = getMieScattering() * 4.0f * glm::pi(); +} + +void Atmosphere::setInnerOuterRadiuses(float inner, float outer) { + Data& data = editData(); + data._radiuses.x = inner; + data._radiuses.y = outer; + data._scales.x = 1.0f / (outer - inner); + data._scales.z = data._scales.x / data._scales.y; +} + const int NUM_DAYS_PER_YEAR = 365; const float NUM_HOURS_PER_DAY = 24.0f; diff --git a/libraries/model/src/model/Stage.h b/libraries/model/src/model/Stage.h index 61914b5a6b..3cc8b4a6e9 100644 --- a/libraries/model/src/model/Stage.h +++ b/libraries/model/src/model/Stage.h @@ -106,6 +106,60 @@ protected: static Mat4d evalWorldToGeoLocationMat(double longitude, double latitude, double altitude, double scale); }; + +class Atmosphere { +public: + + Atmosphere(); + Atmosphere(const Atmosphere& atmosphere); + Atmosphere& operator= (const Atmosphere& atmosphere); + virtual ~Atmosphere() {}; + + + void setScatteringWavelength(Vec3 wavelength); + const Vec3& getScatteringWavelength() const { return _scatteringWavelength; } + + void setRayleighScattering(float scattering); + float getRayleighScattering() const { return _rayleighScattering; } + + void setMieScattering(float scattering); + float getMieScattering() const { return _mieScattering; } + + void setSunBrightness(float brightness); + float getSunBrightness() const { return _sunBrightness; } + + void setInnerOuterRadiuses(float inner, float outer); + float getInnerRadius() const { return getData()._radiuses.x; } + float getOuterRadius() const { return getData()._radiuses.y; } + + // Data to access the attribute values of the atmosphere + class Data { + public: + Vec4 _invWaveLength = Vec4(0.0f); + Vec4 _radiuses = Vec4(6000.0f, 6025.0f, 0.0f, 0.0f); + Vec4 _scales = Vec4(0.0f, 0.25f, 0.0f, 0.0f); + Vec4 _scatterings = Vec4(0.0f); + Vec4 _control = Vec4(2.0f, -0.990f, -0.990f*-0.990f, 0.f); + + Data() {} + }; + + const UniformBufferView& getDataBuffer() const { return _dataBuffer; } + +protected: + UniformBufferView _dataBuffer; + Vec3 _scatteringWavelength = Vec3(0.650f, 0.570f, 0.475f); + float _rayleighScattering = 0.0025f; + float _mieScattering = 0.0010f; + float _sunBrightness = 20.0f; + + const Data& getData() const { return _dataBuffer.get(); } + Data& editData() { return _dataBuffer.edit(); } + + void updateScattering(); +}; +typedef QSharedPointer< Atmosphere > AtmospherePointer; + // Sun sky stage generates the rendering primitives to display a scene realistically // at the specified location and time around earth class SunSkyStage { @@ -141,9 +195,11 @@ public: float getSunIntensity() const { return getSunLight()->getIntensity(); } LightPointer getSunLight() const { valid(); return _sunLight; } + AtmospherePointer getAtmosphere() const { valid(); return _atmosphere; } protected: LightPointer _sunLight; + AtmospherePointer _atmosphere; gpu::PipelinePointer _skyPipeline; diff --git a/libraries/render-utils/src/DeferredGlobalLight.slh b/libraries/render-utils/src/DeferredGlobalLight.slh index 3039c92d67..b48b61fd9f 100755 --- a/libraries/render-utils/src/DeferredGlobalLight.slh +++ b/libraries/render-utils/src/DeferredGlobalLight.slh @@ -13,6 +13,7 @@ <@include DeferredLighting.slh@> + struct SphericalHarmonics { vec4 L00; vec4 L1m1; @@ -50,6 +51,7 @@ uniform SphericalHarmonics ambientSphere; // Everything about light <@include model/Light.slh@> +<@include model/Atmosphere.slh@> // The view Matrix uniform mat4 invViewMat; @@ -89,6 +91,14 @@ vec3 evalAmbienSphereGlobalColor(float shadowAttenuation, vec3 position, vec3 no color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + + vec3 fragPos = vec3(invViewMat * vec4(position, 1.0)); + vec3 cameraPos = invViewMat[3].xyz; + vec3 lightPos = 10000.0 * getLightDirection(light); + + Atmosphere atmo = getAtmosphere(); + vec4 atmoColor = evalAtmosphereContribution(atmo, fragPos, cameraPos, lightPos); + return color; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index c8ad3711d3..96ab790cd6 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -270,6 +270,12 @@ void DeferredLightingEffect::render() { batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } + + if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) { + gpu::Batch batch; + batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer()); + gpu::GLBackend::renderBatch(batch); + } glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); } @@ -511,6 +517,31 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit locations.lightBufferUnit = -1; } #endif + +#if defined(Q_OS_MAC) + loc = program.uniformLocation("atmosphereBufferUnit"); + if (loc >= 0) { + locations.atmosphereBufferUnit = loc; + } else { + locations.atmosphereBufferUnit = -1; + } +#elif defined(Q_OS_WIN) + loc = glGetUniformBlockIndex(program.programId(), "atmosphereBufferUnit"); + if (loc >= 0) { + glUniformBlockBinding(program.programId(), loc, 1); + locations.atmosphereBufferUnit = 1; + } else { + locations.atmosphereBufferUnit = -1; + } +#else + loc = program.uniformLocation("atmosphereBufferUnit"); + if (loc >= 0) { + locations.atmosphereBufferUnit = loc; + } else { + locations.atmosphereBufferUnit = -1; + } +#endif + program.release(); } diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 951c36f038..900c5243cb 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -20,6 +20,7 @@ #include "ProgramObject.h" #include "model/Light.h" +#include "model/Stage.h" class AbstractViewStateInterface; class PostLightingRenderable; @@ -73,6 +74,7 @@ public: // update global lighting void setAmbientLightMode(int preset); void setGlobalLight(const glm::vec3& direction, const glm::vec3& diffuse, float intensity); + void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } private: DeferredLightingEffect() {} @@ -89,6 +91,7 @@ private: int radius; int ambientSphere; int lightBufferUnit; + int atmosphereBufferUnit; int invViewMat; }; @@ -146,6 +149,7 @@ private: AbstractViewStateInterface* _viewState; int _ambientLightMode = 0; + model::AtmospherePointer _atmosphere; }; /// Simple interface for objects that require something to be rendered after deferred lighting. diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index f68272c0ab..10f0a026ca 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -192,9 +192,17 @@ int main (int argc, char** argv) { targetStringStream << "#ifndef scribe_" << targetName << "_h" << std::endl; targetStringStream << "#define scribe_" << targetName << "_h" << std::endl << std::endl; - targetStringStream << "const char " << targetName << "[] = R\"XXXX(" << destStringStream.str() << ")XXXX\";"; + // targetStringStream << "const char " << targetName << "[] = R\"XXXX(" << destStringStream.str() << ")XXXX\";"; + std::istringstream destStringStreamAgain(destStringStream.str()); + targetStringStream << "const char " << targetName << "[] = \n"; + while (!destStringStreamAgain.eof()) { + std::string lineToken; + std::getline(destStringStreamAgain, lineToken); + // targetStringStream << "\"" << lineToken << "\"\n"; + targetStringStream << "R\"X(" << lineToken << ")X\"\"\\n\"\n"; + } - targetStringStream << std::endl << std::endl; + targetStringStream << ";\n" << std::endl << std::endl; targetStringStream << "#endif" << std::endl; } else { targetStringStream << destStringStream.str();