綱要:渲染的時候只要標記出 陰影投影對象 和 陰影接收對象 就行了,其他的交給引擎就可以了。
實現步驟:
- 創建ShadowedScene對象。
- 標明 投射者和被投射者。
- 選擇一種陰影渲染技術,如 ShadowMap,ShadowVolume,ShadowTexture,SoftShadowMap等。
- 標明哪個物體是投射着哪個是被投射者。
- 之后將兩者及光照添加到ShadowedScene中進行渲染,參照http://www.osgchina.org/show.php?id=54。
#include <osg/Texture2D> #include <osg/Geometry> #include <osg/Geode> #include <osgDB/ReadFile> #include <osgUtil/SmoothingVisitor> #include <osgViewer/Viewer> #include <osg/PositionAttitudeTransform> #include <osg/MatrixTransform> #include <osgGA/TrackballManipulator> #include <osg/Material> #include <osgShadow/ShadowedScene> #include <osgShadow/ShadowVolume> #include <osgShadow/ShadowTexture> #include <osgShadow/ShadowMap> #include <osgShadow/SoftShadowMap> #include <osgShadow/ParallelSplitShadowMap> #include <osgUtil/Optimizer> osg::Vec4 lightPos(30.0f,-10.0f,20.0f,1.0f); //標識陰影接收對象 const int ReceivesShadowTraversalMask = 0x1; //標識陰影投影對象 const int CastsShadowTraversalMask = 0x2; class RotateCallback : public osg::NodeCallback { public: RotateCallback() : _rotateZ(0.0) {} virtual void operator()( osg::Node* node, osg::NodeVisitor* nv ) { osg::PositionAttitudeTransform* pat = dynamic_cast<osg::PositionAttitudeTransform*>( node ); if ( pat ) { osg::Quat quat( osg::DegreesToRadians(_rotateZ), osg::Z_AXIS ); pat->setAttitude( quat ); _rotateZ += 1.0; } traverse( node, nv ); } protected: double _rotateZ; }; //創建燈光 void createLight(osg::ref_ptr<osg::Group> lightRoot) { //lightRoot->addChild(node); //開啟光照 osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet(); stateset = lightRoot->getOrCreateStateSet(); stateset->setMode(GL_LIGHTING,osg::StateAttribute::ON); stateset->setMode(GL_LIGHT0,osg::StateAttribute::ON); //創建一個Light對象 osg::ref_ptr<osg::Light> light = new osg::Light(); light->setLightNum(0); //設置方向 light->setDirection(osg::Vec3(1.0f,1.0f,-1.0f)); //設置位置 light->setPosition(lightPos); //設置環境光的顏色 light->setAmbient(osg::Vec4(0.01f,0.01f,0.01f,1.0f)); //設置散射光的顏色 light->setDiffuse(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); ////設置恆衰減指數 //light->setConstantAttenuation(1.0f); ////設置線形衰減指數 //light->setLinearAttenuation(0.0f); ////設置二次方衰減指數 //light->setQuadraticAttenuation(0.0f); //創建光源 osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource(); lightSource->setLight(light.get()); lightRoot->addChild(lightSource.get()); return ; } //創建牆壁 osg::Drawable* createHouseWall() { // House vertices osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; //前面 vertices->push_back( osg::Vec3( 0.0, 0.0, 4.0) ); // 0 vertices->push_back( osg::Vec3( 0.0, 0.0, 0.0) ); // 1 vertices->push_back( osg::Vec3( 4.0, 0.0, 4.0) ); // 2 vertices->push_back( osg::Vec3( 4.0, 0.0, 0.0) ); // 3 //右面 vertices->push_back( osg::Vec3( 4.0, 4.0, 4.0) ); // 4 vertices->push_back( osg::Vec3( 4.0, 4.0, 0.0) ); // 5 //后面 vertices->push_back( osg::Vec3( 0.0, 4.0, 4.0) ); // 6 vertices->push_back( osg::Vec3( 0.0, 4.0, 0.0) ); // 7 //左面 vertices->push_back( osg::Vec3( 0.0, 0.0, 4.0) ); // 8 vertices->push_back( osg::Vec3( 0.0, 0.0, 0.0) ); // 9 // House normals osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array( 10 ); //左前 (*normals)[0].set(-1.0,-1.0, 0.0 ); (*normals)[1].set(-1.0,-1.0, 0.0 ); //右前 (*normals)[2].set( 1.0,-1.0, 0.0 ); (*normals)[3].set( 1.0,-1.0, 0.0 ); //右后 (*normals)[4].set( 1.0, 1.0, 0.0 ); (*normals)[5].set( 1.0, 1.0, 0.0 ); //左后 (*normals)[6].set(-1.0, 1.0, 0.0 ); (*normals)[7].set(-1.0, 1.0, 0.0 ); //左前 (*normals)[8].set(-1.0,-1.0, 0.0 ); (*normals)[9].set(-1.0,-1.0, 0.0 ); // House texture coordinates osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array( 10 ); //前面的左0.3 (*texcoords)[0].set( 0.0, 1.0 ); (*texcoords)[1].set( 0.0, 0.0 ); (*texcoords)[2].set( 1.0, 1.0 ); (*texcoords)[3].set( 1.0, 0.0 ); //右面0.2 (*texcoords)[4].set( 0.0, 1.0 ); (*texcoords)[5].set( 0.0, 0.0 ); //后面0.3 (*texcoords)[6].set( 1.0, 1.0 ); (*texcoords)[7].set( 1.0, 0.0 ); //左邊0.2 (*texcoords)[8].set( 0.0, 1.0 ); (*texcoords)[9].set( 0.0, 0.0 ); // House texture coordinates /*osg::ref_ptr<osg::Vec2Array> texcoords2 = new osg::Vec2Array( 10 ); //右面0.2 (*texcoords2)[4].set( 0.0, 1.0 ); (*texcoords2)[5].set( 0.0, 0.0 ); //后面0.3 (*texcoords2)[6].set( 1.0, 1.0 ); (*texcoords2)[7].set( 1.0, 0.0 ); //左邊0.2 (*texcoords2)[8].set( 0.0, 1.0 ); (*texcoords2)[9].set( 0.0, 0.0 );*/ // Create wall geometry osg::ref_ptr<osg::Geometry> houseWall = new osg::Geometry; houseWall->setVertexArray( vertices.get() ); houseWall->setTexCoordArray( 0, texcoords.get() ); // houseWall->setTexCoordArray( 1, texcoords2.get() ); houseWall->setNormalArray( normals.get() ); houseWall->setNormalBinding( osg::Geometry::BIND_PER_VERTEX ); houseWall->addPrimitiveSet( new osg::DrawArrays(osg::DrawArrays::QUAD_STRIP, 0, 10) ); houseWall->getOrCreateStateSet()->setTextureAttribute( 0,new osg::Texture2D(osgDB::readImageFile("C:\\55.jpg"))); houseWall->getOrCreateStateSet()->setTextureMode(0,GL_TEXTURE_2D,osg::StateAttribute::ON); houseWall->setNodeMask(CastsShadowTraversalMask); // houseWall->getOrCreateStateSet()->setTextureAttributeAndModes( 1,new osg::Texture2D(osgDB::readImageFile("C:\\55.jpg")) ); return houseWall.release(); } //創建大地 osg::Geometry* createGround(){ osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array; vertices->push_back(osg::Vec3(50,-50,-10)); vertices->push_back(osg::Vec3(50,50,-5)); vertices->push_back(osg::Vec3(-50,50,-5)); vertices->push_back(osg::Vec3(-50,-50,-10)); osg::ref_ptr<osg::Vec3Array> colours = new osg::Vec3Array; colours->push_back(osg::Vec3(255,255,0)); colours->push_back(osg::Vec3(0,255,0)); colours->push_back(osg::Vec3(0,255,0)); colours->push_back(osg::Vec3(0,255,0)); osg::Geometry *ground = new osg::Geometry; ground->setVertexArray(vertices); ground->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::QUADS,0,4)); ground->setColorArray(colours,osg::Array::BIND_PER_PRIMITIVE_SET); ground->setNodeMask(CastsShadowTraversalMask); return ground; } int main( int argc, char** argv ) { osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer(); osg::ref_ptr<osg::Group> root = new osg::Group(); //創建一個陰影節點,並標識接收對象和投影對象 osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new osgShadow::ShadowedScene(); shadowedScene->setReceivesShadowTraversalMask(ReceivesShadowTraversalMask); shadowedScene->setCastsShadowTraversalMask(CastsShadowTraversalMask); //創建陰影紋理 osg::ref_ptr<osgShadow::ShadowMap> st = new osgShadow::ShadowMap(); //osg::ref_ptr<osgShadow::ShadowTexture> st = new osgShadow::ShadowTexture(); //關聯陰影紋理 shadowedScene->setShadowTechnique(st); //添加光照 osg::ref_ptr<osg::Group> lightRoot = new osg::Group; createLight(lightRoot); shadowedScene->addChild(lightRoot.get()); //物體 osg::ref_ptr<osg::Geode> geode = new osg::Geode; geode->addDrawable( createHouseWall() ); //旋轉物體 osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform; pat->addChild( geode ); pat->setUpdateCallback( new RotateCallback ); shadowedScene->addChild(pat); shadowedScene->addChild(createGround()); root->addChild(shadowedScene); osgUtil::Optimizer optimizer ; optimizer.optimize(root.get()) ; viewer->setUpViewInWindow(20,20,400,400); viewer->setSceneData(root.get()); viewer->setCameraManipulator(new osgGA::TrackballManipulator); return viewer->run(); }
效果: