osg示例程序解析之osgterrain


2010-07-10 11:30:38|  分类: osg开发|字号 订阅

该示例程序主要讲述如何绘制地形,该示例程序在main()函数中首先定义操纵器,并将定义的操纵器添加到osgGA::KeySwitchMatrixManipulator类中,实现按数字键切换不同的操纵器,主要代码如下:

//设置切换操纵器
 osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
 //按不同的数字键切换操纵器
 keyswitchManipulator->addMatrixManipulator('1',"Trackball",new osgGA::TrackballManipulator() );
 keyswitchManipulator->addMatrixManipulator('2',"Flight",new osgGA::FlightManipulator() );
 keyswitchManipulator->addMatrixManipulator('3',"Drive",new osgGA::DriveManipulator() );
 keyswitchManipulator->addMatrixManipulator('4',"Terrain",new osgGA::TerrainManipulator() );

根据输入的参数是否有动画路径文件,添加动画路径操纵器,代码如下:

std::string pasetElevationLayer thfile;
 char keyForAnimationPath='5';
 //如果输入动画路径文件
 while(arguments.read("-p",pathfile)){
 //定义动画路径操纵器
 osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
 //如果动画路径操纵器有效
  if(apm||!apm->valid()){
      //得到当前存储的操纵器数目
      unsigned int num=keyswitchManipulator->getNumMatrixManipulators();
       //添加动画路径操纵器
      keyswitchManipulator->addMatrixManipulator(keyForAnimationPath,"Path",apm );
      //设置为活动操纵器
      keyswitchManipulator->selectMatrixManipulator(num);
      //如果有多个动画路径文件继续创建操纵器并添加(如-p path1 -p path2等参数)
      ++keyForAnimationPath;
    }

 }
 //设置操纵器
 viewer.setCameraManipulator(keyswitchManipulator.get());

添加相应的事件处理,代码如下:

//添加事件处理
 viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
 //添加状态事件处理
 viewer.addEventHandler(new osgViewer::StatsHandler);
 //记录相机事件路径的事件处理
 viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);

构建地形的主要核心部分是根据输入的参数,确定地形建立的方式,主要构建地形的方式是使用osgTerrain::TerrainTile类,该类主要提供了根据高度数据绘制地形的架构,了解该类在绘制地形时的用法,也就了解了示例程序中参数的意义,使用osgTerrain::TerrainTile类绘制地形,主要使用的函数包括以下三个。

setLocato()函数设置地形坐标系统(投影、地理坐标)。

setElevationLayer()设置一个高度层,定义要绘制的高度数据。

 setColorLayer()设置地形颜色图像。

示例程序首先定义了和这三个函数相关的参数,如下代码所示:

osg::ref_ptr<osgTerrain::TerrainTile>terrainTile=new osgTerrain::TerrainTile;
osg::ref_ptr<osgTerrain::Locator>locator=new osgTerrain::Locator;
//设置高程无效数据

osg::ref_ptr<osgTerrain::ValidDataOperator>validDataOperator=new osgTerrain::NoDataValue(0.0);
osg::ref_ptr<osgTerrain::Layer>lastAppliedLayer;
 //设置坐标系统的类型(地球坐标,描述地球体)
 locator->setCoordinateSystemType(osgTerrain::Locator::GEOGRAPHIC);
 //设置坐标的范围值(x,y最小最大值)
 locator->setTransformAsExtents(x,y,x+w,y+h);

//设置层过滤的方式
 osgTerrain::Layer::Filter filter=osgTerrain::Layer::LINEAR;

下面的代码是读取输入的参数,和setLocato()函数相关的参数是:"-e"和"--cartesian",设置坐标的类型,代码如下:

//设置坐标系统为地理坐标并设置范围
 else if(arguments.read(pos,"-e",x,y,w,h)){
      // define the extents.
      locator->setCoordinateSystemType(osgTerrain::Locator::GEOGRAPHIC);
     locator->setTransformAsExtents(x,y,x+w,y+h);
     readParameter=true;
 }

//设置坐标为投影坐标,并设置范围
else if(arguments.read(pos, "--cartesian",x,y,w,h)){
    // define the extents.
    locator->setCoordinateSystemType(osgTerrain::Locator::PROJECTED);
    locator->setTransformAsExtents(x,y,x+w,y+h);
 }

和setElevationLayer()相关的参数包括:"--hf"和"-d",前者根据高度场数据建立高度数据层,后者根据高度图像文件建立高度层,示例代码如下:

else if(arguments.read(pos,"--hf",filename)){
   readParameter = true;
   osg::notify(osg::NOTICE)<<"--hf "<<filename<<std::endl;
    //读取高度场文件
   osg::ref_ptr<osg::HeightField>hf=osgDB::readHeightFieldFile(filename);
   if(hf.valid()){
    osg::ref_ptr<osgTerrain::HeightFieldLayer> hfl=new osgTerrain::HeightFieldLayer;
    //设置高度场
    hfl->setHeightField(hf.get());
    //设置坐标系
    hfl->setLocator(locator.get());
    hfl->setValidDataOperator(validDataOperator.get());
    //设置层的过滤方式

    hfl->setFilter(filter);
    if(offset!=0.0f || scale!=1.0f){
     hfl->transform(offset,scale);
    }
    //设置数据高程层
    terrainTile->setElevationLayer(hfl.get());
    lastAppliedLayer= hfl.get();
    osg::notify(osg::NOTICE)<<"created osgTerrain::HeightFieldLayer"<<std::endl;
   }
   else{
    osg::notify(osg::NOTICE)<<"failed to create osgTerrain::HeightFieldLayer"<<std::endl;
   }
   scale = 1.0f;
   offset = 0.0f;
  }
   //读取高程图像
  else if(arguments.read(pos,"-d",filename) || arguments.read(pos,"--elevation-image",filename)){
   readParameter = true;
   osg::notify(osg::NOTICE)<<"--elevation-image "<<filename<<std::endl;
   osg::ref_ptr<osg::Image> image=osgDB::readImageFile(filename);
   if(image.valid()){
    //定义图像层
    osg::ref_ptr<osgTerrain::ImageLayer> imageLayer = new osgTerrain::ImageLayer;
    imageLayer->setImage(image.get());
    imageLayer->setLocator(locator.get());
    imageLayer->setValidDataOperator(validDataOperator.get());
    imageLayer->setFilter(filter);
    //设置高程数据的缩放值
    if(offset!=0.0f || scale!=1.0f){
         imageLayer->transform(offset,scale);
    }
    terrainTile->setElevationLayer(imageLayer.get());
    lastAppliedLayer = imageLayer.get();
    osg::notify(osg::NOTICE)<<"created Elevation osgTerrain::ImageLayer"<<std::endl;
   }
   else{
    osg::notify(osg::NOTICE)<<"failed to create osgTerrain::ImageLayer"<<std::endl;
   }
   scale = 1.0f;
   offset = 0.0f;
  }

和setColorLayer()函数相关的参数是"-c",读取地形的纹理图片,贴图到地形表面,相关代码如下:

//读取地形颜色层图像
else if(arguments.read(pos,"-c",filename) || arguments.read(pos, "--image",filename)){
     readParameter = true;
     osg::notify(osg::NOTICE)<<"--image "<<filename<<" x="<<x<<" y="<<y<<" w="<<w<<" h="<<h<<std::endl;
     osg::ref_ptr<osg::Image>image=osgDB::readImageFile(filename);
     if(image.valid()){
        osg::ref_ptr<osgTerrain::ImageLayer>imageLayer=new osgTerrain::ImageLayer;
        imageLayer->setImage(image.get());
        imageLayer->setLocator(locator.get());
        imageLayer->setValidDataOperator(validDataOperator.get());
        imageLayer->setFilter(filter);
        if(offset!=0.0f || scale!=1.0f){
            imageLayer->transform(offset,scale);
        }
        //设置地形的颜色层
        terrainTile->setColorLayer(layerNum,imageLayer.get());
        lastAppliedLayer = imageLayer.get();
       osg::notify(osg::NOTICE)<<"created Color osgTerrain::ImageLayer"<<std::endl;
   }
   else{
       osg::notify(osg::NOTICE)<<"failed to create osgTerrain::ImageLayer"<<std::endl;
    }
    scale = 1.0f;
    offset = 0.0f;
}

设置完绘制地形所需的坐标系统、高度层、颜色层及其相关的属性后,就可以构建场景了,如下代码所示:

//创建场景
 osg::ref_ptr<osg::Group> scene = new osg::Group;
 //如果地形数据有效
 if(terrainTile.valid() && (terrainTile->getElevationLayer() || terrainTile->getColorLayer(0))){
        osg::notify(osg::NOTICE)<<"Terrain created"<<std::endl;
        scene->addChild(terrainTile.get());

        osg::ref_ptr<osgTerrain::GeometryTechnique> geometryTechnique = new    osgTerrain::GeometryTechnique;
        terrainTile->setTerrainTechnique(geometryTechnique.get());
        viewer.addEventHandler(new FilterHandler(geometryTechnique.get()));
        viewer.addEventHandler(new LayerHandler(lastAppliedLayer.get()));
 }

该示例程序看起来有很多的参数需要处理,其实我们只要抓住osgTerrain::TerrainTile类的三个核心函数,就不难理解示例程序绘制地形所使用的方法。


http://lzchenheng.blog.163.com/blog/static/838335362010610113038687/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值