该示例程序主要讲述如何绘制地形,该示例程序在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/