osg利用osgShadow库添加阴影

纲要:渲染的时候只要标记出  阴影投影对象 和 阴影接收对象 就行了,其他的交给引擎就可以了。

  实现步骤:

  1. 创建ShadowedScene对象。
  2. 标明 投射者和被投射者。
  3. 选择一种阴影渲染技术,如 ShadowMapShadowVolumeShadowTextureSoftShadowMap等。
  4. 标明哪个物体是投射着哪个是被投射者。
  5. 之后将两者及光照添加到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();
}

效果:

posted @ 2018-11-21 18:56  一梦、  阅读(2416)  评论(0编辑  收藏  举报