From 8edd14fb8a1df2944b6395745f8b0bde568e9086 Mon Sep 17 00:00:00 2001 From: "Athena Z." Date: Fri, 16 Aug 2024 13:25:07 -0700 Subject: [PATCH] Expose shadow texture size for directional lighting in SDF (#1034) Signed-off-by: Athena Z Co-authored-by: Ian Chen --- include/gz/rendering/Light.hh | 18 +++ include/gz/rendering/Scene.hh | 12 ++ include/gz/rendering/base/BaseScene.hh | 8 ++ .../include/gz/rendering/ogre2/Ogre2Scene.hh | 8 ++ ogre2/src/Ogre2Scene.cc | 112 ++++++++++++++++-- src/base/BaseScene.cc | 23 ++++ test/common_test/Scene_TEST.cc | 40 +++++++ 7 files changed, 209 insertions(+), 12 deletions(-) diff --git a/include/gz/rendering/Light.hh b/include/gz/rendering/Light.hh index 1af5dbe96..3ba82e372 100644 --- a/include/gz/rendering/Light.hh +++ b/include/gz/rendering/Light.hh @@ -26,6 +26,24 @@ namespace gz namespace rendering { inline namespace GZ_RENDERING_VERSION_NAMESPACE { + + /// \enum LightType + /// \brief Enum for Light types. + enum class GZ_RENDERING_VISIBLE LightType + { + /// \brief No light type specified + EMPTY = 0, + + /// \brief Point light + POINT = 1, + + /// \brief Directional light + DIRECTIONAL = 2, + + /// \brief Spot light + SPOT = 3 + }; + // /// \class Light Light.hh gz/rendering/Light.hh /// \brief Represents a light source in the scene graph diff --git a/include/gz/rendering/Scene.hh b/include/gz/rendering/Scene.hh index 3d15d960f..fdaa6436d 100644 --- a/include/gz/rendering/Scene.hh +++ b/include/gz/rendering/Scene.hh @@ -34,6 +34,7 @@ #include "gz/rendering/RenderTypes.hh" #include "gz/rendering/Storage.hh" #include "gz/rendering/Export.hh" +#include "gz/rendering/Light.hh" namespace gz { @@ -1270,6 +1271,17 @@ namespace gz /// \return true to sky is enabled, false otherwise public: virtual bool SkyEnabled() const = 0; + /// \brief Set the shadow texture size for the given light type. + /// \param _lightType Light type that creates the shadow + /// \param _textureSize Shadow texture size + public: virtual bool SetShadowTextureSize(LightType _lightType, + unsigned int _textureSize) = 0; + + /// \brief Get the shadow texture size for the given light type. + /// \param _lightType Light type that creates the shadow + public: virtual unsigned int ShadowTextureSize(LightType _lightType) + const = 0; + /// \brief Sets the given GI as the current new active GI solution /// \param[in] _gi GI solution that should be active. Nullptr to disable public: virtual void SetActiveGlobalIllumination( diff --git a/include/gz/rendering/base/BaseScene.hh b/include/gz/rendering/base/BaseScene.hh index d5c35f3e3..200246a2b 100644 --- a/include/gz/rendering/base/BaseScene.hh +++ b/include/gz/rendering/base/BaseScene.hh @@ -628,6 +628,14 @@ namespace gz // Documentation inherited. public: virtual bool SkyEnabled() const override; + // Documentation inherited. + public: virtual bool SetShadowTextureSize(LightType _lightType, + unsigned int _textureSize) override; + + // Documentation inherited. + public: virtual unsigned int ShadowTextureSize(LightType _lightType) const + override; + // Documentation inherited. public: virtual void SetActiveGlobalIllumination( GlobalIlluminationBasePtr _gi) override; diff --git a/ogre2/include/gz/rendering/ogre2/Ogre2Scene.hh b/ogre2/include/gz/rendering/ogre2/Ogre2Scene.hh index b54625953..323c2b30b 100644 --- a/ogre2/include/gz/rendering/ogre2/Ogre2Scene.hh +++ b/ogre2/include/gz/rendering/ogre2/Ogre2Scene.hh @@ -102,6 +102,14 @@ namespace gz // Documentation inherited public: virtual bool SkyEnabled() const override; + // Documentation inherited + public: bool SetShadowTextureSize(LightType _lightType, + unsigned int _textureSize); + + // Documentation inherited + public: unsigned int ShadowTextureSize(LightType _lightType) const + override; + // Documentation inherited public: virtual void SetActiveGlobalIllumination( GlobalIlluminationBasePtr _gi) override; diff --git a/ogre2/src/Ogre2Scene.cc b/ogre2/src/Ogre2Scene.cc index 17b870cc2..d7bc1ff91 100644 --- a/ogre2/src/Ogre2Scene.cc +++ b/ogre2/src/Ogre2Scene.cc @@ -15,6 +15,16 @@ * */ +#ifdef __APPLE__ + #define GL_SILENCE_DEPRECATION + #include + #include +#else +#ifndef _WIN32 + #include +#endif +#endif + #include #include "gz/rendering/base/SceneExt.hh" @@ -90,6 +100,15 @@ class gz::rendering::Ogre2ScenePrivate /// \brief Flag to indicate if sky is enabled or not public: bool skyEnabled = false; + /// \brief Max shadow texture size + public: unsigned int maxTexSize = 16384u; + + /// \brief Shadow texture size for directional light + public: unsigned int dirTexSize = 2048u; + + /// \brief Shadow texture size for spot and point lights + public: unsigned int spotPointTexSize = 2048u; + /// \brief Flag to alert the user its usage of PreRender/PostRender /// is incorrect public: bool frameUpdateStarted = false; @@ -651,15 +670,15 @@ void Ogre2Scene::UpdateShadowNode() // directional lights unsigned int atlasId = 0u; - unsigned int texSize = 2048u; - unsigned int halfTexSize = static_cast(texSize * 0.5); + unsigned int dirTexSize = this->dataPtr->dirTexSize; + unsigned int halfTexSize = static_cast(dirTexSize * 0.5); for (unsigned int i = 0; i < dirLightCount; ++i) { shadowParam.technique = Ogre::SHADOWMAP_PSSM; shadowParam.atlasId = atlasId; shadowParam.numPssmSplits = 3u; - shadowParam.resolution[0].x = texSize; - shadowParam.resolution[0].y = texSize; + shadowParam.resolution[0].x = dirTexSize; + shadowParam.resolution[0].y = dirTexSize; shadowParam.resolution[1].x = halfTexSize; shadowParam.resolution[1].y = halfTexSize; shadowParam.resolution[2].x = halfTexSize; @@ -667,30 +686,41 @@ void Ogre2Scene::UpdateShadowNode() shadowParam.atlasStart[0].x = 0u; shadowParam.atlasStart[0].y = 0u; shadowParam.atlasStart[1].x = 0u; - shadowParam.atlasStart[1].y = texSize; + shadowParam.atlasStart[1].y = dirTexSize; shadowParam.atlasStart[2].x = halfTexSize; - shadowParam.atlasStart[2].y = texSize; + shadowParam.atlasStart[2].y = dirTexSize; shadowParam.supportedLightTypes = 0u; shadowParam.addLightType(Ogre::Light::LT_DIRECTIONAL); shadowParams.push_back(shadowParam); atlasId++; } + if (engine->GraphicsAPI() == GraphicsAPI::OPENGL) + { + GLint glMaxTexSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glMaxTexSize); + + // todo: there are issues when setting dirTexSize to a val larger + // than 16K + this->dataPtr->maxTexSize = std::min(this->dataPtr->maxTexSize, + static_cast(glMaxTexSize)); + } + // others - unsigned int maxTexSize = 8192u; + unsigned int spotPointTexSize = this->dataPtr->spotPointTexSize; unsigned int rowIdx = 0; unsigned int colIdx = 0; - unsigned int rowSize = maxTexSize / texSize; + unsigned int rowSize = this->dataPtr->maxTexSize / spotPointTexSize; unsigned int colSize = rowSize; for (unsigned int i = 0; i < spotPointLightCount; ++i) { shadowParam.technique = Ogre::SHADOWMAP_FOCUSED; shadowParam.atlasId = atlasId; - shadowParam.resolution[0].x = texSize; - shadowParam.resolution[0].y = texSize; - shadowParam.atlasStart[0].x = colIdx * texSize; - shadowParam.atlasStart[0].y = rowIdx * texSize; + shadowParam.resolution[0].x = spotPointTexSize; + shadowParam.resolution[0].y = spotPointTexSize; + shadowParam.atlasStart[0].x = colIdx * spotPointTexSize; + shadowParam.atlasStart[0].y = rowIdx * spotPointTexSize; shadowParam.supportedLightTypes = 0u; shadowParam.addLightType(Ogre::Light::LT_DIRECTIONAL); @@ -1554,6 +1584,64 @@ bool Ogre2Scene::SkyEnabled() const return this->dataPtr->skyEnabled; } +////////////////////////////////////////////////// +bool Ogre2Scene::SetShadowTextureSize(LightType _lightType, + unsigned int _textureSize) +{ + // If _lightType is not supported, block with gzerr message + if (_lightType != LightType::DIRECTIONAL) + { + gzerr << "Light type [" << static_cast(_lightType) + << "] is not supported." << std::endl; + return false; + } + + // If _textureSize exceeds max possible tex size, then use default + if (_textureSize > this->dataPtr->maxTexSize) + { + gzerr << " of '" << _textureSize + << "' exceeds maximum possible texture size of " + << this->dataPtr->maxTexSize + << ", using default texture size" << std::endl; + return false; + } + + // if _textureSize is an invalid texture size, then use default + if (_textureSize < 512u || !math::isPowerOfTwo(_textureSize)) + { + gzerr << " of '" << _textureSize + << "' is not a valid texture size," + << " using default texture size" << std::endl; + return false; + } + + // Set shadow texture size as _textureSize if value is valid + if (_lightType == LightType::DIRECTIONAL) + { + this->dataPtr->dirTexSize = _textureSize; + } + return true; +} + +////////////////////////////////////////////////// +unsigned int Ogre2Scene::ShadowTextureSize(LightType _lightType) const +{ + // todo: return based on light type, currently only dir light is supported + switch (_lightType) + { + case LightType::DIRECTIONAL: + return this->dataPtr->dirTexSize; + case LightType::SPOT: + case LightType::POINT: + return this->dataPtr->spotPointTexSize; + default: + case LightType::EMPTY: + gzerr << "Invalid light type [" << static_cast(_lightType) << "]" + << std::endl; + return 0u; + } +} + ////////////////////////////////////////////////// void Ogre2Scene::SetActiveGlobalIllumination(GlobalIlluminationBasePtr _gi) { diff --git a/src/base/BaseScene.cc b/src/base/BaseScene.cc index bdd997438..b65112fb3 100644 --- a/src/base/BaseScene.cc +++ b/src/base/BaseScene.cc @@ -1475,6 +1475,29 @@ bool BaseScene::SkyEnabled() const return false; } +////////////////////////////////////////////////// +bool BaseScene::SetShadowTextureSize(LightType _lightType, + unsigned int _textureSize) +{ + if (static_cast(_lightType) || _textureSize) + { + gzerr << "Setting shadow texture size not supported by: " + << this->Engine()->Name() << std::endl; + } + return false; +} + +////////////////////////////////////////////////// +unsigned int BaseScene::ShadowTextureSize(LightType _lightType) const +{ + if (static_cast(_lightType)) + { + gzerr << "Shadow texture size not supported by: " + << this->Engine()->Name() << std::endl; + } + return 0; +} + ////////////////////////////////////////////////// void BaseScene::SetActiveGlobalIllumination(GlobalIlluminationBasePtr _gi) { diff --git a/test/common_test/Scene_TEST.cc b/test/common_test/Scene_TEST.cc index 7803547f5..570e2d738 100644 --- a/test/common_test/Scene_TEST.cc +++ b/test/common_test/Scene_TEST.cc @@ -751,3 +751,43 @@ TEST_F(SceneTest, Sky) // Clean up engine->DestroyScene(scene); } + +///////////////////////////////////////////////// +TEST_F(SceneTest, ShadowTextureSize) +{ + CHECK_SUPPORTED_ENGINE("ogre2"); + + auto scene = engine->CreateScene("scene"); + ASSERT_NE(nullptr, scene); + + // Default shadow texture size for directional light is 2048u + EXPECT_EQ(scene->ShadowTextureSize(LightType::DIRECTIONAL), 2048u); + + // Currently only support setting shadow texture size for + // directional light + // If set shadow texture size for other light types, it is ignored + auto spotLight = scene->CreateSpotLight("spot_light"); + auto pointLight = scene->CreatePointLight("point_light"); + + EXPECT_FALSE(scene->SetShadowTextureSize(LightType::POINT, 4096u)); + EXPECT_EQ(scene->ShadowTextureSize(LightType::POINT), 2048u); + + EXPECT_FALSE(scene->SetShadowTextureSize(LightType::SPOT, 4096u)); + EXPECT_EQ(scene->ShadowTextureSize(LightType::SPOT), 2048u); + + EXPECT_FALSE(scene->SetShadowTextureSize(LightType::EMPTY, 4096u)); + EXPECT_EQ(scene->ShadowTextureSize(LightType::EMPTY), 0u); + + // If set shadow texture size to a valid value, change it + EXPECT_TRUE(scene->SetShadowTextureSize(LightType::DIRECTIONAL, 8192u)); + EXPECT_EQ(scene->ShadowTextureSize(LightType::DIRECTIONAL), 8192u); + + // If set shadow texture size to an invalid value, use default + EXPECT_FALSE(scene->SetShadowTextureSize(LightType::DIRECTIONAL, 1000u)); + EXPECT_EQ(scene->ShadowTextureSize(LightType::DIRECTIONAL), 8192u); + + // If set shadow texture size to a value larger than maxTexSize, + // use default + EXPECT_FALSE(scene->SetShadowTextureSize(LightType::DIRECTIONAL, 32768u)); + EXPECT_EQ(scene->ShadowTextureSize(LightType::DIRECTIONAL), 8192u); +}