mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 16:29:55 +00:00
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.
This commit is contained in:
parent
b12507f808
commit
0edc8fc77d
4 changed files with 35 additions and 69 deletions
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -1548,7 +1536,30 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 +1567,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)
|
sdl.push_back(sd);
|
||||||
{
|
|
||||||
OSG_NOTICE<<"Shadow texture unit is invalid for texgen, will not be used."<<std::endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sdl.push_back(sd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// increment counters.
|
// increment counters.
|
||||||
++textureUnit;
|
++textureUnit;
|
||||||
|
@ -1764,7 +1768,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 +3085,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 +3178,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 +3281,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 +3294,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;
|
||||||
|
|
|
@ -32,7 +32,7 @@ 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(osg::GLExtensions::Get(0, false)->glMaxTextureUnits - 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)
|
||||||
|
|
|
@ -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…
Reference in a new issue