From 0edc8fc77d054d4e818a2bc60d7b20a132ae25f4 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 5 Feb 2023 00:40:33 +0000 Subject: [PATCH 1/6] Don't use FFP-friendly texture image units for shadow maps This more-or-less gets rid of the shadow system's only depencency on FFP stuff. All that remains is it using OSG cameras, which OSG provides a uniform-based implementation of, too, which we can trivially migrate to. This should mean we're not eating any of the ~8 FPP-friendly texture units, which is good as Morrowind models can use all of those on their (although they very rarely do), and instead use some of the ~160 shader-only texture image units. This just requires not calling glEnable(GL_TEXTURE_2D), accomplished by changing setTextureAttributeAndModes to setTextureAttribute. Also changes from using glTexGen and its eye plane matrices to pass the shadow space matrix for each light to explicit uniforms. Thankfully, the maths was a simple combination of the valid region matrix and eye plane matrix maths. As of this commit, I believe this kills shadows in one eye for stereo rendering. --- components/sceneutil/mwshadowtechnique.cpp | 83 ++++++++-------------- components/sceneutil/mwshadowtechnique.hpp | 5 -- components/sceneutil/shadow.cpp | 2 +- files/shaders/shadows_vertex.glsl | 14 ++-- 4 files changed, 35 insertions(+), 69 deletions(-) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index d9a3c9270a..6b12af0e78 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -537,9 +537,6 @@ MWShadowTechnique::ShadowData::ShadowData(MWShadowTechnique::ViewDependentData* bool debug = settings->getDebugDraw(); - // set up texgen - _texgen = new osg::TexGen; - // set up the texture _texture = new osg::Texture2D; @@ -994,8 +991,6 @@ void SceneUtil::MWShadowTechnique::copyShadowMap(osgUtil::CullVisitor& cv, ViewD sdl.push_back(lhs_sd); } - assignTexGenSettings(cv, lhs); - if (lhs->_numValidShadows > 0) { prepareStateSetForRenderingShadow(*lhs, cv.getTraversalNumber()); @@ -1007,13 +1002,6 @@ void SceneUtil::MWShadowTechnique::setCustomFrustumCallback(CustomFrustumCallbac _customFrustumCallback = cfc; } -void SceneUtil::MWShadowTechnique::assignTexGenSettings(osgUtil::CullVisitor& cv, ViewDependentData* vdd) -{ - for (const auto& sd : vdd->getShadowDataList()) - { - assignTexGenSettings(&cv, sd->_camera, sd->_textureUnit, sd->_texgen); - } -} void MWShadowTechnique::update(osg::NodeVisitor& nv) { @@ -1035,7 +1023,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) int endUnit = baseUnit + settings->getNumShadowMapsPerLight(); for (int i = baseUnit; i < endUnit; ++i) { - dummyState->setTextureAttributeAndModes(i, _fallbackShadowMapTexture, osg::StateAttribute::ON); + dummyState->setTextureAttribute(i, _fallbackShadowMapTexture, osg::StateAttribute::ON); dummyState->addUniform(new osg::Uniform(("shadowTexture" + std::to_string(i - baseUnit)).c_str(), i)); dummyState->addUniform(new osg::Uniform(("shadowTextureUnit" + std::to_string(i - baseUnit)).c_str(), i)); } @@ -1548,7 +1536,30 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) // 4.4 compute main scene graph TexGen + uniform settings + setup state // - assignTexGenSettings(&cv, camera.get(), textureUnit, sd->_texgen.get()); + { + osg::Matrix shadowSpaceMatrix = cv.getCurrentCamera()->getInverseViewMatrix() * + camera->getViewMatrix() * + camera->getProjectionMatrix() * + osg::Matrix::translate(1.0,1.0,1.0) * + osg::Matrix::scale(0.5,0.5,0.5); + + std::string shadowSpaceUniformName = "shadowSpaceMatrix" + std::to_string(sm_i); + osg::ref_ptr shadowSpaceUniform; + + for (const auto & uniform : _uniforms[cv.getTraversalNumber() % 2]) + { + if (uniform->getName() == shadowSpaceUniformName) + shadowSpaceUniform = uniform; + } + + if (!shadowSpaceUniform) + { + shadowSpaceUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, shadowSpaceUniformName); + _uniforms[cv.getTraversalNumber() % 2].push_back(shadowSpaceUniform); + } + + shadowSpaceUniform->set(shadowSpaceMatrix); + } // mark the light as one that has active shadows and requires shaders pl.textureUnits.push_back(textureUnit); @@ -1556,14 +1567,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) // pass on shadow data to ShadowDataList sd->_textureUnit = textureUnit; - if (textureUnit >= 8) - { - OSG_NOTICE<<"Shadow texture unit is invalid for texgen, will not be used."<setAttributeAndModes(_castingPrograms[GL_ALWAYS - GL_NEVER], osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); // The casting program uses a sampler, so to avoid undefined behaviour, we must bind a dummy texture in case no other is supplied - _shadowCastingStateSet->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); + _shadowCastingStateSet->setTextureAttribute(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON); _shadowCastingStateSet->addUniform(new osg::Uniform("useDiffuseMapForShadowAlpha", true)); _shadowCastingStateSet->addUniform(new osg::Uniform("alphaTestShadows", false)); osg::ref_ptr depth = new osg::Depth; @@ -3081,28 +3085,6 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render return true; } -bool MWShadowTechnique::assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen) -{ - OSG_INFO<<"assignTexGenSettings() textureUnit="<setTextureAttributeAndModes(sd._textureUnit, sd._texture.get(), shadowMapModeValue); - - stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON); - stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON); - stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON); - stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON); + stateset->setTextureAttribute(sd._textureUnit, sd._texture.get(), shadowMapModeValue); } return stateset; @@ -3304,7 +3281,7 @@ void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr t addAnotherShadowMap(); osg::ref_ptr stateSet = new osg::StateSet(); - stateSet->setTextureAttributeAndModes(sDebugTextureUnit, texture, osg::StateAttribute::ON); + stateSet->setTextureAttribute(sDebugTextureUnit, texture, osg::StateAttribute::ON); auto frustumUniform = mFrustumUniforms[cv.getTraversalNumber() % 2][shadowMapNumber]; frustumUniform->set(matrix); @@ -3317,8 +3294,6 @@ void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr t mDebugCameras[shadowMapNumber]->accept(cv); cv.popStateSet(); cv.setTraversalMask(traversalMask); - - // cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE); } void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) const diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 36cf83c68a..8b39818e2e 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -193,7 +193,6 @@ namespace SceneUtil { unsigned int _textureUnit; osg::ref_ptr _texture; - osg::ref_ptr _texgen; osg::ref_ptr _camera; }; @@ -241,8 +240,6 @@ namespace SceneUtil { void setCustomFrustumCallback(CustomFrustumCallback* cfc); - void assignTexGenSettings(osgUtil::CullVisitor& cv, ViewDependentData* vdd); - virtual void createShaders(); virtual bool selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const; @@ -255,8 +252,6 @@ namespace SceneUtil { virtual bool adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& positionedLight, osg::Camera* camera, double viewNear, double viewFar); - virtual bool assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen); - virtual void cullShadowReceivingScene(osgUtil::CullVisitor* cv) const; virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 702159c3f9..44c0d3d27a 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -32,7 +32,7 @@ namespace SceneUtil = std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8); mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); - mShadowSettings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); + mShadowSettings->setBaseShadowTextureUnit(osg::GLExtensions::Get(0, false)->glMaxTextureUnits - numberOfShadowMapsPerLight); const float maximumShadowMapDistance = Settings::Manager::getFloat("maximum shadow map distance", "Shadows"); if (maximumShadowMapDistance > 0) diff --git a/files/shaders/shadows_vertex.glsl b/files/shaders/shadows_vertex.glsl index f96e1a6735..08daf620bf 100644 --- a/files/shaders/shadows_vertex.glsl +++ b/files/shaders/shadows_vertex.glsl @@ -2,6 +2,7 @@ #if SHADOWS @foreach shadow_texture_unit_index @shadow_texture_unit_list + uniform mat4 shadowSpaceMatrix@shadow_texture_unit_index; uniform int shadowTextureUnit@shadow_texture_unit_index; varying vec4 shadowSpaceCoords@shadow_texture_unit_index; @@ -19,33 +20,28 @@ void setupShadowCoords(vec4 viewPos, vec3 viewNormal) { #if SHADOWS // This matrix has the opposite handedness to the others used here, so multiplication must have the vector to the left. Alternatively it could be transposed after construction, but that's extra work for the GPU just to make the code look a tiny bit cleaner. - mat4 eyePlaneMat; vec4 shadowOffset; @foreach shadow_texture_unit_index @shadow_texture_unit_list - eyePlaneMat = mat4(gl_EyePlaneS[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneT[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneR[shadowTextureUnit@shadow_texture_unit_index], gl_EyePlaneQ[shadowTextureUnit@shadow_texture_unit_index]); - #if @perspectiveShadowMaps shadowRegionCoords@shadow_texture_unit_index = validRegionMatrix@shadow_texture_unit_index * viewPos; #endif - + #if @disableNormalOffsetShadows - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; + shadowSpaceCoords@shadow_texture_unit_index = shadowSpaceMatrix@shadow_texture_unit_index * viewPos; #else shadowOffset = vec4(viewNormal * @shadowNormalOffset, 0.0); if (onlyNormalOffsetUV) { - shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; - vec4 lightSpaceXY = viewPos + shadowOffset; - lightSpaceXY = lightSpaceXY * eyePlaneMat; + lightSpaceXY = shadowSpaceMatrix@shadow_texture_unit_index * lightSpaceXY; shadowSpaceCoords@shadow_texture_unit_index.xy = lightSpaceXY.xy; } else { vec4 offsetViewPosition = viewPos + shadowOffset; - shadowSpaceCoords@shadow_texture_unit_index = offsetViewPosition * eyePlaneMat; + shadowSpaceCoords@shadow_texture_unit_index = shadowSpaceMatrix@shadow_texture_unit_index * offsetViewPosition; } #endif @endforeach From 80d6f6bc97afa02f6343411d5d824abd2a911535 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Sun, 5 Feb 2023 02:07:00 +0000 Subject: [PATCH 2/6] Add line break that clang-format wanted --- components/sceneutil/shadow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 44c0d3d27a..83a870f7fe 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -32,7 +32,8 @@ namespace SceneUtil = std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8); mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); - mShadowSettings->setBaseShadowTextureUnit(osg::GLExtensions::Get(0, false)->glMaxTextureUnits - numberOfShadowMapsPerLight); + mShadowSettings->setBaseShadowTextureUnit( + osg::GLExtensions::Get(0, false)->glMaxTextureUnits - numberOfShadowMapsPerLight); const float maximumShadowMapDistance = Settings::Manager::getFloat("maximum shadow map distance", "Shadows"); if (maximumShadowMapDistance > 0) From 9be3d2668adb2a401e592f55c1d57ccdee579669 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Tue, 7 Feb 2023 22:19:53 +0000 Subject: [PATCH 3/6] Break out of loops when uniform is found --- components/sceneutil/mwshadowtechnique.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 6b12af0e78..f36888ec44 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -1512,7 +1512,10 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) for (const auto & uniform : _uniforms[cv.getTraversalNumber() % 2]) { if (uniform->getName() == validRegionUniformName) + { validRegionUniform = uniform; + break; + } } if (!validRegionUniform) @@ -1549,7 +1552,10 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv) for (const auto & uniform : _uniforms[cv.getTraversalNumber() % 2]) { if (uniform->getName() == shadowSpaceUniformName) + { shadowSpaceUniform = uniform; + break; + } } if (!shadowSpaceUniform) From 7d4410d4fb3e6938e2a13e69f2907127249e543f Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Thu, 9 Feb 2023 01:32:48 +0000 Subject: [PATCH 4/6] Use reserveGlobalTextureUnits for shadow maps --- components/sceneutil/shadow.cpp | 7 +++---- components/sceneutil/shadow.hpp | 2 +- components/shader/shadermanager.cpp | 29 +++++++++++------------------ components/shader/shadermanager.hpp | 7 +++++-- 4 files changed, 20 insertions(+), 25 deletions(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 83a870f7fe..b9f2cbd831 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -13,7 +13,7 @@ namespace SceneUtil { using namespace osgShadow; - void ShadowManager::setupShadowSettings() + void ShadowManager::setupShadowSettings(Shader::ShaderManager& shaderManager) { mEnableShadows = Settings::Manager::getBool("enable shadows", "Shadows"); @@ -32,8 +32,7 @@ namespace SceneUtil = std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8); mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); - mShadowSettings->setBaseShadowTextureUnit( - osg::GLExtensions::Get(0, false)->glMaxTextureUnits - numberOfShadowMapsPerLight); + mShadowSettings->setBaseShadowTextureUnit(shaderManager.reserveGlobalTextureUnits(Shader::ShaderManager::Slot::ShadowMaps, numberOfShadowMapsPerLight)); const float maximumShadowMapDistance = Settings::Manager::getFloat("maximum shadow map distance", "Shadows"); if (maximumShadowMapDistance > 0) @@ -122,7 +121,7 @@ namespace SceneUtil mShadowedScene->setNodeMask(sceneRoot->getNodeMask()); mShadowSettings = mShadowedScene->getShadowSettings(); - setupShadowSettings(); + setupShadowSettings(shaderManager); mShadowTechnique->setupCastingShader(shaderManager); mShadowTechnique->setWorldMask(worldMask); diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index c969ca331f..76fd2b7fdd 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -29,7 +29,7 @@ namespace SceneUtil Shader::ShaderManager& shaderManager); ~ShadowManager(); - void setupShadowSettings(); + void setupShadowSettings(Shader::ShaderManager& shaderManager); Shader::ShaderManager::DefineMap getShadowDefines(); diff --git a/components/shader/shadermanager.cpp b/components/shader/shadermanager.cpp index 9f31412713..73290da2e3 100644 --- a/components/shader/shadermanager.cpp +++ b/components/shader/shadermanager.cpp @@ -636,31 +636,24 @@ namespace Shader program->addShader(linkedShader); } - int ShaderManager::reserveGlobalTextureUnits(Slot slot) + int ShaderManager::reserveGlobalTextureUnits(Slot slot, int count) { - int unit = mReservedTextureUnitsBySlot[static_cast(slot)]; - if (unit >= 0) - return unit; + // TODO: Reuse units when count increase forces reallocation + // TODO: Warn if trampling on the ~8 units needed by model textures + auto unit = mReservedTextureUnitsBySlot[static_cast(slot)]; + if (unit.index >= 0 && unit.count >= count) + return unit.index; - { - // Texture units from `8 - numberOfShadowMaps` to `8` are used for shadows, so we skip them here. - // TODO: Maybe instead of fixed texture units use `reserveGlobalTextureUnits` for shadows as well. - static const int numberOfShadowMaps = Settings::Manager::getBool("enable shadows", "Shadows") - ? std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8) - : 0; - if (getAvailableTextureUnits() >= 8 && getAvailableTextureUnits() - 1 < 8) - mReservedTextureUnits = mMaxTextureUnits - (8 - numberOfShadowMaps); - } - - if (getAvailableTextureUnits() < 2) + if (getAvailableTextureUnits() < count + 1) throw std::runtime_error("Can't reserve texture unit; no available units"); - mReservedTextureUnits++; + mReservedTextureUnits += count; - unit = mMaxTextureUnits - mReservedTextureUnits; + unit.index = mMaxTextureUnits - mReservedTextureUnits; + unit.count = count; mReservedTextureUnitsBySlot[static_cast(slot)] = unit; - return unit; + return unit.index; } void ShaderManager::update(osgViewer::Viewer& viewer) diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index e057867ee3..f27c52a16e 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -76,9 +76,11 @@ namespace Shader { OpaqueDepthTexture, SkyTexture, + ShadowMaps, + SLOT_COUNT }; - int reserveGlobalTextureUnits(Slot slot); + int reserveGlobalTextureUnits(Slot slot, int count = 1); void update(osgViewer::Viewer& viewer); void setHotReloadEnabled(bool value); @@ -116,7 +118,8 @@ namespace Shader int mMaxTextureUnits = 0; int mReservedTextureUnits = 0; std::unique_ptr mHotReloadManager; - std::array mReservedTextureUnitsBySlot = { -1, -1 }; + struct ReservedTextureUnits { int index = -1; int count = 0; }; + std::array(Slot::SLOT_COUNT) > mReservedTextureUnitsBySlot = {}; }; bool parseForeachDirective(std::string& source, const std::string& templateName, size_t foundPos); From 83b940397eaa345056463f475b5dc6de18a29ecb Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 10 Feb 2023 00:12:55 +0000 Subject: [PATCH 5/6] AdD lInE bReAk ThAt ClAnG-fOrMaT wAnTeD --- components/sceneutil/shadow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index b9f2cbd831..7fe7363a74 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -32,7 +32,8 @@ namespace SceneUtil = std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8); mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); - mShadowSettings->setBaseShadowTextureUnit(shaderManager.reserveGlobalTextureUnits(Shader::ShaderManager::Slot::ShadowMaps, numberOfShadowMapsPerLight)); + mShadowSettings->setBaseShadowTextureUnit(shaderManager.reserveGlobalTextureUnits( + Shader::ShaderManager::Slot::ShadowMaps, numberOfShadowMapsPerLight)); const float maximumShadowMapDistance = Settings::Manager::getFloat("maximum shadow map distance", "Shadows"); if (maximumShadowMapDistance > 0) From 8ea2e1544610b3365d7f0070bdc56bd73f5509fe Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Fri, 10 Feb 2023 00:40:48 +0000 Subject: [PATCH 6/6] clang-format some more LLVM shouldn't make me download everything they've ever made in the same package as clang-format. --- components/shader/shadermanager.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/components/shader/shadermanager.hpp b/components/shader/shadermanager.hpp index f27c52a16e..d5d537722a 100644 --- a/components/shader/shadermanager.hpp +++ b/components/shader/shadermanager.hpp @@ -118,8 +118,12 @@ namespace Shader int mMaxTextureUnits = 0; int mReservedTextureUnits = 0; std::unique_ptr mHotReloadManager; - struct ReservedTextureUnits { int index = -1; int count = 0; }; - std::array(Slot::SLOT_COUNT) > mReservedTextureUnitsBySlot = {}; + struct ReservedTextureUnits + { + int index = -1; + int count = 0; + }; + std::array(Slot::SLOT_COUNT)> mReservedTextureUnitsBySlot = {}; }; bool parseForeachDirective(std::string& source, const std::string& templateName, size_t foundPos);