Changeset 13041 for OpenSceneGraph/trunk/src/osgShadow/MinimalShadowMap.cpp
 Timestamp:
 03/21/12 18:36:20 (2 years ago)
 Files:

 1 modified
Legend:
 Unmodified
 Added
 Removed

OpenSceneGraph/trunk/src/osgShadow/MinimalShadowMap.cpp
r12292 r13041 1 /* *c++* OpenSceneGraph  Copyright (C) 19982006 Robert Osfield 1 /* *c++* OpenSceneGraph  Copyright (C) 19982006 Robert Osfield 2 2 * 3 * This library is open source and may be redistributed and/or modified under 4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 3 * This library is open source and may be redistributed and/or modified under 4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 5 5 * (at your option) any later version. The full license is in LICENSE file 6 6 * included with this distribution, and on the openscenegraph.org website. 7 * 7 * 8 8 * This library is distributed in the hope that it will be useful, 9 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 11 * OpenSceneGraph Public License for more details. 12 12 * … … 25 25 #define PRINT_SHADOW_TEXEL_TO_PIXEL_ERROR 0 26 26 27 MinimalShadowMap::MinimalShadowMap(): 28 BaseClass(), 27 MinimalShadowMap::MinimalShadowMap(): 28 BaseClass(), 29 29 _maxFarPlane( FLT_MAX ), 30 30 _minLightMargin( 0 ), 31 31 _shadowReceivingCoarseBoundAccuracy( BOUNDING_BOX ) 32 32 { 33 33 34 34 } 35 35 … … 43 43 } 44 44 45 MinimalShadowMap::~MinimalShadowMap() 45 MinimalShadowMap::~MinimalShadowMap() 46 46 { 47 47 } … … 58 58 { 59 59 // One may skip coarse scene bounds computation if light is infinite. 60 // Empty box will be intersected with view frustum so in the end 60 // Empty box will be intersected with view frustum so in the end 61 61 // view frustum will be used as bounds approximation. 62 // But if light is nondirectional and bounds come out too large 63 // they may bring the effect of almost 180 deg perspective set 64 // up for shadow camera. Such projection will significantly impact 62 // But if light is nondirectional and bounds come out too large 63 // they may bring the effect of almost 180 deg perspective set 64 // up for shadow camera. Such projection will significantly impact 65 65 // precision of further math. 66 66 … … 87 87 frustum.cut( box ); 88 88 89 // approximate sphere with octahedron. Ie first cut by box then 89 // approximate sphere with octahedron. Ie first cut by box then 90 90 // additionaly cut with the same box rotated 45, 45, 45 deg. 91 91 box.transform( // rotate box around its center 92 92 osg::Matrix::translate( bs.center() ) * 93 osg::Matrix::rotate( osg::PI_4, 0, 0, 1 ) * 94 osg::Matrix::rotate( osg::PI_4, 1, 1, 0 ) * 93 osg::Matrix::rotate( osg::PI_4, 0, 0, 1 ) * 94 osg::Matrix::rotate( osg::PI_4, 1, 1, 0 ) * 95 95 osg::Matrix::translate( bs.center() ) ); 96 96 frustum.cut( box ); 97 98 return frustum.computeBoundingBox( ); 99 } 100 97 98 return frustum.computeBoundingBox( ); 99 } 100 101 101 if( accuracy == MinimalShadowMap::BOUNDING_BOX ) // Default 102 102 { 103 // more precise method but slower method 104 // bound visitor traversal takes lot of time for complex scenes 103 // more precise method but slower method 104 // bound visitor traversal takes lot of time for complex scenes 105 105 // (note that this adds to cull time) 106 106 … … 115 115 } 116 116 117 void MinimalShadowMap::ViewData::aimShadowCastingCamera( 117 void MinimalShadowMap::ViewData::aimShadowCastingCamera( 118 118 const osg::BoundingSphere &bs, 119 119 const osg::Light *light, 120 120 const osg::Vec4 &lightPos, 121 121 const osg::Vec3 &lightDir, 122 const osg::Vec3 &lightUpVector 122 const osg::Vec3 &lightUpVector 123 123 /* by default = osg::Vec3( 0, 1 0 )*/ ) 124 124 { … … 129 129 ( const osg::Light *light, const osg::Vec4 &lightPos, 130 130 const osg::Vec3 &lightDir, const osg::Vec3 &lightUp ) 131 { 131 { 132 132 osg::BoundingBox bb = computeScenePolytopeBounds(); 133 133 if( !bb.valid() ) { // empty scene or looking at the sky  substitute something … … 137 137 osg::Vec3 up = lightUp; 138 138 139 if( up.length2() <= 0 ) 139 if( up.length2() <= 0 ) 140 140 { 141 // This is extra step (not really needed but helpful in debuging) 141 // This is extra step (not really needed but helpful in debuging) 142 142 // Compute such lightUp vector that shadow cam is intuitively aligned with eye 143 143 // We compute this vector on ZY view plane, perpendicular to light direction … … 158 158 up.set( m( 2, 0 ), m( 2, 1 ), m( 2, 2 ) ); 159 159 #endif 160 } 160 } 161 161 162 162 aimShadowCastingCamera( osg::BoundingSphere( bb ), light, lightPos, lightDir, up ); … … 176 176 ( const osg::Camera* cameraMain, osg::Camera* cameraShadow, int pass ) 177 177 { 178 osg::Matrix mvp = 178 osg::Matrix mvp = 179 179 cameraShadow>getViewMatrix() * cameraShadow>getProjectionMatrix(); 180 180 … … 195 195 196 196 // So I replaced it with safer code working with spot lights as well 197 osg::Vec3d normal = 197 osg::Vec3d normal = 198 198 osg::Vec3d(0,0,1) * transform  osg::Vec3d(0,0,1) * transform; 199 199 … … 202 202 203 203 // Zero pass does crude shadowed scene hull approximation. 204 // Its important to cut it to coarse light frustum properly 204 // Its important to cut it to coarse light frustum properly 205 205 // at this stage. 206 // If not cut and polytope extends beyond shadow projection clip 207 // space (1..1), it may get "twisted" by precisely adjusted shadow cam 208 // projection in second pass. 206 // If not cut and polytope extends beyond shadow projection clip 207 // space (1..1), it may get "twisted" by precisely adjusted shadow cam 208 // projection in second pass. 209 209 210 210 if ( pass == 0 && _frameShadowCastingCameraPasses > 1 ) … … 223 223 } 224 224 225 setDebugPolytope( "extended", 225 setDebugPolytope( "extended", 226 226 _sceneReceivingShadowPolytope, osg::Vec4( 1, 0.5, 0, 1 ), osg::Vec4( 1, 0.5, 0, 0.1 ) ); 227 227 228 228 _sceneReceivingShadowPolytope = polytope; 229 229 _sceneReceivingShadowPolytopePoints = points; 230 231 // Warning: Trim light projection at near plane may remove shadowing 230 231 // Warning: Trim light projection at near plane may remove shadowing 232 232 // from objects outside of view space but still casting shadows into it. 233 233 // I have not noticed this issue so I left mask at default: all bits set. … … 236 236 237 237 ///// Debuging stuff ////////////////////////////////////////////////////////// 238 setDebugPolytope( "scene", _sceneReceivingShadowPolytope, osg::Vec4(0,1,0,1) ); 238 setDebugPolytope( "scene", _sceneReceivingShadowPolytope, osg::Vec4(0,1,0,1) ); 239 239 240 240 … … 254 254 frustum.transform( osg::Matrix::inverse( mvp ), mvp ); 255 255 256 setDebugPolytope( "shadowCamFrustum", frustum, osg::Vec4(0,0,1,1) ); 256 setDebugPolytope( "shadowCamFrustum", frustum, osg::Vec4(0,0,1,1) ); 257 257 } 258 258 … … 271 271 dump( *filename ); 272 272 filename>clear(); 273 } 273 } 274 274 } 275 275 } … … 284 284 285 285 // Redo steps from CullVisitor::popProjectionMatrix() 286 // which clamps projection matrix when Camera & Projection 286 // which clamps projection matrix when Camera & Projection 287 287 // completes traversal of their children 288 288 289 // We have to do this now manually 290 // because we did not complete camera traversal yet but 289 // We have to do this now manually 290 // because we did not complete camera traversal yet but 291 291 // we need to know how this clamped projection matrix will be 292 292 293 293 _cv>computeNearPlane(); 294 294 295 295 osgUtil::CullVisitor::value_type n = _cv>getCalculatedNearPlane(); 296 296 osgUtil::CullVisitor::value_type f = _cv>getCalculatedFarPlane(); … … 298 298 if( n < f ) 299 299 _cv>clampProjectionMatrix( _clampedProjection, n, f ); 300 } 301 302 // Aditionally clamp far plane if shadows don't need to be cast as 303 // far as main projection far plane 300 } 301 302 // Aditionally clamp far plane if shadows don't need to be cast as 303 // far as main projection far plane 304 304 if( 0 < *_maxFarPlanePtr ) 305 305 clampProjection( _clampedProjection, 0.f, *_maxFarPlanePtr ); 306 306 307 // Give derived classes chance to initialize _sceneReceivingShadowPolytope 307 // Give derived classes chance to initialize _sceneReceivingShadowPolytope 308 308 osg::BoundingBox bb = computeShadowReceivingCoarseBounds( ); 309 309 if( bb.valid() ) 310 310 _sceneReceivingShadowPolytope.setToBoundingBox( bb ); 311 else 311 else 312 312 _sceneReceivingShadowPolytope.clear(); 313 313 314 // Cut initial scene using main camera frustum. 315 // Cutting will work correctly on empty polytope too. 314 // Cut initial scene using main camera frustum. 315 // Cutting will work correctly on empty polytope too. 316 316 // Take into consideration near far calculation and _maxFarPlane variable 317 317 … … 337 337 338 338 void MinimalShadowMap::ViewData::cutScenePolytope 339 ( const osg::Matrix & transform, 340 const osg::Matrix & inverse, 339 ( const osg::Matrix & transform, 340 const osg::Matrix & inverse, 341 341 const osg::BoundingBox & bb ) 342 { 342 { 343 343 _sceneReceivingShadowPolytopePoints.clear(); 344 344 … … 347 347 polytope.setToBoundingBox( bb ); 348 348 polytope.transformProvidingInverse( inverse ); 349 _sceneReceivingShadowPolytope.cut( polytope ); 349 _sceneReceivingShadowPolytope.cut( polytope ); 350 350 _sceneReceivingShadowPolytope.getPoints 351 351 ( _sceneReceivingShadowPolytopePoints ); … … 354 354 } 355 355 356 osg::BoundingBox 356 osg::BoundingBox 357 357 MinimalShadowMap::ViewData::computeScenePolytopeBounds( const osg::Matrix & m ) 358 358 { … … 362 362 for( unsigned i = 0; i < _sceneReceivingShadowPolytopePoints.size(); ++i ) 363 363 bb.expandBy( _sceneReceivingShadowPolytopePoints[i] * m ); 364 else 364 else 365 365 for( unsigned i = 0; i < _sceneReceivingShadowPolytopePoints.size(); ++i ) 366 366 bb.expandBy( _sceneReceivingShadowPolytopePoints[i] ); … … 399 399 if( !bb.valid()  !( trimMask & (12481632) ) ) return; 400 400 double l, r, t, b, n, f; 401 bool ortho = projectionMatrix.getOrtho( l, r, b, t, n, f ); 401 bool ortho = projectionMatrix.getOrtho( l, r, b, t, n, f ); 402 402 if( !ortho && !projectionMatrix.getFrustum( l, r, b, t, n, f ) ) 403 403 return; // rotated or skewed or other crooked projection  give up … … 410 410 411 411 osg::Matrix projectionToView = osg::Matrix::inverse( projectionMatrix ); 412 412 413 413 osg::Vec3 min = 414 414 osg::Vec3( bb._min[0], bb._min[1], bb._min[2] ) * projectionToView; … … 453 453 } 454 454 455 if( ortho ) 455 if( ortho ) 456 456 projectionMatrix.makeOrtho( l, r, b, t, n, f ); 457 else 457 else 458 458 projectionMatrix.makeFrustum( l, r, b, t, n, f ); 459 459 #endif … … 480 480 } 481 481 n = new_near; 482 } 482 } 483 483 484 484 if( n < new_far && new_far < f ) { 485 f = new_far; 485 f = new_far; 486 486 } 487 487 … … 489 489 projection.makeFrustum( l, r, b, t, n, f ); 490 490 else 491 projection.makeOrtho( l, r, b, t, n, f ); 492 } 493 } 494 495 // Imagine following scenario: 491 projection.makeOrtho( l, r, b, t, n, f ); 492 } 493 } 494 495 // Imagine following scenario: 496 496 // We stand in the room and look through the window. 497 497 // How should our view change if we were looking through larger window ? 498 // In other words how should projection be adjusted if 499 // window had grown by some margin ? 498 // In other words how should projection be adjusted if 499 // window had grown by some margin ? 500 500 // Method computes such new projection which maintains perpective/world ratio 501 501 … … 515 515 516 516 osg::Matrix window = viewport>computeWindowMatrix(); 517 518 osg::Vec3 vMin( viewport>x()  margin.x(), 519 viewport>y()  margin.y(), 517 518 osg::Vec3 vMin( viewport>x()  margin.x(), 519 viewport>y()  margin.y(), 520 520 0.0 ); 521 521 522 osg::Vec3 vMax( viewport>width() + margin.x() * 2 + vMin.x(), 523 viewport>height() + margin.y() * 2 + vMin.y(), 522 osg::Vec3 vMax( viewport>width() + margin.x() * 2 + vMin.x(), 523 viewport>height() + margin.y() * 2 + vMin.y(), 524 524 0.0 ); 525 525 526 526 osg::Matrix inversePW = osg::Matrix::inverse( projection * window ); 527 527 528 528 vMin = vMin * inversePW; 529 529 vMax = vMax * inversePW; 530 531 l = vMin.x(); 530 531 l = vMin.x(); 532 532 r = vMax.x(); 533 b = vMin.y(); 533 b = vMin.y(); 534 534 t = vMax.y(); 535 535 536 536 if( frustum ) 537 537 projection.makeFrustum( l,r,b,t,n,f ); 538 else 538 else 539 539 projection.makeOrtho( l,r,b,t,n,f ); 540 540 }