Merge branch 'moo-bitch-get-out-my-hay' into 'master'

Don't use FFP-friendly texture image units for shadow maps

Closes #7102

See merge request OpenMW/openmw!2682
update_gitlab_rules
psi29a 2 years ago
commit 4faa1bf3e8

@ -537,9 +537,6 @@ MWShadowTechnique::ShadowData::ShadowData(MWShadowTechnique::ViewDependentData*
bool debug = settings->getDebugDraw(); bool debug = settings->getDebugDraw();
// set up texgen
_texgen = new osg::TexGen;
// set up the texture // set up the texture
_texture = new osg::Texture2D; _texture = new osg::Texture2D;
@ -994,8 +991,6 @@ void SceneUtil::MWShadowTechnique::copyShadowMap(osgUtil::CullVisitor& cv, ViewD
sdl.push_back(lhs_sd); sdl.push_back(lhs_sd);
} }
assignTexGenSettings(cv, lhs);
if (lhs->_numValidShadows > 0) if (lhs->_numValidShadows > 0)
{ {
prepareStateSetForRenderingShadow(*lhs, cv.getTraversalNumber()); prepareStateSetForRenderingShadow(*lhs, cv.getTraversalNumber());
@ -1007,13 +1002,6 @@ void SceneUtil::MWShadowTechnique::setCustomFrustumCallback(CustomFrustumCallbac
_customFrustumCallback = cfc; _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) void MWShadowTechnique::update(osg::NodeVisitor& nv)
{ {
@ -1035,7 +1023,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
int endUnit = baseUnit + settings->getNumShadowMapsPerLight(); int endUnit = baseUnit + settings->getNumShadowMapsPerLight();
for (int i = baseUnit; i < endUnit; ++i) 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(("shadowTexture" + std::to_string(i - baseUnit)).c_str(), i));
dummyState->addUniform(new osg::Uniform(("shadowTextureUnit" + std::to_string(i - baseUnit)).c_str(), i)); dummyState->addUniform(new osg::Uniform(("shadowTextureUnit" + std::to_string(i - baseUnit)).c_str(), i));
} }
@ -1524,7 +1512,10 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
for (const auto & uniform : _uniforms[cv.getTraversalNumber() % 2]) for (const auto & uniform : _uniforms[cv.getTraversalNumber() % 2])
{ {
if (uniform->getName() == validRegionUniformName) if (uniform->getName() == validRegionUniformName)
{
validRegionUniform = uniform; validRegionUniform = uniform;
break;
}
} }
if (!validRegionUniform) if (!validRegionUniform)
@ -1548,7 +1539,33 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
// 4.4 compute main scene graph TexGen + uniform settings + setup state // 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<osg::Uniform> shadowSpaceUniform;
for (const auto & uniform : _uniforms[cv.getTraversalNumber() % 2])
{
if (uniform->getName() == shadowSpaceUniformName)
{
shadowSpaceUniform = uniform;
break;
}
}
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 // mark the light as one that has active shadows and requires shaders
pl.textureUnits.push_back(textureUnit); pl.textureUnits.push_back(textureUnit);
@ -1556,14 +1573,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
// pass on shadow data to ShadowDataList // pass on shadow data to ShadowDataList
sd->_textureUnit = textureUnit; sd->_textureUnit = textureUnit;
if (textureUnit >= 8)
{
OSG_NOTICE<<"Shadow texture unit is invalid for texgen, will not be used."<<std::endl;
}
else
{
sdl.push_back(sd); sdl.push_back(sd);
}
// increment counters. // increment counters.
++textureUnit; ++textureUnit;
@ -1764,7 +1774,7 @@ void MWShadowTechnique::createShaders()
// Always use the GL_ALWAYS shader as the shadows bin will change it if necessary // Always use the GL_ALWAYS shader as the shadows bin will change it if necessary
_shadowCastingStateSet->setAttributeAndModes(_castingPrograms[GL_ALWAYS - GL_NEVER], osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); _shadowCastingStateSet->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 // 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("useDiffuseMapForShadowAlpha", true));
_shadowCastingStateSet->addUniform(new osg::Uniform("alphaTestShadows", false)); _shadowCastingStateSet->addUniform(new osg::Uniform("alphaTestShadows", false));
osg::ref_ptr<osg::Depth> depth = new osg::Depth; osg::ref_ptr<osg::Depth> depth = new osg::Depth;
@ -3081,28 +3091,6 @@ bool MWShadowTechnique::adjustPerspectiveShadowMapCameraSettings(osgUtil::Render
return true; return true;
} }
bool MWShadowTechnique::assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen)
{
OSG_INFO<<"assignTexGenSettings() textureUnit="<<textureUnit<<" texgen="<<texgen<<std::endl;
texgen->setMode(osg::TexGen::EYE_LINEAR);
// compute the matrix which takes a vertex from local coords into tex coords
// We actually use two matrices one used to define texgen
// and second that will be used as modelview when appling to OpenGL
texgen->setPlanesFromMatrix( camera->getProjectionMatrix() *
osg::Matrix::translate(1.0,1.0,1.0) *
osg::Matrix::scale(0.5,0.5,0.5) );
// Place texgen with modelview which removes big offsets (making it float friendly)
osg::ref_ptr<osg::RefMatrix> refMatrix =
new osg::RefMatrix( camera->getInverseViewMatrix() * (*(cv->getModelViewMatrix())) );
osgUtil::RenderStage* currentStage = cv->getCurrentRenderBin()->getStage();
currentStage->getPositionalStateContainer()->addPositionedTextureAttribute( textureUnit, refMatrix.get(), texgen );
return true;
}
void MWShadowTechnique::cullShadowReceivingScene(osgUtil::CullVisitor* cv) const void MWShadowTechnique::cullShadowReceivingScene(osgUtil::CullVisitor* cv) const
{ {
OSG_INFO<<"cullShadowReceivingScene()"<<std::endl; OSG_INFO<<"cullShadowReceivingScene()"<<std::endl;
@ -3196,12 +3184,7 @@ osg::StateSet* MWShadowTechnique::prepareStateSetForRenderingShadow(ViewDependen
OSG_INFO<<" ShadowData for "<<sd._textureUnit<<std::endl; OSG_INFO<<" ShadowData for "<<sd._textureUnit<<std::endl;
stateset->setTextureAttributeAndModes(sd._textureUnit, sd._texture.get(), shadowMapModeValue); stateset->setTextureAttribute(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);
} }
return stateset; return stateset;
@ -3304,7 +3287,7 @@ void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr<osg::Texture2D> t
addAnotherShadowMap(); addAnotherShadowMap();
osg::ref_ptr<osg::StateSet> stateSet = new osg::StateSet(); osg::ref_ptr<osg::StateSet> 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]; auto frustumUniform = mFrustumUniforms[cv.getTraversalNumber() % 2][shadowMapNumber];
frustumUniform->set(matrix); frustumUniform->set(matrix);
@ -3317,8 +3300,6 @@ void SceneUtil::MWShadowTechnique::DebugHUD::draw(osg::ref_ptr<osg::Texture2D> t
mDebugCameras[shadowMapNumber]->accept(cv); mDebugCameras[shadowMapNumber]->accept(cv);
cv.popStateSet(); cv.popStateSet();
cv.setTraversalMask(traversalMask); cv.setTraversalMask(traversalMask);
// cv.getState()->setCheckForGLErrors(osg::State::ONCE_PER_ATTRIBUTE);
} }
void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) const void SceneUtil::MWShadowTechnique::DebugHUD::releaseGLObjects(osg::State* state) const

@ -193,7 +193,6 @@ namespace SceneUtil {
unsigned int _textureUnit; unsigned int _textureUnit;
osg::ref_ptr<osg::Texture2D> _texture; osg::ref_ptr<osg::Texture2D> _texture;
osg::ref_ptr<osg::TexGen> _texgen;
osg::ref_ptr<osg::Camera> _camera; osg::ref_ptr<osg::Camera> _camera;
}; };
@ -241,8 +240,6 @@ namespace SceneUtil {
void setCustomFrustumCallback(CustomFrustumCallback* cfc); void setCustomFrustumCallback(CustomFrustumCallback* cfc);
void assignTexGenSettings(osgUtil::CullVisitor& cv, ViewDependentData* vdd);
virtual void createShaders(); virtual void createShaders();
virtual bool selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const; 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 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 cullShadowReceivingScene(osgUtil::CullVisitor* cv) const;
virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const; virtual void cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const;

@ -13,7 +13,7 @@ namespace SceneUtil
{ {
using namespace osgShadow; using namespace osgShadow;
void ShadowManager::setupShadowSettings() void ShadowManager::setupShadowSettings(Shader::ShaderManager& shaderManager)
{ {
mEnableShadows = Settings::Manager::getBool("enable shadows", "Shadows"); mEnableShadows = Settings::Manager::getBool("enable shadows", "Shadows");
@ -32,7 +32,8 @@ namespace SceneUtil
= std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8); = std::clamp(Settings::Manager::getInt("number of shadow maps", "Shadows"), 1, 8);
mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight); mShadowSettings->setNumShadowMapsPerLight(numberOfShadowMapsPerLight);
mShadowSettings->setBaseShadowTextureUnit(8 - numberOfShadowMapsPerLight); mShadowSettings->setBaseShadowTextureUnit(shaderManager.reserveGlobalTextureUnits(
Shader::ShaderManager::Slot::ShadowMaps, numberOfShadowMapsPerLight));
const float maximumShadowMapDistance = Settings::Manager::getFloat("maximum shadow map distance", "Shadows"); const float maximumShadowMapDistance = Settings::Manager::getFloat("maximum shadow map distance", "Shadows");
if (maximumShadowMapDistance > 0) if (maximumShadowMapDistance > 0)
@ -121,7 +122,7 @@ namespace SceneUtil
mShadowedScene->setNodeMask(sceneRoot->getNodeMask()); mShadowedScene->setNodeMask(sceneRoot->getNodeMask());
mShadowSettings = mShadowedScene->getShadowSettings(); mShadowSettings = mShadowedScene->getShadowSettings();
setupShadowSettings(); setupShadowSettings(shaderManager);
mShadowTechnique->setupCastingShader(shaderManager); mShadowTechnique->setupCastingShader(shaderManager);
mShadowTechnique->setWorldMask(worldMask); mShadowTechnique->setWorldMask(worldMask);

@ -29,7 +29,7 @@ namespace SceneUtil
Shader::ShaderManager& shaderManager); Shader::ShaderManager& shaderManager);
~ShadowManager(); ~ShadowManager();
void setupShadowSettings(); void setupShadowSettings(Shader::ShaderManager& shaderManager);
Shader::ShaderManager::DefineMap getShadowDefines(); Shader::ShaderManager::DefineMap getShadowDefines();

@ -681,31 +681,24 @@ namespace Shader
program->addShader(linkedShader); program->addShader(linkedShader);
} }
int ShaderManager::reserveGlobalTextureUnits(Slot slot) int ShaderManager::reserveGlobalTextureUnits(Slot slot, int count)
{ {
int unit = mReservedTextureUnitsBySlot[static_cast<int>(slot)]; // TODO: Reuse units when count increase forces reallocation
if (unit >= 0) // TODO: Warn if trampling on the ~8 units needed by model textures
return unit; auto unit = mReservedTextureUnitsBySlot[static_cast<int>(slot)];
if (unit.index >= 0 && unit.count >= count)
return unit.index;
{ if (getAvailableTextureUnits() < count + 1)
// 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)
throw std::runtime_error("Can't reserve texture unit; no available units"); 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<int>(slot)] = unit; mReservedTextureUnitsBySlot[static_cast<int>(slot)] = unit;
return unit; return unit.index;
} }
void ShaderManager::update(osgViewer::Viewer& viewer) void ShaderManager::update(osgViewer::Viewer& viewer)

@ -80,9 +80,11 @@ namespace Shader
{ {
OpaqueDepthTexture, OpaqueDepthTexture,
SkyTexture, SkyTexture,
ShadowMaps,
SLOT_COUNT
}; };
int reserveGlobalTextureUnits(Slot slot); int reserveGlobalTextureUnits(Slot slot, int count = 1);
void update(osgViewer::Viewer& viewer); void update(osgViewer::Viewer& viewer);
void setHotReloadEnabled(bool value); void setHotReloadEnabled(bool value);
@ -120,7 +122,12 @@ namespace Shader
int mMaxTextureUnits = 0; int mMaxTextureUnits = 0;
int mReservedTextureUnits = 0; int mReservedTextureUnits = 0;
std::unique_ptr<HotReloadManager> mHotReloadManager; std::unique_ptr<HotReloadManager> mHotReloadManager;
std::array<int, 2> mReservedTextureUnitsBySlot = { -1, -1 }; struct ReservedTextureUnits
{
int index = -1;
int count = 0;
};
std::array<ReservedTextureUnits, static_cast<int>(Slot::SLOT_COUNT)> mReservedTextureUnitsBySlot = {};
}; };
bool parseForeachDirective(std::string& source, const std::string& templateName, size_t foundPos); bool parseForeachDirective(std::string& source, const std::string& templateName, size_t foundPos);

@ -2,6 +2,7 @@
#if SHADOWS #if SHADOWS
@foreach shadow_texture_unit_index @shadow_texture_unit_list @foreach shadow_texture_unit_index @shadow_texture_unit_list
uniform mat4 shadowSpaceMatrix@shadow_texture_unit_index;
uniform int shadowTextureUnit@shadow_texture_unit_index; uniform int shadowTextureUnit@shadow_texture_unit_index;
varying vec4 shadowSpaceCoords@shadow_texture_unit_index; varying vec4 shadowSpaceCoords@shadow_texture_unit_index;
@ -19,33 +20,28 @@ void setupShadowCoords(vec4 viewPos, vec3 viewNormal)
{ {
#if SHADOWS #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. // 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; vec4 shadowOffset;
@foreach shadow_texture_unit_index @shadow_texture_unit_list @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 #if @perspectiveShadowMaps
shadowRegionCoords@shadow_texture_unit_index = validRegionMatrix@shadow_texture_unit_index * viewPos; shadowRegionCoords@shadow_texture_unit_index = validRegionMatrix@shadow_texture_unit_index * viewPos;
#endif #endif
#if @disableNormalOffsetShadows #if @disableNormalOffsetShadows
shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat; shadowSpaceCoords@shadow_texture_unit_index = shadowSpaceMatrix@shadow_texture_unit_index * viewPos;
#else #else
shadowOffset = vec4(viewNormal * @shadowNormalOffset, 0.0); shadowOffset = vec4(viewNormal * @shadowNormalOffset, 0.0);
if (onlyNormalOffsetUV) if (onlyNormalOffsetUV)
{ {
shadowSpaceCoords@shadow_texture_unit_index = viewPos * eyePlaneMat;
vec4 lightSpaceXY = viewPos + shadowOffset; vec4 lightSpaceXY = viewPos + shadowOffset;
lightSpaceXY = lightSpaceXY * eyePlaneMat; lightSpaceXY = shadowSpaceMatrix@shadow_texture_unit_index * lightSpaceXY;
shadowSpaceCoords@shadow_texture_unit_index.xy = lightSpaceXY.xy; shadowSpaceCoords@shadow_texture_unit_index.xy = lightSpaceXY.xy;
} }
else else
{ {
vec4 offsetViewPosition = viewPos + shadowOffset; vec4 offsetViewPosition = viewPos + shadowOffset;
shadowSpaceCoords@shadow_texture_unit_index = offsetViewPosition * eyePlaneMat; shadowSpaceCoords@shadow_texture_unit_index = shadowSpaceMatrix@shadow_texture_unit_index * offsetViewPosition;
} }
#endif #endif
@endforeach @endforeach

Loading…
Cancel
Save