osg for android 学习之五:场景漫游

时间:2021-07-15 16:08:53
需要实现这个,先把参考的文章列在这里

http://blog.csdn.net/tinya0913/article/details/6124167

效果很不错哦,希望在android上可以实现。

/**********************************************************
*Write by xuhy  
**********************************************************/

#pragma once

#include <osgViewer/Viewer>

#include <osg/LineSegment>
#include <osg/Point>
#include <osg/Geometry>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Group>
#include <osg/Vec3>

#include <osgGA/CameraManipulator>

#include <osgUtil/IntersectVisitor>

#include <vector>

class PersonWalkManipulator :
    public osgGA::CameraManipulator
{
public:

    //构造函数
    PersonWalkManipulator ();
    PersonWalkManipulator (osg::ref_ptr <osgViewer::Viewer> viewer);

    //析构函数
    ~PersonWalkManipulator(void);

    // 把漫游加入到场景之中
    static PersonWalkManipulator* TravelToScene(osg::ref_ptr <osgViewer::Viewer> viewer);

private:
    osg::ref_ptr <osgViewer::Viewer>    m_pHostViewer;

    //移动速度
    float m_fMoveSpeed;
    //
    osg::Vec3 m_vPosition;
    //
    osg::Vec3 m_vRotation;

public:

    //鼠标左键是否按下
    bool m_bLeftButtonDown  ;

    //鼠标X,Y
    float m_fpushY;

    float m_fpushX;

    //设置矩阵
    virtual void setByMatrix(const osg::Matrixd& matrix);
    //设置逆矩阵
    virtual void setByInverseMatrix(const osg::Matrixd& matrix);
    //得到矩阵
    virtual osg::Matrixd getMatrix(void) const;
    //得到逆矩阵
    virtual osg::Matrixd getInverseMatrix(void)const ;

    //事件处理函数
    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us);

    // 屏幕角度
    float m_fAngle;

    // 位置变换函数
    void ChangePosition(osg::Vec3& delta);

    //碰撞检测是否开启
    bool m_bPeng;

    //设置速度
    float getSpeed() ;

    void  setSpeed(float &) ;

    //设置起始位置
    void SetPosition(osg::Vec3 &position) ;

    osg::Vec3 GetPosition() ;

} ;





/**********************************************************
*Write by xuhy  
**********************************************************/

#include "PersonWalkManipulator.h"

//构造函数
PersonWalkManipulator::PersonWalkManipulator(): m_fMoveSpeed(0.3f)
, m_bLeftButtonDown(false)
, m_fpushX(0)
, m_fAngle(2.5)
, m_bPeng(true)
, m_fpushY(0)
{
    m_vPosition = osg::Vec3(0.0f, 0.0f, 1.7f);

    m_vRotation = osg::Vec3(osg::PI_2, 0.0f, 0.0f);        

}


PersonWalkManipulator::PersonWalkManipulator (osg::ref_ptr <osgViewer::Viewer> viewer): m_fMoveSpeed(0.3f)
, m_bLeftButtonDown(false)
, m_fpushX(0)
, m_fAngle(2.5)
, m_bPeng(true)
, m_fpushY(0)
{
    m_vPosition = osg::Vec3(0.0f, 0.0f, 1.7f);
    m_vRotation = osg::Vec3(osg::PI_2, 0.0f, 0.0f);        
    m_pHostViewer = viewer;
    //计算立足点的z值
    osg::ref_ptr<osg::LineSegment> lineZ = new osg::LineSegment(m_vPosition,
        osg::Vec3(0.0f, 0.0f, 0.0f)) ;

    osgUtil::IntersectVisitor findZ;
    findZ.addLineSegment(lineZ.get()) ;
    osg::Node* rt = m_pHostViewer->getSceneData();
    if(rt){
        rt->accept(findZ) ;

        osgUtil::IntersectVisitor::HitList hits;
        hits =     findZ.getHitList(lineZ.get());
        osgUtil::Hit newPositionResult;
        if ( !hits.empty() )
        {               
            newPositionResult = hits.front();
            osg::Vec3 newPos = newPositionResult.getWorldIntersectPoint();          
            m_vPosition =newPos + osg::Vec3(0.0,0.0,1.7f) ;

        }
    }
}



//析构函数
PersonWalkManipulator::~PersonWalkManipulator()
{
    //
}
// 把漫游加入到场景之中
PersonWalkManipulator * PersonWalkManipulator::TravelToScene(osg::ref_ptr <osgViewer::Viewer> viewer)
{
    PersonWalkManipulator* camera = new PersonWalkManipulator;

    viewer->setCameraManipulator(camera) ;

    camera->m_pHostViewer =viewer ;

    return camera;    
}

// 设置矩阵
void PersonWalkManipulator::setByMatrix(const osg::Matrixd& matrix)
{
    //
}
//设置逆矩阵
void PersonWalkManipulator::setByInverseMatrix(const osg::Matrixd& matrix)
{
    //
}
//得到矩阵
osg::Matrixd PersonWalkManipulator::getMatrix(void) const
{
    osg::Matrixd mat;

    mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f),

        m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f),

        m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));

    return mat * osg::Matrixd::translate(m_vPosition);
}
//得到逆矩阵
osg::Matrixd PersonWalkManipulator::getInverseMatrix(void) const
{
    osg::Matrixd mat;

    mat.makeRotate(m_vRotation._v[0], osg::Vec3(1.0f, 0.0f, 0.0f),

        m_vRotation._v[1], osg::Vec3(0.0f, 1.0f, 0.0f),

        m_vRotation._v[2], osg::Vec3(0.0f, 0.0f, 1.0f));

    return osg::Matrixd::inverse(mat * osg::Matrixd::translate(m_vPosition));
}
//事件处理函数
bool PersonWalkManipulator::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us)
{
    //得到鼠标的位置
    float mouseX = ea.getX();
    float mouseY = ea.getY();

    switch(ea.getEventType())
    {
    case(osgGA::GUIEventAdapter::KEYDOWN):
        {
            //空格键
            if (ea.getKey() == 0x20)
            {
                us.requestRedraw();

                us.requestContinuousUpdate(false);

                return true;
            }
            //上移动
            if (ea.getKey() == 0xFF50)
            {
                osg::Vec3 up(0, 0, m_fMoveSpeed);
                osg::Vec3& r_up = up;
                ChangePosition(r_up) ;
                return true;
            }
            //下移动
            if (ea.getKey() == 0xFF57)
            {
                osg::Vec3 down(0, 0, -m_fMoveSpeed);
                osg::Vec3& r_down = down;
                ChangePosition(r_down) ;

                return true;
            }
            //增加速度 右键
            if (ea.getKey() == 0x2B)
            {
                m_fMoveSpeed += 0.3f;

                return true;
            }
            //减少速度
            if (ea.getKey() == 0x2D)
            {
                m_fMoveSpeed -= 0.3f;

                if (m_fMoveSpeed < 0.3f)
                {
                    m_fMoveSpeed = 0.3f;
                }
                return true;
            }
            //前进
            if (ea.getKey() == 0xFF52 || ea.getKey () == 0x57 || ea.getKey () == 0x77)//up,w,f8
            {
                osg::Vec3 v1(0, m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]), 0);
                osg::Vec3& r_v1 = v1;
                ChangePosition(r_v1) ;

                osg::Vec3 v2(m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0, 0);
                osg::Vec3& r_v2 = v2;
                ChangePosition(r_v2) ;

                return true;
            }
            //后退
            if (ea.getKey() == 0xFF54 || ea.getKey () == 0x53 || ea.getKey () == 0x73 )//down s f4
            {

                osg::Vec3 v1(0, -m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]), 0);
                osg::Vec3& r_v1 = v1;
                ChangePosition(r_v1) ;

                osg::Vec3 v2(-m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0, 0);
                osg::Vec3& r_v2 = v2;
                ChangePosition(r_v2) ;

                return true;
            }
            //向左
            if (ea.getKey () == 0x41||ea.getKey () == 0x61)//a 数字键1
            {
                osg::Vec3 v1(0, m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0);
                osg::Vec3& r_v1 = v1;
                ChangePosition(r_v1) ;

                osg::Vec3 v2(-m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]), 0, 0);
                osg::Vec3& r_v2 = v2;
                ChangePosition(r_v2) ;

                return true;
            }
            //向右
            if (ea.getKey () == 0x44||ea.getKey () == 0x64) //d 数字键4
            {
                osg::Vec3 v1(0,-m_fMoveSpeed * cosf(osg::PI_2+m_vRotation._v[2]), 0);
                osg::Vec3& r_v1 = v1;
                ChangePosition(r_v1) ;

                osg::Vec3 v2(m_fMoveSpeed * sinf(osg::PI_2+m_vRotation._v[2]), 0, 0);
                osg::Vec3& r_v2 = v2;
                ChangePosition(r_v2) ;

                return true;
            }
            //Right
            if (ea.getKey() == 0xFF53)//右方向键
            {
                m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle);
            }
            //Left
            if (ea.getKey()== 0xFF51)
            {
                m_vRotation._v[2] += osg::DegreesToRadians(m_fAngle);
            }
            //改变屏角
            if (ea.getKey() == 0x46 || ea.getKey() == 0x66)//F 数字键6
            {
                m_fAngle -= 0.2 ;
                if(m_fAngle<0.2)
                {
                    m_fAngle = 0.2;
                }

                return true ;
            }

            if (ea.getKey() == 0x47 || ea.getKey() == 0x67)//G 数字键7
            {
                m_fAngle += 0.2 ;
                if(m_fAngle>2.5)
                {
                    m_fAngle = 2.5;
                }
                return true ;
            }

            return false;
        }
        //鼠标按下
    case (osgGA::GUIEventAdapter ::PUSH ):
        osg::notify(osg::ALWAYS)<<"PUSH";
        osg::notify(osg::ALWAYS)<<ea.getButton ()<<std::endl;
        if ( ea.getButton () == 1)
        {
            osg::notify(osg::ALWAYS)<<"1 PUSH"<<std::endl;
            m_fpushX = mouseX ;
            m_fpushY = mouseY ;

            m_bLeftButtonDown = true ;
        }

        return false ;

        //拖动
    case (osgGA::GUIEventAdapter ::DRAG ):
        osg::notify(osg::ALWAYS)<<"drag";
        osg::notify(osg::ALWAYS)<<m_bLeftButtonDown<<std::endl;
        if ( m_bLeftButtonDown)
        {
            osg::notify(osg::ALWAYS)<<"left drag"<<std::endl;
            m_vRotation._v[2] -= osg::DegreesToRadians(m_fAngle * (mouseX - m_fpushX)) / 1000;  
            m_vRotation._v[0] += osg::DegreesToRadians(m_fAngle * (mouseY - m_fpushY)) / 1000;  

            if (m_vRotation._v [0] >= 3.14)
            {
                m_vRotation._v [0] = 3.14 ;
            }

            if (m_vRotation._v [0] <= 0)
            {
                m_vRotation._v [0] = 0 ;
            }
        }

        return false ;
        //鼠标释放
    case (osgGA::GUIEventAdapter ::RELEASE ):

        osg::notify(osg::ALWAYS)<<"release"<<std::endl;
        if ( ea.getButton () == 1)
        {
            m_bLeftButtonDown = false ;
        }

        return false ;    

    default:
        return false;
    }
}

// 位置变换函数
void PersonWalkManipulator::ChangePosition(osg::Vec3& delta)
{
    //
    if (m_bPeng)
    {
        

        //得到新的位置
        osg::Vec3 newPos1 = m_vPosition + delta;

        //新位置合理性检测,新位置以下1.0米开始,1.4米的范围
        osg::ref_ptr<osg::LineSegment> lineZ = new osg::LineSegment(osg::Vec3(newPos1.x(),newPos1.y(),newPos1.z()-1.0f),
            osg::Vec3(newPos1.x(),newPos1.y(),newPos1.z()-2.4f)) ;

        osgUtil::IntersectVisitor findZ;
        findZ.addLineSegment(lineZ.get()) ;
        m_pHostViewer->getSceneData()->accept(findZ) ;

        osgUtil::IntersectVisitor::HitList hits;
        hits =
            findZ.getHitList(lineZ.get());
        osgUtil::Hit newPositionResult;
        if ( !hits.empty() )
        {               
            newPositionResult = hits.front();
            osg::Vec3 newPos = newPositionResult.getWorldIntersectPoint();          
            newPos += osg::Vec3(0.0,0.0,1.7f) ;
            //检查新位置是否够1.7米
            lineZ = new osg::LineSegment(newPos,newPos-osg::Vec3(0.0,0.0,1.69f) );
            osgUtil::IntersectVisitor findNewZ;
            findNewZ.addLineSegment(lineZ.get()) ;
            m_pHostViewer->getSceneData()->accept(findNewZ) ;
            hits = findNewZ.getHitList(lineZ.get());            
            if ( hits.empty() )//表示新位置够1.7米
            {               
                //检查是否遮挡
                 lineZ = new osg::LineSegment(m_vPosition,newPos);
                osgUtil::IntersectVisitor findWall;
                findWall.addLineSegment(lineZ.get()) ;
                 m_pHostViewer->getSceneData()->accept(findWall) ;
                 hits = findWall.getHitList(lineZ.get());            
                 if ( hits.empty() )//表示没有遮挡
                 {
                     m_vPosition=newPos;
                 }else
                 {
                     newPositionResult = hits.front();
                     osg::Vec3 newPos3 = newPositionResult.getWorldIntersectPoint();
                     osg::notify(osg::ALWAYS)<<newPos3.x()<<","<<newPos3.y()<<","<<newPos3.z()<<std::endl;

                 }
            }else
            {
                newPositionResult = hits.front();
                osg::Vec3 newPos2 = newPositionResult.getWorldIntersectPoint();
                osg::notify(osg::ALWAYS)<<newPos2.x()<<","<<newPos2.y()<<","<<newPos2.z()<<std::endl;

            }
        }

    }
    else
    {
        m_vPosition += delta;
    }
    /*
    //碰撞检测
    if (m_bPeng)
    {
    //得到新的位置
    osg::Vec3 newPos1 = m_vPosition + delta;

    osgUtil::IntersectVisitor ivXY;
    //根据新的位置得到两条线段检测
    osg::ref_ptr<osg::LineSegment> lineXY = new osg::LineSegment(newPos1,
    m_vPosition);

    osg::ref_ptr<osg::LineSegment> lineZ = new osg::LineSegment(newPos1,
    newPos1 + osg::Vec3(0.0f,0.0f,-0.5f)) ;

    ivXY.addLineSegment(lineZ.get()) ;

    ivXY.addLineSegment(lineXY.get()) ;
    //结构交集检测
    m_pHostViewer->getSceneData()->accept(ivXY) ;
    //如果没有碰撞检测
    if(!ivXY.hits())
    {
    m_vPosition += delta;
    }
    }
    else
    {
    m_vPosition += delta;
    }
    */
}

//设置速度
void PersonWalkManipulator::setSpeed (float &sp)
{
    m_fMoveSpeed = sp ;
}

//得到当前速度
float PersonWalkManipulator::getSpeed()
{
    return m_fMoveSpeed ;
}

//设置起始的位置
void PersonWalkManipulator::SetPosition (osg::Vec3 &position)
{
    m_vPosition = position ;
}

//得到当前的所在位置
osg::Vec3 PersonWalkManipulator::GetPosition ()
{
    return m_vPosition ;
}



/* OpenSceneGraph example, osglight.
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the "Software"), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*  THE SOFTWARE.
*/

#include <osgViewer/Viewer>

#include <osg/Group>
#include <osg/Node>

#include <osg/Light>
#include <osg/LightSource>
#include <osg/StateAttribute>
#include <osg/Geometry>
#include <osg/Point>
#include <osg/BlendFunc>
#include <osg/PointSprite>
#include <osg/ShapeDrawable>

#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>

#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/GUIEventAdapter>
#include <osgGA/MultiTouchTrackballManipulator>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>
#include <osgGA/SphericalManipulator>

#include <osgDB/Registry>
#include <osgDB/ReadFile>

#include <osgUtil/Optimizer>
#include <osgUtil/SmoothingVisitor>

#include "stdio.h"
#include "PersonWalkManipulator.h"


osg::StateSet* makeStateSet(float size)
{
    osg::StateSet *set = new osg::StateSet();

    ///// Setup cool blending
    //set->setMode(GL_BLEND, osg::StateAttribute::ON);
    //osg::BlendFunc *fn = new osg::BlendFunc();
    //fn->setFunction(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::DST_ALPHA);
    //set->setAttributeAndModes(fn, osg::StateAttribute::ON);

    /// Setup the point sprites
    osg::PointSprite *sprite = new osg::PointSprite();
    set->setTextureAttributeAndModes(0, sprite, osg::StateAttribute::ON);

    /// Give some size to the points to be able to see the sprite
    osg::Point *point = new osg::Point();
    point->setSize(size);
    set->setAttribute(point);

    // Disable depth test to avoid sort problems and Lighting
    //set->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
    set->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

    ///// The texture for the sprites
    //osg::Texture2D *tex = new osg::Texture2D();
    //tex->setImage(osgDB::readImageFile("Images/particle.rgb"));
    //set->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON);

    return set;
}

osg::Node* createLights(osg::BoundingBox& bb,osg::StateSet* rootStateSet)
{
    osg::Group* lightGroup = new osg::Group;

    float modelSize = bb.radius();

    // create a spot light.
    osg::Light* myLight1 = new osg::Light;
    myLight1->setLightNum(0);

    myLight1->setPosition(osg::Vec4(bb.corner(4),1.0f));//设置位置,第四个参数为0表示平行光
    myLight1->setAmbient(osg::Vec4(0.5f,0.5f,0.5f,1.0f));//设置环境光的颜色,第四个设为1,透明度
    myLight1->setDiffuse(osg::Vec4(1.0f,1.0f,1.0f,1.0f));//设置散射光的颜色
    //myLight1->setSpotCutoff(20.0f);// 聚光灯圆锥的顶角
    //myLight1->setSpotExponent(100.0f);// 聚光指数
    myLight1->setDirection(osg::Vec3(1.0f,1.0f,-1.0f));//设置方向

    osg::LightSource* lightS1 = new osg::LightSource;    
    lightS1->setLight(myLight1);
    lightS1->setLocalStateSetModes(osg::StateAttribute::ON);

    lightS1->setStateSetModes(*rootStateSet,osg::StateAttribute::ON);
    lightGroup->addChild(lightS1);   

    osg::ShapeDrawable* sd = new osg::ShapeDrawable(new osg::Sphere(bb.center(), 0.2));
    osg::Geode* lightNode = new osg::Geode;
    lightNode->addDrawable(sd);
    lightNode->getOrCreateStateSet()->setTextureAttributeAndModes(0, new osg::Texture2D(osgDB::readImageFile("Images/land_shallow_topo_2048.jpg")));
    lightGroup->addChild(lightNode);

    return lightGroup;
}

osg::ref_ptr<osg::Geode> makeCoordinate()
{
    //创建保存几何信息的对象
    osg::ref_ptr<osg::Geometry> geom = new osg::Geometry();

    //创建四个顶点
    osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array();
    v->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
    v->push_back(osg::Vec3(1000.0f, 0.0f, 0.0f));
    v->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
    v->push_back(osg::Vec3(0.0f, 1000.0f, 0.0f));
    v->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
    v->push_back(osg::Vec3(0.0f, 0.0f, 1000.0f));
    geom->setVertexArray(v.get());

    //为每个顶点指定一种颜色
    osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array();
    c->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); //坐标原点为红色
    c->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); //x red
    c->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); //坐标原点为绿色
    c->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f)); //y green
    c->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); //坐标原点为蓝色
    c->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f)); //z blue
    //如果没指定颜色则会变为黑色
    geom->setColorArray(c.get());
    geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);

    //三个轴
    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, 2)); //X LINES表示两个一组,第一个点和个数
    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINES, 2, 2)); //Y
    geom->addPrimitiveSet( new osg::DrawArrays(osg::PrimitiveSet::LINES, 4, 2)); //Z

    osg::ref_ptr<osg::Geode> geode = new osg::Geode();
    geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
    geode->addDrawable(geom.get());

    return geode;
}

int main( int argc, char **argv )
{
    osg::Node* _roomNode  = osgDB::readNodeFile("room.ive");
    
    // create a room made of foor walls, a floor, a roof, and swinging light fitting.
     osg::ref_ptr<osg::Group> root = new osg::Group();

    root->addChild(_roomNode);

    osg::BoundingSphere bs = _roomNode->getBound();
    osg::BoundingBox bb;
    bb.expandBy(bs);
    osg::ref_ptr<osg::StateSet> _state = root->getOrCreateStateSet();
    _state->setMode(GL_LIGHTING, osg::StateAttribute::ON);
    root->addChild( createLights(bb,_state));

    root->addChild(makeCoordinate().get());
    
    // run optimization over the scene graph
    osgUtil::Optimizer optimzer;
    optimzer.optimize(root.get());

     osg::ref_ptr<osgViewer::Viewer> _viewer= new osgViewer::Viewer();
    _viewer->setUpViewInWindow(50, 50, 800, 600);
    //把漫游器加入到场景中
    /*PersonWalkManipulator::TravelToScene(viewer.get());*/


    //_viewer->addEventHandler(new osgViewer::StatsHandler);
    _viewer->addEventHandler(new osgGA::StateSetManipulator(_viewer->getCamera()->getOrCreateStateSet()));
    //_viewer->addEventHandler(new osgViewer::ThreadingHandler);
    //_viewer->addEventHandler(new osgViewer::LODScaleHandler);

    // add a viewport to the viewer and attach the scene graph.
    _viewer->setSceneData( root.get() );    
    osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> _manipulator = new osgGA::KeySwitchMatrixManipulator;

    PersonWalkManipulator* pm = new PersonWalkManipulator(_viewer);
osgGA::TerrainManipulator* tm = new osgGA::TerrainManipulator();
    _manipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
    _manipulator->addMatrixManipulator( '2', "FirstPerson", pm );
    _manipulator->addMatrixManipulator( '3', "Flight", new osgGA::FlightManipulator() );
        _manipulator->addMatrixManipulator( '4', "Drive", new osgGA::DriveManipulator() );
        _manipulator->addMatrixManipulator( '5', "Terrain",tm );
        _manipulator->addMatrixManipulator( '6', "Orbit", new osgGA::OrbitManipulator() );
        _manipulator->addMatrixManipulator( '7', "FirstPerson", new osgGA::FirstPersonManipulator() );
        _manipulator->addMatrixManipulator( '8', "Spherical", new osgGA::SphericalManipulator() );
    _viewer->setCameraManipulator( _manipulator.get() );


    // create the windows and run the threads.
    _viewer->realize();

    _viewer->getCamera()->setCullingMode( _viewer->getCamera()->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING);

    return _viewer->run();
}