osgShadow.SoftShadowMap是OpenSceneGraph库中实现软阴影映射的一种方法。该技术可以在场景中模拟阴影。该技术能够将阴影弥合并且使用纹理过滤器进行平滑处理,从而产生更加真实的光影效果。
SoftShadowMap技术是基于阴影映射实现的。它通过渲染场景两次,一次从光源视角,另一次从相机视角来获取阴影信息。这些信息然后通过纹理过滤器进行平滑处理并应用到场景中。
首先需要创建一个新的osgShadow::ShadowedScene类,并将场景图节点附加到它上面。接下来需要为光源和视角创建阴影映射,代码如下:
osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new osgShadow::ShadowedScene;
shadowedScene->setReceivesShadowTraversalMask( RECEIVES_SHADOW );
shadowedScene->setCastsShadowTraversalMask( CASTS_SHADOW );
osg::ref_ptr<osgShadow::SoftShadowMap> softShadowMap = new osgShadow::SoftShadowMap;
softShadowMap->setJitter( 0.5 );
softShadowMap->setSoftnessWidth( 0.003 );
shadowedScene->setShadowTechnique( softShadowMap.get() );
shadowedScene->addChild( sceneNode.get() );
需要为场景中的光源设置一些属性来确保正确性,例如设置阴影模式为OneLight。
osg::ref_ptr<osg::Light> light = new osg::Light;
light->setAmbient(osg::Vec4(0.2,0.2,0.2,1.0));
light->setDiffuse(osg::Vec4(0.8,0.8,0.8,1.0));
light->setConstantAttenuation(0.3f);
light->setQuadraticAttenuation(0.1f);
light->setDirection(osg::Vec3(1.0, 0.0, -0.5));
osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource;
lightSource->setLight(light.get());
lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
lightSource->setShadowTechnique(shadowedScene->getShadowTechnique());
lightSource->setStateSetModes(*sceneStateSet, osg::StateAttribute::ON);
需要将相机的遍历掩码设置为SHADOW_OCCLUDER,以确保只有相机可见的对象会生成阴影。此外,还需要设置相机的坐标系。
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setClearColor(osg::Vec4(0.5f,0.5f,0.5f,1.0f));
camera->setProjectionMatrixAsPerspective(90.0f, 1.0f, 1.0f, 10000.0f);
camera->setComputeNearFarMode( osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR );
camera->setViewport(0,0,SHADOW_TEXTURE_SIZE,SHADOW_TEXTURE_SIZE);
camera->setRenderOrder( osg::Camera::PRE_RENDER );
camera->setReferenceFrame( osg::Camera::ABSOLUTE_RF );
camera->setViewMatrix( lightSource->getLight()->getInverseMatrix() );
camera->setProjectionResizePolicy( osg::Camera::FIXED );
camera->setProjectionMatrix( osg::Matrixd::ortho(-200.0,200.0,-200.0,200.0,-20000.0,20000.0) );
camera->setCullMask(SHADOW_OCCLUDER);
在场景渲染循环中需要对场景进行两次渲染,从光源和相机的视角渲染:
while (!viewer.done())
{
viewer.frame();
// 渲染从光源视角看的场景
shadowedScene->renderShadowMap( *camera );
// 渲染从相机视角看的场景
viewer.getCamera()->setViewMatrixAsLookAt( osg::Vec3d(0.0,-10.0,0.0), osg::Vec3d(0.0,0.0,0.0), osg::Vec3d(0.0,0.0,1.0) );
viewer.getCamera()->setViewport(0,0,viewer.getCamera()->getGraphicsContext()->getTraits()->width,viewer.getCamera()->getGraphicsContext()->getTraits()->height);
viewer.getCamera()->setProjectionMatrixAsPerspective(45.0f, static_cast<double>(viewer.getCamera()->getGraphicsContext()->getTraits()->width)/static_cast<double>(viewer.getCamera()->getGraphicsContext()->getTraits()->height), 0.1f, 10000.0f);
viewer.getCamera()->setCullMask(osg::CullSettings::DEFAULT_OCCLUDER);
viewer.renderingTraversals();
}
OpenSceneGraph的官方示例中有一个使用SoftShadowMap的例子,路径为$OSG_DIR/examples/osgshadow。该例子可以通过命令行启动:
./osgshadow.exe
可以在窗口中看到一个木制的立方体和阴影。可以用鼠标拖动视角来查看场景。