From b41edb9c02c799025693b30bc7ff8ec38d789b43 Mon Sep 17 00:00:00 2001 From: Jonathas Costa Date: Sun, 8 Dec 2019 14:50:19 -0500 Subject: [PATCH] Added more control over shadow generation. Added documentation. Merged Master. --- .../globebrowsing/shaders/renderer_fs.glsl | 35 +++++++------ modules/globebrowsing/shaders/rings_fs.glsl | 33 ++++++------ modules/globebrowsing/src/renderableglobe.cpp | 28 +++++++++- modules/globebrowsing/src/renderableglobe.h | 20 +++++--- modules/globebrowsing/src/ringscomponent.cpp | 51 ++++++++++++++++++- modules/globebrowsing/src/ringscomponent.h | 5 +- modules/globebrowsing/src/shadowcomponent.cpp | 12 ++++- 7 files changed, 137 insertions(+), 47 deletions(-) diff --git a/modules/globebrowsing/shaders/renderer_fs.glsl b/modules/globebrowsing/shaders/renderer_fs.glsl index e3281fcedd..082f8630aa 100644 --- a/modules/globebrowsing/shaders/renderer_fs.glsl +++ b/modules/globebrowsing/shaders/renderer_fs.glsl @@ -62,6 +62,8 @@ uniform float orenNayarRoughness; #if SHADOW_MAPPING_ENABLED in vec4 shadowCoords; uniform sampler2DShadow shadowMapTexture; +uniform int nShadowSamples; +uniform float zFightingPercentage; #endif #if USE_ECLIPSE_SHADOWS @@ -267,26 +269,23 @@ Fragment getFragment() { float shadow = 1.0; if ( shadowCoords.w > 1 ) { vec4 normalizedShadowCoords = shadowCoords; - normalizedShadowCoords.z = normalizeFloat(normalizedShadowCoords.w - 0.005 * normalizedShadowCoords.w); - normalizedShadowCoords.xy = normalizedShadowCoords.xy / normalizedShadowCoords.w; - normalizedShadowCoords.w = 1.0; + normalizedShadowCoords.z = normalizeFloat(zFightingPercentage * normalizedShadowCoords.w); + normalizedShadowCoords.xy = normalizedShadowCoords.xy / normalizedShadowCoords.w; + normalizedShadowCoords.w = 1.0; - //shadow = textureProj(shadowMapTexture, normalizedShadowCoords); - - float sum = 0; - int fStep = 5; - for (int i = 0; i < fStep; ++i) { - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-fStep + i, -fStep + i)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-fStep + i, 0)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-fStep + i, fStep - i)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0, -fStep + i)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0, fStep - i)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( fStep - i, -fStep + i)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( fStep - i, 0)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( fStep - i, fStep - i)); + float sum = 0; + for (int i = 0; i < nShadowSamples; ++i) { + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, -nShadowSamples + i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, 0)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, nShadowSamples - i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0 , -nShadowSamples + i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0 , nShadowSamples - i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, -nShadowSamples + i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, 0)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, nShadowSamples - i)); } - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0, 0)); - shadow = sum / (8.f * fStep + 1.f); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(0, 0)); + shadow = sum / (8.f * nShadowSamples + 1.f); } frag.color.xyz *= shadow < 0.99 ? clamp(shadow + 0.5, 0.0, 1.0) : shadow; #endif diff --git a/modules/globebrowsing/shaders/rings_fs.glsl b/modules/globebrowsing/shaders/rings_fs.glsl index d1be63cef7..c31eef3ff4 100644 --- a/modules/globebrowsing/shaders/rings_fs.glsl +++ b/modules/globebrowsing/shaders/rings_fs.glsl @@ -37,6 +37,8 @@ uniform float transparency; uniform bool hasSunPosition; uniform vec3 sunPosition; uniform float _nightFactor; +uniform int nShadowSamples; +uniform float zFightingPercentage; // temp in vec4 fragPosInLightSpace; @@ -73,24 +75,23 @@ Fragment getFragment() { float shadow = 1.0; if ( shadowCoords.z >= 0 ) { vec4 normalizedShadowCoords = shadowCoords; - normalizedShadowCoords.z = normalizeFloat(normalizedShadowCoords.w - 0.005 * normalizedShadowCoords.w); - normalizedShadowCoords.xy = normalizedShadowCoords.xy / normalizedShadowCoords.w; - normalizedShadowCoords.w = 1.0; - - //shadow = textureProj(shadowMapTexture, normalizedShadowCoords); + normalizedShadowCoords.z = normalizeFloat(zFightingPercentage * normalizedShadowCoords.w); + normalizedShadowCoords.xy = normalizedShadowCoords.xy / normalizedShadowCoords.w; + normalizedShadowCoords.w = 1.0; float sum = 0; - int fStep = 2; - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-fStep, -fStep)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-fStep, 0)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-fStep, fStep)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0, -fStep)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0, 0)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0, fStep)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( fStep, -fStep)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( fStep, 0)); - sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( fStep, fStep)); - shadow = sum / 9.f; + for (int i = 0; i < nShadowSamples; ++i) { + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, -nShadowSamples + i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, 0)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(-nShadowSamples + i, nShadowSamples - i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0 , -nShadowSamples + i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( 0 , nShadowSamples - i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, -nShadowSamples + i)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, 0)); + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2( nShadowSamples - i, nShadowSamples - i)); + } + sum += textureProjOffset(shadowMapTexture, normalizedShadowCoords, ivec2(0, 0)); + shadow = sum / (8.f * nShadowSamples + 1.f); } // The normal for the one plane depends on whether we are dealing diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 191b351738..56477c915e 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -190,6 +190,20 @@ namespace { "Enables shadow mapping algorithm. Used by renderable rings too." }; + constexpr openspace::properties::Property::PropertyInfo ZFightingPercentageInfo = { + "ZFightingPercentage", + "Z-Fighting Percentage", + "The percentage of the correct distance to the surface being shadowed. " + "Possible values: [0.0, 1.0]" + }; + + constexpr openspace::properties::Property::PropertyInfo NumberShadowSamplesInfo = { + "NumberShadowSamples", + "Number of Shadow Samples", + "The number of samples used during shadow mapping calculation " + "(Percentage Closer Filtering)." + }; + constexpr openspace::properties::Property::PropertyInfo TargetLodScaleFactorInfo = { "TargetLodScaleFactor", "Target Level of Detail Scale Factor", @@ -502,12 +516,15 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) BoolProperty(EclipseInfo, false), BoolProperty(EclipseHardShadowsInfo, false), BoolProperty(ShadowMappingInfo, false), + FloatProperty(ZFightingPercentageInfo, 0.995f, 0.000001f, 1.f), + IntProperty(NumberShadowSamplesInfo, 5, 1, 20), FloatProperty(TargetLodScaleFactorInfo, 15.f, 1.f, 50.f), FloatProperty(CurrentLodScaleFactorInfo, 15.f, 1.f, 50.f), FloatProperty(CameraMinHeightInfo, 100.f, 0.f, 1000.f), FloatProperty(OrenNayarRoughnessInfo, 0.f, 0.f, 1.f), IntProperty(NActiveLayersInfo, 0, 0, OpenGLCap.maxTextureUnits() / 3) }) + , _shadowMappingPropertyOwner({ "Shadow Mapping" }) , _debugPropertyOwner({ "Debug" }) , _grid(DefaultSkirtedGridSegments, DefaultSkirtedGridSegments) , _leftRoot(Chunk(LeftHemisphereIndex)) @@ -544,7 +561,12 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) addProperty(_generalProperties.useAccurateNormals); addProperty(_generalProperties.eclipseShadowsEnabled); addProperty(_generalProperties.eclipseHardShadows); - addProperty(_generalProperties.shadowMapping); + + _shadowMappingPropertyOwner.addProperty(_generalProperties.shadowMapping); + _shadowMappingPropertyOwner.addProperty(_generalProperties.zFightingPercentage); + _shadowMappingPropertyOwner.addProperty(_generalProperties.nShadowSamples); + addPropertySubOwner(_shadowMappingPropertyOwner); + _generalProperties.targetLodScaleFactor.onChange([this]() { float sf = _generalProperties.targetLodScaleFactor; _generalProperties.currentLodScaleFactor = sf; @@ -1296,6 +1318,8 @@ void RenderableGlobe::renderChunkGlobally(const Chunk& chunk, const RenderData& glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture); program.setUniform("shadowMapTexture", shadowMapUnit); + program.setUniform("nShadowSamples", _generalProperties.nShadowSamples); + program.setUniform("zFightingPercentage", _generalProperties.zFightingPercentage); } glEnable(GL_DEPTH_TEST); @@ -1420,6 +1444,8 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d glBindTexture(GL_TEXTURE_2D, shadowData.shadowDepthTexture); program.setUniform("shadowMapTexture", shadowMapUnit); + program.setUniform("nShadowSamples", _generalProperties.nShadowSamples); + program.setUniform("zFightingPercentage", _generalProperties.zFightingPercentage); } glEnable(GL_DEPTH_TEST); diff --git a/modules/globebrowsing/src/renderableglobe.h b/modules/globebrowsing/src/renderableglobe.h index 60ee41413a..d21445e1f9 100644 --- a/modules/globebrowsing/src/renderableglobe.h +++ b/modules/globebrowsing/src/renderableglobe.h @@ -129,25 +129,29 @@ private: properties::BoolProperty showHeightIntensities; properties::BoolProperty levelByProjectedAreaElseDistance; properties::BoolProperty resetTileProviders; - properties::IntProperty modelSpaceRenderingCutoffLevel; - properties::IntProperty dynamicLodIterationCount; + properties::IntProperty modelSpaceRenderingCutoffLevel; + properties::IntProperty dynamicLodIterationCount; } _debugProperties; struct { - properties::BoolProperty performShading; - properties::BoolProperty useAccurateNormals; - properties::BoolProperty eclipseShadowsEnabled; - properties::BoolProperty eclipseHardShadows; - properties::BoolProperty shadowMapping; + properties::BoolProperty performShading; + properties::BoolProperty useAccurateNormals; + properties::BoolProperty eclipseShadowsEnabled; + properties::BoolProperty eclipseHardShadows; + properties::BoolProperty shadowMapping; + properties::FloatProperty zFightingPercentage; + properties::IntProperty nShadowSamples; properties::FloatProperty targetLodScaleFactor; properties::FloatProperty currentLodScaleFactor; properties::FloatProperty cameraMinHeight; properties::FloatProperty orenNayarRoughness; - properties::IntProperty nActiveLayers; + properties::IntProperty nActiveLayers; } _generalProperties; properties::PropertyOwner _debugPropertyOwner; + properties::PropertyOwner _shadowMappingPropertyOwner; + /** * Test if a specific chunk can safely be culled without affecting the rendered * image. diff --git a/modules/globebrowsing/src/ringscomponent.cpp b/modules/globebrowsing/src/ringscomponent.cpp index 699201e654..c9f20cdb41 100644 --- a/modules/globebrowsing/src/ringscomponent.cpp +++ b/modules/globebrowsing/src/ringscomponent.cpp @@ -56,9 +56,10 @@ #include namespace { - constexpr const std::array UniformNames = { + constexpr const std::array UniformNames = { "modelViewProjectionMatrix", "textureOffset", "transparency", "_nightFactor", - "sunPosition", "ringTexture", "shadowMatrix", "shadowMapTexture" + "sunPosition", "ringTexture", "shadowMatrix", "shadowMapTexture", + "nShadowSamples", "zFightingPercentage" }; constexpr const std::array GeomUniformNames = { @@ -101,6 +102,20 @@ namespace { "This value determines the transparency of part of the rings depending on the " "color values. For this value v, the transparency is equal to length(color) / v." }; + + constexpr openspace::properties::Property::PropertyInfo ZFightingPercentageInfo = { + "ZFightingPercentage", + "Z-Fighting Percentage", + "The percentage of the correct distance to the surface being shadowed. " + "Possible values: [0.0, 1.0]" + }; + + constexpr openspace::properties::Property::PropertyInfo NumberShadowSamplesInfo = { + "NumberShadowSamples", + "Number of Shadow Samples", + "The number of samples used during shadow mapping calculation " + "(Percentage Closer Filtering)." + }; } // namespace namespace openspace { @@ -140,6 +155,18 @@ namespace openspace { new DoubleVerifier, Optional::Yes, TransparencyInfo.description + }, + { + ZFightingPercentageInfo.identifier, + new DoubleVerifier, + Optional::Yes, + ZFightingPercentageInfo.description + }, + { + NumberShadowSamplesInfo.identifier, + new IntVerifier, + Optional::Yes, + NumberShadowSamplesInfo.description } } }; @@ -153,6 +180,8 @@ namespace openspace { , _nightFactor(NightFactorInfo, 0.33f, 0.f, 1.f) , _transparency(TransparencyInfo, 0.15f, 0.f, 1.f) , _enabled({ "Enabled", "Enabled", "Enable/Disable Rings" }, true) + , _zFightingPercentage(ZFightingPercentageInfo, 0.995f, 0.000001f, 1.f) + , _nShadowSamples(NumberShadowSamplesInfo, 2, 1, 20) , _ringsDictionary(dictionary) { using ghoul::filesystem::File; @@ -204,6 +233,22 @@ namespace openspace { _ringsDictionary.value(TransparencyInfo.identifier) ); } + + // Shadow Mapping Quality Controls + if (_ringsDictionary.hasKey(ZFightingPercentageInfo.identifier)) { + _zFightingPercentage = _ringsDictionary.value( + ZFightingPercentageInfo.identifier + ); + } + addProperty(_zFightingPercentage); + + if (_ringsDictionary.hasKey(NumberShadowSamplesInfo.identifier)) { + _nShadowSamples = _ringsDictionary.value( + NumberShadowSamplesInfo.identifier + ); + } + addProperty(_nShadowSamples); + addProperty(_transparency); } @@ -287,6 +332,8 @@ namespace openspace { _shader->setUniform(_uniformCache.transparency, _transparency); _shader->setUniform(_uniformCache.nightFactor, _nightFactor); _shader->setUniform(_uniformCache.sunPosition, _sunPosition); + _shader->setUniform(_uniformCache.nShadowSamples, _nShadowSamples); + _shader->setUniform(_uniformCache.zFightingPercentage, _zFightingPercentage); ringTextureUnit.activate(); _texture->bind(); diff --git a/modules/globebrowsing/src/ringscomponent.h b/modules/globebrowsing/src/ringscomponent.h index 0b4d796bf9..4804af9ae3 100644 --- a/modules/globebrowsing/src/ringscomponent.h +++ b/modules/globebrowsing/src/ringscomponent.h @@ -92,11 +92,14 @@ namespace openspace { properties::FloatProperty _nightFactor; properties::FloatProperty _transparency; properties::BoolProperty _enabled; + properties::FloatProperty _zFightingPercentage; + properties::IntProperty _nShadowSamples; std::unique_ptr _shader; std::unique_ptr _geometryOnlyShader; UniformCache(modelViewProjectionMatrix, textureOffset, transparency, nightFactor, - sunPosition, ringTexture, shadowMatrix, shadowMapTexture + sunPosition, ringTexture, shadowMatrix, shadowMapTexture, + nShadowSamples, zFightingPercentage ) _uniformCache; UniformCache(modelViewProjectionMatrix, textureOffset, ringTexture) _geomUniformCache; diff --git a/modules/globebrowsing/src/shadowcomponent.cpp b/modules/globebrowsing/src/shadowcomponent.cpp index f857588011..da2d166bd6 100644 --- a/modules/globebrowsing/src/shadowcomponent.cpp +++ b/modules/globebrowsing/src/shadowcomponent.cpp @@ -163,13 +163,19 @@ namespace openspace { new DoubleVerifier, Optional::Yes, DistanceFractionInfo.description + }, + { + DepthMapSizeInfo.identifier, + new Vector2ListVerifier, + Optional::Yes, + DepthMapSizeInfo.description } } }; } ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary) - : properties::PropertyOwner({ "Shadows" }) + : properties::PropertyOwner({ "Shadows Component" }) , _saveDepthTexture(SaveDepthTextureInfo) , _distanceFraction(DistanceFractionInfo, 20, 1, 10000) , _enabled({ "Enabled", "Enabled", "Enable/Disable Shadows" }, true) @@ -222,6 +228,10 @@ namespace openspace { _dynamicDepthTextureRes = true; } + _saveDepthTexture.onChange([&]() { + _executeDepthTextureSave = true; + }); + _viewDepthMap = false; addProperty(_enabled);