pxmlw6n2f/Gazebo_Distributed_MPI/gazebo/rendering/RTShaderSystem.cc

736 lines
23 KiB
C++
Raw Normal View History

2019-04-18 10:27:54 +08:00
/*
* Copyright (C) 2012 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifdef _WIN32
// Ensure that Winsock2.h is included before Windows.h, which can get
// pulled in by anybody (e.g., Boost).
#include <Winsock2.h>
#endif
#include <sys/stat.h>
#if defined(HAVE_OPENGL)
#if defined(__APPLE__)
#include <OpenGL/gl.h>
#include <OpenGL/glext.h>
#else
#if defined(_WIN32)
#include <windows.h>
#endif /* _WIN32 */
#include <GL/gl.h>
#include <GL/glext.h>
#endif /* __APPLE__ */
#endif /* HAVE_OPENGL */
#include "gazebo/common/Console.hh"
#include "gazebo/common/Exception.hh"
#include "gazebo/common/SystemPaths.hh"
#include "gazebo/rendering/ogre_gazebo.h"
#include "gazebo/rendering/CustomPSSMShadowCameraSetup.hh"
#include "gazebo/rendering/RenderEngine.hh"
#include "gazebo/rendering/Scene.hh"
#include "gazebo/rendering/Visual.hh"
#include "gazebo/rendering/RTShaderSystemPrivate.hh"
#include "gazebo/rendering/RTShaderSystem.hh"
#define MINOR_VERSION 7
using namespace gazebo;
using namespace rendering;
//////////////////////////////////////////////////
RTShaderSystem::RTShaderSystem()
: dataPtr(new RTShaderSystemPrivate)
{
this->dataPtr->initialized = false;
this->dataPtr->shadowsApplied = false;
this->dataPtr->pssmSetup.setNull();
this->dataPtr->updateShaders = false;
}
//////////////////////////////////////////////////
RTShaderSystem::~RTShaderSystem()
{
this->Fini();
delete this->dataPtr;
this->dataPtr = NULL;
}
//////////////////////////////////////////////////
void RTShaderSystem::Init()
{
#if INCLUDE_RTSHADER && OGRE_VERSION_MAJOR >= 1 &&\
OGRE_VERSION_MINOR >= MINOR_VERSION
// Only initialize if using FORWARD rendering
if (RenderEngine::Instance()->GetRenderPathType() != RenderEngine::FORWARD)
return;
if (Ogre::RTShader::ShaderGenerator::initialize())
{
this->dataPtr->initialized = true;
std::string coreLibsPath, cachePath;
this->GetPaths(coreLibsPath, cachePath);
// Get the shader generator pointer
this->dataPtr->shaderGenerator =
Ogre::RTShader::ShaderGenerator::getSingletonPtr();
// Add the shader libs resource location
Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
coreLibsPath, "FileSystem");
// Set shader cache path.
this->dataPtr->shaderGenerator->setShaderCachePath(cachePath);
#if OGRE_VERSION_MAJOR >= 1 && OGRE_VERSION_MINOR <= 8
this->dataPtr->programWriterFactory =
OGRE_NEW CustomGLSLProgramWriterFactory();
Ogre::RTShader::ProgramWriterManager::getSingletonPtr()->addFactory(
this->dataPtr->programWriterFactory);
#endif
this->dataPtr->shaderGenerator->setTargetLanguage("glsl");
Ogre::RTShader::SubRenderStateFactory* factory =
OGRE_NEW CustomPSSM3Factory;
this->dataPtr->shaderGenerator->addSubRenderStateFactory(factory);
}
else
gzerr << "RT Shader system failed to initialize\n";
#endif
// normal map is not working with the shaders in media/rtshaderlib
// (GLSL < 130), so disable it for now.
// this mainly affects gazebo on OSX
const Ogre::RenderSystemCapabilities *capabilities =
Ogre::Root::getSingleton().getRenderSystem()->getCapabilities();
Ogre::DriverVersion glVersion;
glVersion.build = 0;
glVersion.major = 3;
glVersion.minor = 0;
glVersion.release = 0;
if (capabilities->isDriverOlderThanVersion(glVersion))
this->dataPtr->enableNormalMap = false;
}
//////////////////////////////////////////////////
void RTShaderSystem::Fini()
{
if (!this->dataPtr->initialized)
return;
// Restore default scheme.
Ogre::MaterialManager::getSingleton().setActiveScheme(
Ogre::MaterialManager::DEFAULT_SCHEME_NAME);
// Finalize RTShader system.
if (this->dataPtr->shaderGenerator != NULL)
{
// On Windows, we're using 1.9RC1, which doesn't have a bunch of changes.
#if (OGRE_VERSION < ((1 << 16) | (9 << 8) | 0)) || defined(_WIN32)
Ogre::RTShader::ShaderGenerator::finalize();
#else
Ogre::RTShader::ShaderGenerator::destroy();
#endif
if (this->dataPtr->programWriterFactory)
delete this->dataPtr->programWriterFactory;
this->dataPtr->shaderGenerator = NULL;
}
this->dataPtr->pssmSetup.setNull();
this->dataPtr->scenes.clear();
this->dataPtr->shadowsApplied = false;
this->dataPtr->initialized = false;
}
#if INCLUDE_RTSHADER && OGRE_VERSION_MAJOR >= 1 &&\
OGRE_VERSION_MINOR >= MINOR_VERSION
//////////////////////////////////////////////////
void RTShaderSystem::AddScene(ScenePtr _scene)
{
if (!this->dataPtr->initialized)
return;
// Set the scene manager
this->dataPtr->shaderGenerator->addSceneManager(_scene->OgreSceneManager());
this->dataPtr->shaderGenerator->createScheme(_scene->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
this->dataPtr->scenes.push_back(_scene);
}
#else
void RTShaderSystem::AddScene(ScenePtr /*_scene*/)
{
}
#endif
//////////////////////////////////////////////////
void RTShaderSystem::RemoveScene(ScenePtr _scene)
{
if (!this->dataPtr->initialized)
return;
auto iter = this->dataPtr->scenes.begin();
for (; iter != this->dataPtr->scenes.end(); ++iter)
if ((*iter) == _scene)
break;
if (iter != this->dataPtr->scenes.end())
{
this->dataPtr->scenes.erase(iter);
this->dataPtr->shaderGenerator->invalidateScheme(_scene->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
this->dataPtr->shaderGenerator->removeSceneManager(
_scene->OgreSceneManager());
this->dataPtr->shaderGenerator->removeAllShaderBasedTechniques();
this->dataPtr->shaderGenerator->flushShaderCache();
}
}
//////////////////////////////////////////////////
void RTShaderSystem::RemoveScene(const std::string &_scene)
{
if (!this->dataPtr->initialized)
return;
for (auto iter : this->dataPtr->scenes)
{
if (iter->Name() == _scene)
{
this->RemoveScene(iter);
return;
}
}
}
//////////////////////////////////////////////////
void RTShaderSystem::AttachEntity(Visual * /*_vis*/)
{
return;
}
//////////////////////////////////////////////////
void RTShaderSystem::DetachEntity(Visual * /*_vis*/)
{
return;
}
//////////////////////////////////////////////////
void RTShaderSystem::Clear()
{
}
//////////////////////////////////////////////////
void RTShaderSystem::AttachViewport(Ogre::Viewport *_viewport, ScenePtr _scene)
{
#if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 7
_viewport->setMaterialScheme(_scene->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
#endif
}
//////////////////////////////////////////////////
void RTShaderSystem::DetachViewport(Ogre::Viewport *_viewport, ScenePtr _scene)
{
#if OGRE_VERSION_MAJOR == 1 && OGRE_VERSION_MINOR >= 7
if (_viewport && _scene && _scene->Initialized())
_viewport->setMaterialScheme(_scene->Name());
#endif
}
//////////////////////////////////////////////////
void RTShaderSystem::UpdateShaders()
{
// shaders will be updated in the Update call on pre-render event.
this->dataPtr->updateShaders = true;
}
//////////////////////////////////////////////////
void RTShaderSystem::UpdateShaders(VisualPtr _vis)
{
if (_vis)
{
if (_vis->UseRTShader())
this->GenerateShaders(_vis);
for (unsigned int i = 0; i < _vis->GetChildCount(); ++i)
this->UpdateShaders(_vis->GetChild(i));
}
}
//////////////////////////////////////////////////
void RTShaderSystem::GenerateShaders(Visual *_vis)
{
VisualPtr vis(_vis);
this->GenerateShaders(vis);
}
//////////////////////////////////////////////////
void RTShaderSystem::GenerateShaders(const VisualPtr &_vis)
{
if (!this->dataPtr->initialized || !_vis)
return;
for (unsigned int k = 0; _vis->GetSceneNode() &&
k < _vis->GetSceneNode()->numAttachedObjects(); ++k)
{
Ogre::MovableObject *obj = _vis->GetSceneNode()->getAttachedObject(k);
Ogre::Entity *entity = dynamic_cast<Ogre::Entity*>(obj);
if (!entity)
continue;
for (unsigned int i = 0; i < entity->getNumSubEntities(); ++i)
{
Ogre::SubEntity* curSubEntity = entity->getSubEntity(i);
const Ogre::String& curMaterialName = curSubEntity->getMaterialName();
bool success = false;
for (unsigned int s = 0; s < this->dataPtr->scenes.size(); s++)
{
try
{
success = this->dataPtr->shaderGenerator->createShaderBasedTechnique(
curMaterialName,
Ogre::MaterialManager::DEFAULT_SCHEME_NAME,
this->dataPtr->scenes[s]->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
}
catch(Ogre::Exception &e)
{
gzerr << "Unable to create shader technique for material["
<< curMaterialName << "]\n";
success = false;
}
// Setup custom shader sub render states according to current setup.
if (success)
{
Ogre::MaterialPtr curMaterial =
Ogre::MaterialManager::getSingleton().getByName(curMaterialName);
// Grab the first pass render state.
// NOTE:For more complicated samples iterate over the passes and build
// each one of them as desired.
Ogre::RTShader::RenderState* renderState =
this->dataPtr->shaderGenerator->getRenderState(
this->dataPtr->scenes[s]->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME,
curMaterialName, 0);
// Remove all sub render states.
renderState->reset();
if (this->dataPtr->enableNormalMap &&
_vis->GetShaderType() == "normal_map_object_space")
{
Ogre::RTShader::SubRenderState* subRenderState =
this->dataPtr->shaderGenerator->createSubRenderState(
Ogre::RTShader::NormalMapLighting::Type);
Ogre::RTShader::NormalMapLighting* normalMapSubRS =
static_cast<Ogre::RTShader::NormalMapLighting*>(subRenderState);
normalMapSubRS->setNormalMapSpace(
Ogre::RTShader::NormalMapLighting::NMS_OBJECT);
normalMapSubRS->setNormalMapTextureName(_vis->GetNormalMap());
renderState->addTemplateSubRenderState(normalMapSubRS);
}
else if (this->dataPtr->enableNormalMap &&
_vis->GetShaderType() == "normal_map_tangent_space")
{
Ogre::RTShader::SubRenderState* subRenderState =
this->dataPtr->shaderGenerator->createSubRenderState(
Ogre::RTShader::NormalMapLighting::Type);
Ogre::RTShader::NormalMapLighting* normalMapSubRS =
static_cast<Ogre::RTShader::NormalMapLighting*>(subRenderState);
normalMapSubRS->setNormalMapSpace(
Ogre::RTShader::NormalMapLighting::NMS_TANGENT);
normalMapSubRS->setNormalMapTextureName(_vis->GetNormalMap());
renderState->addTemplateSubRenderState(normalMapSubRS);
}
else if (_vis->GetShaderType() == "vertex")
{
Ogre::RTShader::SubRenderState *perPerVertexLightModel =
this->dataPtr->shaderGenerator->createSubRenderState(
Ogre::RTShader::FFPLighting::Type);
renderState->addTemplateSubRenderState(perPerVertexLightModel);
}
else
{
Ogre::RTShader::SubRenderState *perPixelLightModel =
this->dataPtr->shaderGenerator->createSubRenderState(
Ogre::RTShader::PerPixelLighting::Type);
renderState->addTemplateSubRenderState(perPixelLightModel);
}
// Invalidate this material in order to re-generate its shaders.
this->dataPtr->shaderGenerator->invalidateMaterial(
this->dataPtr->scenes[s]->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME,
curMaterialName);
}
}
}
}
}
//////////////////////////////////////////////////
bool RTShaderSystem::GetPaths(std::string &coreLibsPath, std::string &cachePath)
{
if (!this->dataPtr->initialized)
return false;
Ogre::StringVector groupVector;
// Setup the core libraries and shader cache path
groupVector = Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
Ogre::StringVector::iterator itGroup = groupVector.begin();
Ogre::StringVector::iterator itGroupEnd = groupVector.end();
Ogre::String shaderCoreLibsPath;
for (; itGroup != itGroupEnd; ++itGroup)
{
Ogre::ResourceGroupManager::LocationList resLocationsList;
Ogre::ResourceGroupManager::LocationList::iterator it;
Ogre::ResourceGroupManager::LocationList::iterator itEnd;
bool coreLibsFound = false;
resLocationsList =
Ogre::ResourceGroupManager::getSingleton().getResourceLocationList(
*itGroup);
it = resLocationsList.begin();
itEnd = resLocationsList.end();
// Try to find the location of the core shader lib functions and use it
// as shader cache path as well - this will reduce the number of
// generated files when running from different directories.
for (; it != itEnd; ++it)
{
struct stat st;
if (stat((*it)->archive->getName().c_str(), &st) == 0)
{
if ((*it)->archive->getName().find("rtshaderlib") != Ogre::String::npos)
{
coreLibsPath = (*it)->archive->getName() + "/";
// setup patch name for rt shader cache in tmp
char *tmpdir;
char *user;
std::ostringstream stream;
std::ostringstream errStream;
// Get the tmp dir
tmpdir = getenv("TMP");
if (!tmpdir)
{
common::SystemPaths *paths = common::SystemPaths::Instance();
tmpdir = const_cast<char*>(paths->GetTmpPath().c_str());
}
// Get the user
user = getenv("USER");
if (!user)
user = const_cast<char*>("nobody");
stream << tmpdir << "/gazebo-" << user << "-rtshaderlibcache" << "/";
cachePath = stream.str();
// Create the directory
#ifdef _WIN32
if (mkdir(cachePath.c_str()) != 0)
#else
if (mkdir(cachePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0)
#endif
{
if (errno != EEXIST)
{
errStream << "failed to create [" << cachePath << "] : ["
<< strerror(errno) << "]";
throw(errStream.str());
}
}
coreLibsFound = true;
break;
}
}
}
// Core libs path found in the current group.
if (coreLibsFound)
break;
}
// Core shader lib not found -> shader generating will fail.
if (coreLibsPath.empty())
{
gzerr << "Unable to find shader lib. Shader generating will fail.";
return false;
}
return true;
}
/////////////////////////////////////////////////
void RTShaderSystem::RemoveShadows(ScenePtr _scene)
{
if (!this->dataPtr->initialized || !this->dataPtr->shadowsApplied)
return;
_scene->OgreSceneManager()->setShadowTechnique(Ogre::SHADOWTYPE_NONE);
_scene->OgreSceneManager()->setShadowCameraSetup(
Ogre::ShadowCameraSetupPtr());
Ogre::RTShader::RenderState* schemeRenderState =
this->dataPtr->shaderGenerator->getRenderState(
_scene->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
schemeRenderState->removeTemplateSubRenderState(
this->dataPtr->shadowRenderState);
this->dataPtr->shaderGenerator->invalidateScheme(_scene->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
this->UpdateShaders();
this->dataPtr->shadowsApplied = false;
}
/////////////////////////////////////////////////
void RTShaderSystem::ApplyShadows(ScenePtr _scene)
{
if (!this->dataPtr->initialized || this->dataPtr->shadowsApplied)
return;
Ogre::SceneManager *sceneMgr = _scene->OgreSceneManager();
// Grab the scheme render state.
Ogre::RTShader::RenderState* schemRenderState =
this->dataPtr->shaderGenerator->getRenderState(_scene->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
sceneMgr->setShadowTechnique(Ogre::SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED);
// 3 textures per directional light
sceneMgr->setShadowTextureCountPerLightType(Ogre::Light::LT_DIRECTIONAL, 3);
sceneMgr->setShadowTextureCountPerLightType(Ogre::Light::LT_POINT, 0);
sceneMgr->setShadowTextureCountPerLightType(Ogre::Light::LT_SPOTLIGHT, 0);
sceneMgr->setShadowTextureCount(3);
unsigned int texSize = this->dataPtr->shadowTextureSize;
#if defined(__APPLE__)
// workaround a weird but on OSX if texture size at 2 and 3 splits are not
// halved
texSize = this->dataPtr->shadowTextureSize/2;
#endif
sceneMgr->setShadowTextureConfig(0,
this->dataPtr->shadowTextureSize, this->dataPtr->shadowTextureSize,
Ogre::PF_FLOAT32_R);
sceneMgr->setShadowTextureConfig(1, texSize, texSize, Ogre::PF_FLOAT32_R);
sceneMgr->setShadowTextureConfig(2, texSize, texSize, Ogre::PF_FLOAT32_R);
#if defined(HAVE_OPENGL)
// Enable shadow map comparison, so shader can use
// float texture(sampler2DShadow, vec3, [float]) instead of
// vec4 texture(sampler2D, vec2, [float]).
// NVidia, AMD, and Intel all take this as a cue to provide "hardware PCF",
// a driver hack that softens shadow edges with 4-sample interpolation.
for (size_t i = 0; i < sceneMgr->getShadowTextureCount(); ++i)
{
const Ogre::TexturePtr tex = sceneMgr->getShadowTexture(i);
// This will fail if not using OpenGL as the rendering backend.
GLuint texId;
tex->getCustomAttribute("GLID", &texId);
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
GL_COMPARE_R_TO_TEXTURE);
}
#endif
sceneMgr->setShadowTextureSelfShadow(false);
sceneMgr->setShadowCasterRenderBackFaces(true);
// TODO: We have two different shadow caster materials, both taken from
// OGRE samples. They should be compared and tested.
// Set up caster material - this is just a standard depth/shadow map caster
// sceneMgr->setShadowTextureCasterMaterial("PSSM/shadow_caster");
sceneMgr->setShadowTextureCasterMaterial("Gazebo/shadow_caster");
// Disable fog on the caster pass.
// Ogre::MaterialPtr passCaterMaterial =
// Ogre::MaterialManager::getSingleton().getByName("PSSM/shadow_caster");
// Ogre::Pass* pssmCasterPass =
// passCaterMaterial->getTechnique(0)->getPass(0);
// pssmCasterPass->setFog(true);
// shadow camera setup
if (this->dataPtr->pssmSetup.isNull())
{
this->dataPtr->pssmSetup =
Ogre::ShadowCameraSetupPtr(new CustomPSSMShadowCameraSetup());
}
sceneMgr->setShadowFarDistance(this->dataPtr->shadowFar);
CustomPSSMShadowCameraSetup *cameraSetup =
dynamic_cast<CustomPSSMShadowCameraSetup*>(
this->dataPtr->pssmSetup.get());
cameraSetup->calculateSplitPoints(3, this->dataPtr->shadowNear,
this->dataPtr->shadowFar, this->dataPtr->shadowSplitLambda);
cameraSetup->setSplitPadding(this->dataPtr->shadowSplitPadding);
sceneMgr->setShadowCameraSetup(this->dataPtr->pssmSetup);
this->dataPtr->shadowRenderState =
this->dataPtr->shaderGenerator->createSubRenderState(
CustomPSSM3::Type);
CustomPSSM3 *pssm3SubRenderState =
static_cast<CustomPSSM3 *>(this->dataPtr->shadowRenderState);
const Ogre::PSSMShadowCameraSetup::SplitPointList &srcSplitPoints =
cameraSetup->getSplitPoints();
CustomPSSM3::SplitPointList dstSplitPoints;
for (unsigned int i = 0; i < srcSplitPoints.size(); ++i)
{
dstSplitPoints.push_back(srcSplitPoints[i]);
}
pssm3SubRenderState->setSplitPoints(dstSplitPoints);
schemRenderState->addTemplateSubRenderState(this->dataPtr->shadowRenderState);
this->dataPtr->shaderGenerator->invalidateScheme(_scene->Name() +
Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
this->UpdateShaders();
this->dataPtr->shadowsApplied = true;
}
/////////////////////////////////////////////////
void RTShaderSystem::ReapplyShadows()
{
if (this->dataPtr->shadowsApplied)
{
for (unsigned int i = 0; i < this->dataPtr->scenes.size(); i++)
{
RemoveShadows(this->dataPtr->scenes[i]);
ApplyShadows(this->dataPtr->scenes[i]);
}
}
}
/////////////////////////////////////////////////
Ogre::PSSMShadowCameraSetup *RTShaderSystem::GetPSSMShadowCameraSetup() const
{
return dynamic_cast<Ogre::PSSMShadowCameraSetup *>(
this->dataPtr->pssmSetup.get());
}
/////////////////////////////////////////////////
void RTShaderSystem::Update()
{
if (!this->dataPtr->initialized || !this->dataPtr->updateShaders)
return;
for (const auto &scene : this->dataPtr->scenes)
{
VisualPtr vis = scene->WorldVisual();
if (vis)
{
this->UpdateShaders(vis);
}
}
this->dataPtr->updateShaders = false;
}
/////////////////////////////////////////////////
bool RTShaderSystem::SetShadowTextureSize(const unsigned int _size)
{
// check if texture size is a power of 2
if (!ignition::math::isPowerOfTwo(_size))
{
gzerr << "Shadow texture size must be a power of 2" << std::endl;
return false;
}
this->dataPtr->shadowTextureSize = _size;
return true;
}
/////////////////////////////////////////////////
unsigned int RTShaderSystem::ShadowTextureSize() const
{
return this->dataPtr->shadowTextureSize;
}
/////////////////////////////////////////////////
void RTShaderSystem::SetShadowClipDist(const double _near, const double _far)
{
this->dataPtr->shadowNear = _near;
this->dataPtr->shadowFar = _far;
ReapplyShadows();
}
/////////////////////////////////////////////////
double RTShaderSystem::ShadowNearClip() const
{
return this->dataPtr->shadowNear;
}
/////////////////////////////////////////////////
double RTShaderSystem::ShadowFarClip() const
{
return this->dataPtr->shadowFar;
}
/////////////////////////////////////////////////
void RTShaderSystem::SetShadowSplitLambda(const double _lambda)
{
this->dataPtr->shadowSplitLambda = _lambda;
ReapplyShadows();
}
/////////////////////////////////////////////////
double RTShaderSystem::ShadowSplitLambda() const
{
return this->dataPtr->shadowSplitLambda;
}
/////////////////////////////////////////////////
void RTShaderSystem::SetShadowSplitPadding(const double _padding)
{
this->dataPtr->shadowSplitPadding = _padding;
ReapplyShadows();
}
/////////////////////////////////////////////////
double RTShaderSystem::ShadowSplitPadding() const
{
return this->dataPtr->shadowSplitPadding;
}