void ShadowMap::cull(osgUtil::CullVisitor& cv) { // record the traversal mask on entry so we can reapply it later. unsigned int traversalMask = cv.getTraversalMask(); osgUtil::RenderStage* orig_rs = cv.getRenderStage(); // do traversal of shadow receiving scene which does need to be decorated by the shadow map { cv.pushStateSet(_stateset.get()); _shadowedScene->osg::Group::traverse(cv); cv.popStateSet(); } // need to compute view frustum for RTT camera. // 1) get the light position // 2) get the center and extents of the view frustum const osg::Light* selectLight = 0; osg::Vec4 lightpos; osg::Vec3 lightDir; //MR testing giving a specific light osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList(); for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin(); itr != aml.end(); ++itr) { const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get()); if (light) { if( _light.valid()) { if( _light.get() == light ) selectLight = light; else continue; } else selectLight = light; osg::RefMatrix* matrix = itr->second.get(); if (matrix) { lightpos = light->getPosition() * (*matrix); lightDir = osg::Matrix::transform3x3( light->getDirection(), *matrix ); } else { lightpos = light->getPosition(); lightDir = light->getDirection(); } } } osg::Matrix eyeToWorld; eyeToWorld.invert(*cv.getModelViewMatrix()); lightpos = lightpos * eyeToWorld; lightDir = osg::Matrix::transform3x3( lightDir, eyeToWorld ); lightDir.normalize(); if (selectLight) { // set to ambient on light to black so that the ambient bias uniform can take it's affect const_cast<osg::Light*>(selectLight)->setAmbient(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); //std::cout<<"----- VxOSG::ShadowMap selectLight spot cutoff "<<selectLight->getSpotCutoff()<<std::endl; float fov = selectLight->getSpotCutoff() * 2; if(fov < 180.0f) // spotlight, then we don't need the bounding box { osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z()); _camera->setProjectionMatrixAsPerspective(fov, 1.0, 0.1, 1000.0); _camera->setViewMatrixAsLookAt(position,position+lightDir,computeOrthogonalVector(lightDir)); } else { // get the bounds of the model. osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask()); _shadowedScene->osg::Group::traverse(cbbv); osg::BoundingBox bb = cbbv.getBoundingBox(); if (lightpos[3]!=0.0) // point light { osg::Vec3 position(lightpos.x(), lightpos.y(), lightpos.z()); float centerDistance = (position-bb.center()).length(); float znear = centerDistance-bb.radius(); float zfar = centerDistance+bb.radius(); float zNearRatio = 0.001f; if (znear<zfar*zNearRatio) znear = zfar*zNearRatio; float top = (bb.radius()/centerDistance)*znear; float right = top; _camera->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar); _camera->setViewMatrixAsLookAt(position,bb.center(),computeOrthogonalVector(bb.center()-position)); } else // directional light { // make an orthographic projection osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z()); lightDir.normalize(); // set the position far away along the light direction osg::Vec3 position = bb.center() + lightDir * bb.radius() * 2; float centerDistance = (position-bb.center()).length(); float znear = centerDistance-bb.radius(); float zfar = centerDistance+bb.radius(); float zNearRatio = 0.001f; if (znear<zfar*zNearRatio) znear = zfar*zNearRatio; float top = bb.radius(); float right = top; _camera->setProjectionMatrixAsOrtho(-right, right, -top, top, znear, zfar); _camera->setViewMatrixAsLookAt(position,bb.center(),computeOrthogonalVector(lightDir)); } } cv.setTraversalMask( traversalMask & getShadowedScene()->getCastsShadowTraversalMask() ); // do RTT camera traversal _camera->accept(cv); _texgen->setMode(osg::TexGen::EYE_LINEAR); #if IMPROVE_TEXGEN_PRECISION // 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.5f,0.5f,0.5f) ); // Place texgen with modelview which removes big offsets (making it float friendly) osg::RefMatrix * refMatrix = new osg::RefMatrix ( _camera->getInverseViewMatrix() * *cv.getModelViewMatrix() ); cv.getRenderStage()->getPositionalStateContainer()-> addPositionedTextureAttribute( _shadowTextureUnit, refMatrix, _texgen.get() ); #else // compute the matrix which takes a vertex from local coords into tex coords // will use this later to specify osg::TexGen.. osg::Matrix MVPT = _camera->getViewMatrix() * _camera->getProjectionMatrix() * osg::Matrix::translate(1.0,1.0,1.0) * osg::Matrix::scale(0.5f,0.5f,0.5f); _texgen->setPlanesFromMatrix(MVPT); orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_shadowTextureUnit, cv.getModelViewMatrix(), _texgen.get()); #endif } // if(selectLight) // reapply the original traversal mask cv.setTraversalMask( traversalMask ); }
void ParallelSplitShadowMap::cull(osgUtil::CullVisitor& cv){ // record the traversal mask on entry so we can reapply it later. unsigned int traversalMask = cv.getTraversalMask(); osgUtil::RenderStage* orig_rs = cv.getRenderStage(); #ifdef SHADOW_TEXTURE_GLSL PSSMShadowSplitTextureMap::iterator it=_PSSMShadowSplitTextureMap.begin(); #else // do traversal of shadow receiving scene which does need to be decorated by the shadow map for (PSSMShadowSplitTextureMap::iterator it=_PSSMShadowSplitTextureMap.begin();it!=_PSSMShadowSplitTextureMap.end();it++) #endif { PSSMShadowSplitTexture pssmShadowSplitTexture = it->second; cv.pushStateSet(pssmShadowSplitTexture._stateset.get()); ////////////////////////////////////////////////////////////////////////// // DEBUG if ( _displayTexturesGroupingNode ) { cv.pushStateSet(pssmShadowSplitTexture._debug_stateset.get()); } ////////////////////////////////////////////////////////////////////////// _shadowedScene->osg::Group::traverse(cv); cv.popStateSet(); } // need to compute view frustum for RTT camera. // get the bounds of the model. osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask()); _shadowedScene->osg::Group::traverse(cbbv); ////////////////////////////////////////////////////////////////////////// const osg::Light* selectLight = 0; /// light pos and light direction osg::Vec4 lightpos; osg::Vec3 lightDirection; if ( ! _userLight ) { // try to find a light in the scene osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList(); for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin(); itr != aml.end(); ++itr) { const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get()); if (light) { osg::RefMatrix* matrix = itr->second.get(); if (matrix) lightpos = light->getPosition() * (*matrix); else lightpos = light->getPosition(); if (matrix) lightDirection = light->getDirection() * (*matrix); else lightDirection = light->getDirection(); selectLight = light; } } osg::Matrix eyeToWorld; eyeToWorld.invert(*cv.getModelViewMatrix()); lightpos = lightpos * eyeToWorld; lightDirection = lightDirection * eyeToWorld; }else{ // take the user light as light source lightpos = _userLight->getPosition(); lightDirection = _userLight->getDirection(); selectLight = _userLight.get(); } if (selectLight) { // do traversal of shadow receiving scene which does need to be decorated by the shadow map //unsigned int iMaxSplit = _PSSMShadowSplitTextureMap.size(); for (PSSMShadowSplitTextureMap::iterator it=_PSSMShadowSplitTextureMap.begin();it!=_PSSMShadowSplitTextureMap.end();it++) { PSSMShadowSplitTexture pssmShadowSplitTexture = it->second; ////////////////////////////////////////////////////////////////////////// // SETUP pssmShadowSplitTexture for rendering // lightDirection.normalize(); pssmShadowSplitTexture._lightDirection = lightDirection; pssmShadowSplitTexture._cameraView = cv.getRenderInfo().getView()->getCamera()->getViewMatrix(); pssmShadowSplitTexture._cameraProj = cv.getRenderInfo().getView()->getCamera()->getProjectionMatrix(); ////////////////////////////////////////////////////////////////////////// // CALCULATE // Calculate corner points of frustum split // // To avoid edge problems, scale the frustum so // that it's at least a few pixels larger // osg::Vec3d pCorners[8]; calculateFrustumCorners(pssmShadowSplitTexture,pCorners); // Init Light (Directional Light) // calculateLightInitialPosition(pssmShadowSplitTexture,pCorners); // Calculate near and far for light view // calculateLightNearFarFormFrustum(pssmShadowSplitTexture,pCorners); // Calculate view and projection matrices // calculateLightViewProjectionFormFrustum(pssmShadowSplitTexture,pCorners); ////////////////////////////////////////////////////////////////////////// // set up shadow rendering camera pssmShadowSplitTexture._camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); ////////////////////////////////////////////////////////////////////////// // DEBUG if ( _displayTexturesGroupingNode ) { pssmShadowSplitTexture._debug_camera->setViewMatrix(pssmShadowSplitTexture._camera->getViewMatrix()); pssmShadowSplitTexture._debug_camera->setProjectionMatrix(pssmShadowSplitTexture._camera->getProjectionMatrix()); pssmShadowSplitTexture._debug_camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); } ////////////////////////////////////////////////////////////////////////// // compute the matrix which takes a vertex from local coords into tex coords // will use this later to specify osg::TexGen.. osg::Matrix MVPT = pssmShadowSplitTexture._camera->getViewMatrix() * pssmShadowSplitTexture._camera->getProjectionMatrix() * osg::Matrix::translate(1.0,1.0,1.0) * osg::Matrix::scale(0.5,0.5,0.5); pssmShadowSplitTexture._texgen->setMode(osg::TexGen::EYE_LINEAR); pssmShadowSplitTexture._texgen->setPlanesFromMatrix(MVPT); ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// cv.setTraversalMask( traversalMask & getShadowedScene()->getCastsShadowTraversalMask() ); // do RTT camera traversal pssmShadowSplitTexture._camera->accept(cv); ////////////////////////////////////////////////////////////////////////// // DEBUG if ( _displayTexturesGroupingNode ) { pssmShadowSplitTexture._debug_camera->accept(cv); } orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(pssmShadowSplitTexture._textureUnit, cv.getModelViewMatrix(), pssmShadowSplitTexture._texgen.get()); } } // if light // reapply the original traversal mask cv.setTraversalMask( traversalMask ); }
void SoftShadowMap::cull(osgUtil::CullVisitor& cv) { // record the traversal mask on entry so we can reapply it later. unsigned int traversalMask = cv.getTraversalMask(); osgUtil::RenderStage* orig_rs = cv.getRenderStage(); // do traversal of shadow receiving scene which does need to be decorated by the shadow map { cv.pushStateSet(_stateset.get()); _shadowedScene->osg::Group::traverse(cv); cv.popStateSet(); } // need to compute view frustum for RTT camera. // 1) get the light position // 2) get the center and extents of the view frustum const osg::Light* selectLight = 0; osg::Vec4 lightpos; osgUtil::PositionalStateContainer::AttrMatrixList& aml = orig_rs->getPositionalStateContainer()->getAttrMatrixList(); for(osgUtil::PositionalStateContainer::AttrMatrixList::iterator itr = aml.begin(); itr != aml.end(); ++itr) { const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get()); if (light) { osg::RefMatrix* matrix = itr->second.get(); if (matrix) lightpos = light->getPosition() * (*matrix); else lightpos = light->getPosition(); selectLight = light; } } osg::Matrix eyeToWorld; eyeToWorld.invert(*cv.getModelViewMatrix()); lightpos = lightpos * eyeToWorld; if (selectLight) { // get the bounds of the model. osg::ComputeBoundsVisitor cbbv(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); cbbv.setTraversalMask(getShadowedScene()->getCastsShadowTraversalMask()); _shadowedScene->osg::Group::traverse(cbbv); osg::BoundingBox bb = cbbv.getBoundingBox(); osg::Vec3 position; if (lightpos[3]!=0.0) { position.set(lightpos.x(), lightpos.y(), lightpos.z()); } else { // make an orthographic projection osg::Vec3 lightDir(lightpos.x(), lightpos.y(), lightpos.z()); lightDir.normalize(); // set the position far away along the light direction position = lightDir * bb.radius() * 20; } float centerDistance = (position-bb.center()).length(); float znear = centerDistance-bb.radius(); float zfar = centerDistance+bb.radius(); float zNearRatio = 0.001f; if (znear<zfar*zNearRatio) znear = zfar*zNearRatio; float top = bb.radius(); float right = top; _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); _camera->setProjectionMatrixAsOrtho(-right, right, -top, top, znear, zfar); _camera->setViewMatrixAsLookAt(position, bb.center(), osg::Vec3(0.0f,1.0f,0.0f)); // compute the matrix which takes a vertex from local coords into tex coords // will use this later to specify osg::TexGen.. osg::Matrix MVPT = _camera->getViewMatrix() * _camera->getProjectionMatrix() * osg::Matrix::translate(1.0,1.0,1.0) * osg::Matrix::scale(0.5,0.5,0.5+_bias); _texgen->setMode(osg::TexGen::EYE_LINEAR); _texgen->setPlanesFromMatrix(MVPT); cv.setTraversalMask( traversalMask & getShadowedScene()->getCastsShadowTraversalMask() ); // do RTT camera traversal _camera->accept(cv); orig_rs->getPositionalStateContainer()->addPositionedTextureAttribute(_textureUnit, cv.getModelViewMatrix(), _texgen.get()); } // reapply the original traversal mask cv.setTraversalMask( traversalMask ); }