From d11d5b819a5f5a502e069ce96a32d27143ffc0ad Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 24 Sep 2007 15:24:23 +0000 Subject: [PATCH] From Adrian Egli, further work on PSSM implementation. --- examples/osgshadow/osgshadow.cpp | 42 ++++++++++- include/osgShadow/ParallelSplitShadowMap | 44 +++++++++++- src/osgShadow/ParallelSplitShadowMap.cpp | 88 ++++++++++++++++-------- 3 files changed, 143 insertions(+), 31 deletions(-) diff --git a/examples/osgshadow/osgshadow.cpp b/examples/osgshadow/osgshadow.cpp index 7d830b696..711cb366e 100644 --- a/examples/osgshadow/osgshadow.cpp +++ b/examples/osgshadow/osgshadow.cpp @@ -499,7 +499,14 @@ int main(int argc, char** argv) arguments.getApplicationUsage()->addCommandLineOption("--mapcount", "ParallelSplitShadowMap texture count.");//ADEGLI arguments.getApplicationUsage()->addCommandLineOption("--mapres", "ParallelSplitShadowMap texture resolution.");//ADEGLI arguments.getApplicationUsage()->addCommandLineOption("--debug-color", "ParallelSplitShadowMap display debugging color (only the first 3 maps are color r=0,g=1,b=2.");//ADEGLI + arguments.getApplicationUsage()->addCommandLineOption("--minNearSplit", "ParallelSplitShadowMap shadow map near offset.");//ADEGLI + arguments.getApplicationUsage()->addCommandLineOption("--maxFarDist", "ParallelSplitShadowMap max far distance to shadow.");//ADEGLI + arguments.getApplicationUsage()->addCommandLineOption("--NVidea", "ParallelSplitShadowMap set default PolygonOffset for NVidea.");//ADEGLI + arguments.getApplicationUsage()->addCommandLineOption("--PolyOffset-Factor", "ParallelSplitShadowMap set PolygonOffset factor.");//ADEGLI + arguments.getApplicationUsage()->addCommandLineOption("--PolyOffset-Unit", "ParallelSplitShadowMap set PolygonOffset unit.");//ADEGLI + arguments.getApplicationUsage()->addCommandLineOption("--CullFaceFront", "ParallelSplitShadowMap add a cull face: front.");//ADEGLI + arguments.getApplicationUsage()->addCommandLineOption("-1", "Use test model one."); arguments.getApplicationUsage()->addCommandLineOption("-2", "Use test model two."); arguments.getApplicationUsage()->addCommandLineOption("-3", "Use test model three."); @@ -625,13 +632,42 @@ int main(int argc, char** argv) while (arguments.read("--mapcount", mapcount)); osg::ref_ptr pssm = new osgShadow::ParallelSplitShadowMap(NULL,mapcount); - unsigned int mapres = 1024; - while (arguments.read("--mapres", mapres)); - pssm->setTextureResolution(mapres); + int mapres = 1024; + while (arguments.read("--mapres", mapres)) + pssm->setTextureResolution(mapres); while (arguments.read("--debug-color")) { pssm->setDebugColorOn(); } + int minNearSplit=0; + while (arguments.read("--minNearSplit", minNearSplit)) + if ( minNearSplit > 0 ) { + pssm->setMinNearDistanceForSplits(minNearSplit); + std::cout << "ParallelSplitShadowMap : setMinNearDistanceForSplits(" << minNearSplit <<")" << std::endl; + } + + int maxfardist = 0; + while (arguments.read("--maxFarDist", maxfardist)) + if ( maxfardist > 0 ) { + pssm->setMaxFarDistance(maxfardist); + std::cout << "ParallelSplitShadowMap : setMaxFarDistance(" << maxfardist<<")" << std::endl; + } + + double polyoffsetfactor = -0.02; + double polyoffsetunit = 1.0; + while (arguments.read("--PolyOffset-Factor", polyoffsetfactor)); + while (arguments.read("--PolyOffset-Unit", polyoffsetunit)); + pssm->setPolygonOffset(osg::Vec2(polyoffsetfactor,polyoffsetunit)); //ATI Radeon + + if (arguments.read("--NVidea")){ + //pssm->setPolygonOffset(osg::Vec2(-0.02,1.0)); //ATI Radeon + pssm->setPolygonOffset(osg::Vec2(10.0f,20.0f)); //NVidea + } + + if ( arguments.read("--CullFaceFront") ) { + pssm->forceFrontCullFace(); + } + shadowedScene->setShadowTechnique(pssm.get()); } else if (arguments.read("--ssm")) diff --git a/include/osgShadow/ParallelSplitShadowMap b/include/osgShadow/ParallelSplitShadowMap index 53e5852e6..33e4f91c9 100644 --- a/include/osgShadow/ParallelSplitShadowMap +++ b/include/osgShadow/ParallelSplitShadowMap @@ -20,8 +20,9 @@ #include #include - + namespace osgShadow { + class OSGSHADOW_EXPORT ParallelSplitShadowMap : public ShadowTechnique { public: @@ -56,6 +57,38 @@ class OSGSHADOW_EXPORT ParallelSplitShadowMap : public ShadowTechnique /** Set the texture resolution */ inline void setTextureResolution(unsigned int resolution) { _resolution = resolution; } + /** Set the max far distance */ + inline void setMaxFarDistance(double farDist) { _setMaxFarDistance = farDist; _isSetMaxFarDistance = true; } + + /** Force to add a osg::CullFace::FRONT state */ + inline void forceFrontCullFace() { _useFrontCullFace = true; } + + /** Set min near distance for splits */ + inline void setMinNearDistanceForSplits(double nd){ _split_min_near_dist=nd; } + + /** use linear split (default: linear) */ + inline void useLinearSplit(bool flag) { _linearSplit = flag;} + + + /** + light / | + \ / | + min near dist / | + for splits / | + \ / ¦ | + ./ \ ¦ | + | \ ¦ | + | x ¦ | + | ¦ | + . | | + \ ¦ | + \ ¦ | + \ | + \ | + \ | + + .<- max far dist. ->. + */ protected : virtual ~ParallelSplitShadowMap() {} @@ -119,6 +152,15 @@ class OSGSHADOW_EXPORT ParallelSplitShadowMap : public ShadowTechnique unsigned int _resolution; + double _setMaxFarDistance; + bool _isSetMaxFarDistance; + + bool _useFrontCullFace; + + double _split_min_near_dist; + + bool _linearSplit; + }; } #endif diff --git a/src/osgShadow/ParallelSplitShadowMap.cpp b/src/osgShadow/ParallelSplitShadowMap.cpp index 8a5f0e8c0..7f7202740 100644 --- a/src/osgShadow/ParallelSplitShadowMap.cpp +++ b/src/osgShadow/ParallelSplitShadowMap.cpp @@ -19,6 +19,7 @@ /* ParallelSplitShadowMap written by Adrian Egli */ #include + #include #include #include @@ -32,9 +33,12 @@ #include #include + + using namespace osgShadow; + // split scheme #define TEXTURE_RESOLUTION 1024 //#define ADAPTIVE_TEXTURE_RESOLUTION @@ -109,32 +113,32 @@ std::string ParallelSplitShadowMap::generateGLSL_FragmentShader_BaseTex(bool deb if ( _debug_color_in_GLSL ) { - sstr << " float c0=0.5;" << std::endl; - sstr << " float c1=0.5;" << std::endl; - sstr << " float c2=0.5;" << std::endl; + sstr << " float c0=0.0;" << std::endl; + sstr << " float c1=0.0;" << std::endl; + sstr << " float c2=0.0;" << std::endl; + + sstr << " float sumTerm=0.0;" << std::endl; for (unsigned int i=0;i<_number_of_splits;i++) { - if ( i < 3 ) sstr << " c" << i << "=0.5+0.5*term" << i << ";" << std::endl; + if ( i < 3 ) sstr << " c" << i << "=term" << i << ";" << std::endl; + sstr << " sumTerm=sumTerm+term" << i << ";" << std::endl; } - sstr << " vec4 color = gl_Color*vec4(c0,c1,c2,1.0); " << std::endl; + sstr << " vec4 color = gl_Color * ( 1.0 - sumTerm ) + (sumTerm)* gl_Color*vec4(c0,(1.0-c0)*c1,(1.0-c0)*(1.0-c1)*c2,1.0); " << std::endl; - sstr << " vec4 texcolor = vec4(1,1,1,1); " << std::endl; } else { sstr << " vec4 color = gl_Color; "<< std::endl; - sstr << " vec4 texcolor = texture2D(baseTexture,gl_TexCoord[0].st); " << std::endl; } + sstr << " vec4 texcolor = texture2D(baseTexture,gl_TexCoord[0].st); " << std::endl; sstr << " float enableBaseTextureFilter = enableBaseTexture*(1.0 - step(texcolor.x+texcolor.y+texcolor.z+texcolor.a,0.0)); " << std::endl; //18 - sstr << " vec4 colorTex = color*texcolor;" << std::endl; + sstr << " vec4 colorTex = color*texcolor;" << std::endl; sstr << " gl_FragColor = (color*(1.0-enableBaseTextureFilter) + colorTex*enableBaseTextureFilter)*(1.0-0.30*v); "<< std::endl; - - sstr << "}"<< std::endl; @@ -159,7 +163,11 @@ ParallelSplitShadowMap::ParallelSplitShadowMap(osg::Geode** gr, int icountplanes _textureUnitOffset(1), _debug_color_in_GLSL(false), _user_polgyonOffset_set(false), - _resolution(TEXTURE_RESOLUTION) + _resolution(TEXTURE_RESOLUTION), + _isSetMaxFarDistance(false), + _useFrontCullFace(false), + _split_min_near_dist(ZNEAR_MIN_FROM_LIGHT_SOURCE), + _linearSplit(LINEAR_SPLIT) { _displayTexturesGroupingNode = gr; _number_of_splits = icountplanes; @@ -171,7 +179,17 @@ ParallelSplitShadowMap::ParallelSplitShadowMap(osg::Geode** gr, int icountplanes ParallelSplitShadowMap::ParallelSplitShadowMap(const ParallelSplitShadowMap& copy, const osg::CopyOp& copyop): ShadowTechnique(copy,copyop), _textureUnitOffset(copy._textureUnitOffset), - _number_of_splits(copy._number_of_splits) + _debug_color_in_GLSL(copy._debug_color_in_GLSL), + _user_polgyonOffset_set(copy._user_polgyonOffset_set), + _resolution(copy._resolution), + _isSetMaxFarDistance(copy._isSetMaxFarDistance), + _useFrontCullFace(copy._useFrontCullFace), + _split_min_near_dist(copy._split_min_near_dist), + _linearSplit(copy._linearSplit), + _number_of_splits(copy._number_of_splits), + _polgyonOffset(copy._polgyonOffset), + _setMaxFarDistance(copy._setMaxFarDistance) + { } @@ -243,7 +261,7 @@ void ParallelSplitShadowMap::init(){ break; } #endif - pssmShadowSplitTexture._camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); + pssmShadowSplitTexture._camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR); // set viewport pssmShadowSplitTexture._camera->setViewport(0,0,pssmShadowSplitTexture._resolution,pssmShadowSplitTexture._resolution); @@ -273,6 +291,13 @@ void ParallelSplitShadowMap::init(){ stateset->setAttribute(polygon_offset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); stateset->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); } + + if ( _useFrontCullFace ) { + osg::ref_ptr cull_face = new osg::CullFace; + cull_face->setMode(osg::CullFace::FRONT); + stateset->setAttribute(cull_face.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + } } // set up stateset and append texture, texGen ,... { @@ -304,7 +329,7 @@ void ParallelSplitShadowMap::init(){ osg::Uniform* shadowTextureSampler = new osg::Uniform(strST.str().c_str(),(int)(pssmShadowSplitTexture._textureUnit)); pssmShadowSplitTexture._stateset->addUniform(shadowTextureSampler); - //TODO: NOT YET SUPPORTED in the current version of the shader + //TODO: NOT YET SUPPORTED in the current version of the shader //std::stringstream strAB; strAB << "ambientBias" << (pssmShadowSplitTexture._textureUnit-1); //osg::Uniform* ambientBias = new osg::Uniform(strAB.str().c_str(),pssmShadowSplitTexture._ambientBias); //pssmShadowSplitTexture._stateset->addUniform(ambientBias); @@ -330,11 +355,11 @@ void ParallelSplitShadowMap::init(){ { // fake texture for baseTexture, add a fake texture - // we support by default at least one texture layer - // without this fake texture we can not support - // textured and not textured scene + // we support by default at least one texture layer + // without this fake texture we can not support + // textured and not textured scene - // TODO: at the moment the PSSM supports just one texture layer in the GLSL shader, multitexture are + // TODO: at the moment the PSSM supports just one texture layer in the GLSL shader, multitexture are // not yet supported ! osg::Image* image = new osg::Image; @@ -641,13 +666,18 @@ void ParallelSplitShadowMap::calculateFrustumCorners( double fovy,aspectRatio,camNear,camFar; pssmShadowSplitTexture._cameraProj.getPerspective(fovy,aspectRatio,camNear,camFar); + + + if ( _isSetMaxFarDistance ) { + if ( camNear + _setMaxFarDistance < camFar) camFar = camNear + _setMaxFarDistance; + } + ////////////////////////////////////////////////////////////////////////// /// CALCULATE SPLIT double maxFar = camFar; double minNear = camNear; double camNearFar_Dist = maxFar - camNear; - bool linear = LINEAR_SPLIT; - if ( linear ) { + if ( _linearSplit ) { camFar = camNear + (camNearFar_Dist) * ((double)(pssmShadowSplitTexture._splitID+1))/((double)(_number_of_splits)); camNear = camNear + (camNearFar_Dist) * ((double)(pssmShadowSplitTexture._splitID))/((double)(_number_of_splits)); } else { @@ -686,13 +716,17 @@ void ParallelSplitShadowMap::calculateFrustumCorners( ////////////////////////////////////////////////////////////////////////// /// TRANSFORM frustum corners (Optimized for Orthogonal) - osg::Matrixf projMat; - projMat.makePerspective(fovy,aspectRatio,camNear,camFar); - osg::Matrixf projViewMat = pssmShadowSplitTexture._cameraView*projMat; osg::Matrixf invProjViewMat; + + osg::Matrixf projMat; + projMat.makePerspective(fovy,aspectRatio,camNear,camFar); + osg::Matrixf projViewMat(pssmShadowSplitTexture._cameraView*projMat); invProjViewMat.invert(projViewMat); + + + //transform frustum vertices to world space frustumCorners[0] = const_pointFarBR * invProjViewMat; frustumCorners[1] = const_pointNearBR* invProjViewMat; @@ -709,7 +743,7 @@ void ParallelSplitShadowMap::calculateFrustumCorners( // // compute directional light inital postion; void ParallelSplitShadowMap::calculateLightInitalPosition(PSSMShadowSplitTexture &pssmShadowSplitTexture,osg::Vec3d *frustumCorners){ - pssmShadowSplitTexture._frustumSplitCenter = frustumCorners[0]; + pssmShadowSplitTexture._frustumSplitCenter = frustumCorners[0]; for(int i=1;i<8;i++) { pssmShadowSplitTexture._frustumSplitCenter +=frustumCorners[i]; } @@ -732,7 +766,7 @@ void ParallelSplitShadowMap::calculateLightNearFarFormFrustum( // force zNear > 0.0 // set 2.0m distance to the nearest point int count = 0; - while (zNear <= ZNEAR_MIN_FROM_LIGHT_SOURCE && count++ < 10) { + while (zNear <= _split_min_near_dist && count++ < 10) { zNear= DBL_MAX; zFar =-DBL_MAX; for(int i=0;i<8;i++) { @@ -741,8 +775,8 @@ void ParallelSplitShadowMap::calculateLightNearFarFormFrustum( if ( zFar < dist_z_from_light ) zFar = dist_z_from_light; } - if ( zNear <= ZNEAR_MIN_FROM_LIGHT_SOURCE ){ - osg::Vec3 dUpdate = - pssmShadowSplitTexture._lightDirection*(fabs(zNear)+ZNEAR_MIN_FROM_LIGHT_SOURCE); + if ( zNear <= _split_min_near_dist ){ + osg::Vec3 dUpdate = - pssmShadowSplitTexture._lightDirection*(fabs(zNear)+_split_min_near_dist); pssmShadowSplitTexture._lightCameraSource = pssmShadowSplitTexture._lightCameraSource + dUpdate; }