From 6df0110d0cee6daff55efcc2dabe4f995f9dd714 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 27 Sep 2007 12:47:34 +0000 Subject: [PATCH] From Adrian Egli, "update the PSSM, i did some bug fixes and added new features to move the camera virtual against the view direction by applaying a simple distance factor (a), which is calculated camera eye - camera center distance. and we can move the "light camera" against the light direction (b). (a) some objects behind the camera can cast shadow (b) object aboive the camera can cast shadow then i fixed the shadow map orientation, now screen x coordinate alinged which improve the quality" --- examples/osgshadow/osgshadow.cpp | 63 ++++++++++------- include/osgShadow/ParallelSplitShadowMap | 9 ++- src/osgShadow/ParallelSplitShadowMap.cpp | 90 ++++++++++++++---------- 3 files changed, 96 insertions(+), 66 deletions(-) diff --git a/examples/osgshadow/osgshadow.cpp b/examples/osgshadow/osgshadow.cpp index 711cb366e..f315a87b2 100644 --- a/examples/osgshadow/osgshadow.cpp +++ b/examples/osgshadow/osgshadow.cpp @@ -501,6 +501,7 @@ int main(int argc, char** argv) 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("--moveVCamFactor", "ParallelSplitShadowMap move the virtual frustum behind the real camera, (also back ground object can cast 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 @@ -576,31 +577,6 @@ int main(int argc, char** argv) // add stats viewer.addEventHandler( new osgViewer::StatsHandler() ); - osg::ref_ptr model = osgDB::readNodeFiles(arguments); - if (model.valid()) - { - model->setNodeMask(CastsShadowTraversalMask | ReceivesShadowTraversalMask); - } - else - { - model = createTestModel(arguments); - } - - // get the bounds of the model. - osg::ComputeBoundsVisitor cbbv; - model->accept(cbbv); - osg::BoundingBox bb = cbbv.getBoundingBox(); - - osg::Vec4 lightpos; - - if (postionalLight) - { - lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius() ,1.0f); - } - else - { - lightpos.set(0.5f,0.25f,0.8f,0.0f); - } osg::ref_ptr shadowedScene = new osgShadow::ShadowedScene; @@ -653,6 +629,14 @@ int main(int argc, char** argv) std::cout << "ParallelSplitShadowMap : setMaxFarDistance(" << maxfardist<<")" << std::endl; } + int moveVCamFactor = 0; + while (arguments.read("--moveVCamFactor", moveVCamFactor)) + if ( maxfardist > 0 ) { + pssm->setMoveVCamBehindRCamFactor(moveVCamFactor); + std::cout << "ParallelSplitShadowMap : setMoveVCamBehindRCamFactor(" << moveVCamFactor<<")" << std::endl; + } + + double polyoffsetfactor = -0.02; double polyoffsetunit = 1.0; while (arguments.read("--PolyOffset-Factor", polyoffsetfactor)); @@ -680,6 +664,33 @@ int main(int argc, char** argv) osg::ref_ptr sm = new osgShadow::ShadowMap; shadowedScene->setShadowTechnique(sm.get()); } + + osg::ref_ptr model = osgDB::readNodeFiles(arguments); + if (model.valid()) + { + model->setNodeMask(CastsShadowTraversalMask | ReceivesShadowTraversalMask); + } + else + { + model = createTestModel(arguments); + } + + // get the bounds of the model. + osg::ComputeBoundsVisitor cbbv; + model->accept(cbbv); + osg::BoundingBox bb = cbbv.getBoundingBox(); + + osg::Vec4 lightpos; + + if (postionalLight) + { + lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius() ,1.0f); + } + else + { + lightpos.set(0.5f,0.25f,0.8f,0.0f); + } + if ( arguments.read("--base")) { @@ -712,7 +723,7 @@ int main(int argc, char** argv) ls->getLight()->setAmbient(osg::Vec4(0.2,0.2,0.2,1.0)); ls->getLight()->setDiffuse(osg::Vec4(0.8,0.8,0.8,1.0)); } - + shadowedScene->addChild(model.get()); shadowedScene->addChild(ls.get()); diff --git a/include/osgShadow/ParallelSplitShadowMap b/include/osgShadow/ParallelSplitShadowMap index 33e4f91c9..ecadb09da 100644 --- a/include/osgShadow/ParallelSplitShadowMap +++ b/include/osgShadow/ParallelSplitShadowMap @@ -60,7 +60,10 @@ class OSGSHADOW_EXPORT ParallelSplitShadowMap : public ShadowTechnique /** Set the max far distance */ inline void setMaxFarDistance(double farDist) { _setMaxFarDistance = farDist; _isSetMaxFarDistance = true; } - /** Force to add a osg::CullFace::FRONT state */ + /** Set the factor for moving the virtual camera behind the real camera*/ + inline void setMoveVCamBehindRCamFactor(double distFactor ) { _move_vcam_behind_rcam_factor = distFactor; } + + /** Force to add a cull face front */ inline void forceFrontCullFace() { _useFrontCullFace = true; } /** Set min near distance for splits */ @@ -158,7 +161,9 @@ class OSGSHADOW_EXPORT ParallelSplitShadowMap : public ShadowTechnique bool _useFrontCullFace; double _split_min_near_dist; - + + double _move_vcam_behind_rcam_factor; + bool _linearSplit; }; diff --git a/src/osgShadow/ParallelSplitShadowMap.cpp b/src/osgShadow/ParallelSplitShadowMap.cpp index 7f7202740..ec4cd4a89 100644 --- a/src/osgShadow/ParallelSplitShadowMap.cpp +++ b/src/osgShadow/ParallelSplitShadowMap.cpp @@ -48,6 +48,7 @@ using namespace osgShadow; #define ZNEAR_MIN_FROM_LIGHT_SOURCE 2.0 +#define MOVE_VIRTUAL_CAMERA_BEHIND_REAL_CAMERA_FACTOR 0.0 //#define SHOW_SHADOW_TEXTURE_DEBUG // DEPTH instead of color for debug information texture display in a rectangle @@ -167,7 +168,8 @@ ParallelSplitShadowMap::ParallelSplitShadowMap(osg::Geode** gr, int icountplanes _isSetMaxFarDistance(false), _useFrontCullFace(false), _split_min_near_dist(ZNEAR_MIN_FROM_LIGHT_SOURCE), - _linearSplit(LINEAR_SPLIT) + _linearSplit(LINEAR_SPLIT), + _move_vcam_behind_rcam_factor(MOVE_VIRTUAL_CAMERA_BEHIND_REAL_CAMERA_FACTOR) { _displayTexturesGroupingNode = gr; _number_of_splits = icountplanes; @@ -188,8 +190,8 @@ ParallelSplitShadowMap::ParallelSplitShadowMap(const ParallelSplitShadowMap& cop _linearSplit(copy._linearSplit), _number_of_splits(copy._number_of_splits), _polgyonOffset(copy._polgyonOffset), - _setMaxFarDistance(copy._setMaxFarDistance) - + _setMaxFarDistance(copy._setMaxFarDistance), + _move_vcam_behind_rcam_factor(copy._move_vcam_behind_rcam_factor) { } @@ -668,8 +670,18 @@ void ParallelSplitShadowMap::calculateFrustumCorners( + osg::Matrixf viewMat; + osg::Vec3d camEye,camCenter,camUp; + pssmShadowSplitTexture._cameraView.getLookAt(camEye,camCenter,camUp); + osg::Vec3d viewDir = camCenter - camEye; + //viewDir.normalize(); + camEye = camEye - viewDir * _move_vcam_behind_rcam_factor; + camFar += _move_vcam_behind_rcam_factor * viewDir.length(); + viewMat.makeLookAt(camEye,camCenter,camUp); + + if ( _isSetMaxFarDistance ) { - if ( camNear + _setMaxFarDistance < camFar) camFar = camNear + _setMaxFarDistance; + if (_setMaxFarDistance < camFar) camFar = _setMaxFarDistance; } ////////////////////////////////////////////////////////////////////////// @@ -716,17 +728,15 @@ void ParallelSplitShadowMap::calculateFrustumCorners( ////////////////////////////////////////////////////////////////////////// /// TRANSFORM frustum corners (Optimized for Orthogonal) - osg::Matrixf invProjViewMat; + osg::Matrixf projMat; projMat.makePerspective(fovy,aspectRatio,camNear,camFar); - osg::Matrixf projViewMat(pssmShadowSplitTexture._cameraView*projMat); + + osg::Matrixf projViewMat(viewMat*projMat); invProjViewMat.invert(projViewMat); - - - //transform frustum vertices to world space frustumCorners[0] = const_pointFarBR * invProjViewMat; frustumCorners[1] = const_pointNearBR* invProjViewMat; @@ -764,45 +774,56 @@ void ParallelSplitShadowMap::calculateLightNearFarFormFrustum( // force zNear > 0.0 - // set 2.0m distance to the nearest point + // set _split_min_near_dist(2.0m) distance to the nearest point int count = 0; while (zNear <= _split_min_near_dist && count++ < 10) { + + // init zNear, zFar zNear= DBL_MAX; zFar =-DBL_MAX; + + // calculate zNear, zFar for(int i=0;i<8;i++) { double dist_z_from_light = pssmShadowSplitTexture._lightDirection*(frustumCorners[i] - pssmShadowSplitTexture._lightCameraSource); if ( zNear > dist_z_from_light ) zNear = dist_z_from_light; if ( zFar < dist_z_from_light ) zFar = dist_z_from_light; - } + } + // update if zNear too small if ( zNear <= _split_min_near_dist ){ osg::Vec3 dUpdate = - pssmShadowSplitTexture._lightDirection*(fabs(zNear)+_split_min_near_dist); pssmShadowSplitTexture._lightCameraSource = pssmShadowSplitTexture._lightCameraSource + dUpdate; } - } - pssmShadowSplitTexture._lightCameraTarget = pssmShadowSplitTexture._lightCameraSource + pssmShadowSplitTexture._lightDirection*zFar; - pssmShadowSplitTexture._lightNear = zNear; + pssmShadowSplitTexture._lightCameraTarget = pssmShadowSplitTexture._frustumSplitCenter;//pssmShadowSplitTexture._lightCameraSource + pssmShadowSplitTexture._lightDirection;//*zFar; + pssmShadowSplitTexture._lightNear = 0.1;//zNear; pssmShadowSplitTexture._lightFar = zFar; } void ParallelSplitShadowMap::calculateLightViewProjectionFormFrustum(PSSMShadowSplitTexture &pssmShadowSplitTexture,osg::Vec3d *frustumCorners) { ////////////////////////////////////////////////////////////////////////// - // light dir - osg::Vec3d lightDir = pssmShadowSplitTexture._lightDirection; - - osg::Vec3d up(0,1,0); + // calculate top, left + osg::Vec3d top(0,0,1); osg::Vec3d left; - osg::Vec3d top; + osg::Vec3d lightDir = pssmShadowSplitTexture._lightDirection; + lightDir.normalize(); + + osg::Vec3d camEye,camCenter,camUp; + pssmShadowSplitTexture._cameraView.getLookAt(camEye,camCenter,camUp); - left = up ^ lightDir; - top = lightDir ^ left; + osg::Vec3d viewDir(camCenter-camEye); + viewDir.normalize(); + + osg::Vec3d camLeft = camUp ^ viewDir; + camLeft.normalize(); + + top = lightDir ^ camLeft; + left = top ^ lightDir; - - double maxLeft,maxTop; + double maxLeft,maxTop; double minLeft,minTop; osg::Vec3d fCenter = pssmShadowSplitTexture._frustumSplitCenter; @@ -811,32 +832,25 @@ void ParallelSplitShadowMap::calculateLightViewProjectionFormFrustum(PSSMShadowS minLeft = minTop = DBL_MAX; for(int i = 0; i < 8; i++) { - osg::Vec3d diffCorner = fCenter - frustumCorners[i]; - double lLeft = (diffCorner*left) * 1.5; // scale, removes edges problem, faster for calculation - double lTop = (diffCorner*top) * 1.5; // scale, removes edges problem, faster for calculation + osg::Vec3d diffCorner = pssmShadowSplitTexture._frustumSplitCenter - frustumCorners[i]; + double lLeft = (diffCorner*left) * 1.41425; + double lTop = (diffCorner*top) * 1.41425; if ( lLeft > maxLeft ) maxLeft = lLeft; - if ( lTop > maxTop ) maxTop = lTop ; + if ( lTop > maxTop ) maxTop = lTop; if ( lLeft < minLeft ) minLeft = lLeft; - if ( lTop < minTop ) minTop = lTop ; - } + if ( lTop < minTop ) minTop = lTop; + } osg::Matrixd lightView; - lightView.makeLookAt(pssmShadowSplitTexture._lightCameraSource,pssmShadowSplitTexture._lightCameraTarget,up); + lightView.makeLookAt(pssmShadowSplitTexture._lightCameraSource,pssmShadowSplitTexture._lightCameraTarget,top); osg::Matrixd lightProj; - double zNear = pssmShadowSplitTexture._lightNear; - double zFar = pssmShadowSplitTexture._lightFar; - - lightProj.makeOrtho(minLeft,maxLeft,minTop,maxTop,zNear,zFar); - + lightProj.makeOrtho(minLeft,maxLeft,minTop,maxTop,pssmShadowSplitTexture._lightNear,pssmShadowSplitTexture._lightFar); pssmShadowSplitTexture._camera->setViewMatrix(lightView); pssmShadowSplitTexture._camera->setProjectionMatrix(lightProj); - - - }