前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用OSG创建一个简单的地形

使用OSG创建一个简单的地形

作者头像
charlee44
发布2022-05-05 21:53:09
1.6K0
发布2022-05-05 21:53:09
举报
文章被收录于专栏:代码编写世界

目录

1.解决方案

在网上参考了一些资料,使用OSG创建地形最简单的办法就是使用OSG::HeightField类,它是描述类似于DEM网格的四角面片。首先给出具体实现代码:

代码语言:javascript
复制
#include <iostream>
#include <Windows.h>

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osg/Texture2D>
#include <osg/ShapeDrawable>
#include <gdal_priv.h>

using namespace std;

using namespace osg;
using namespace osgViewer;

//实现函数:从高程图创建地形
osg::Node* createHeightField(std::string heightFile, std::string texFile)
{
	//读取高度文件
	GDALAllRegister();          //GDAL所有操作都需要先注册格式
	CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");  //支持中文路径
	GDALDataset* img = (GDALDataset *)GDALOpen(heightFile.c_str(), GA_ReadOnly);
	if (!img)
	{
		return nullptr;
	}

	//读取基本参数
	int imgWidth = img->GetRasterXSize();   //图像宽度
	int imgHeight = img->GetRasterYSize();  //图像高度
	int bandNum = img->GetRasterCount();    //波段数
	int depth = GDALGetDataTypeSize(img->GetRasterBand(1)->GetRasterDataType()) / 8;    //图像深度

	//获取地理坐标信息
	double padfTransform[6];
	if (img->GetGeoTransform(padfTransform) == CE_Failure)
	{
		return nullptr;
	}
	double startX = padfTransform[0] + 0.5 * padfTransform[1];			//左上角点坐标X
	double dX = padfTransform[1];			//X方向的分辨率		
	double startY = padfTransform[3] + padfTransform[5] * imgHeight - 0.5 * padfTransform[5];			//左下角点坐标Y
	double dY = -padfTransform[5];			//Y方向的分辨率

	//申请buf
	int bufWidth = imgWidth;
	int bufHeight = imgHeight;
	size_t imgBufNum = (size_t)bufWidth * bufHeight * bandNum;
	float *imgBuf = new float[imgBufNum];

	//读取
	size_t imgBufOffset = (size_t)bufWidth * (bufHeight - 1) * bandNum;
	img->RasterIO(GF_Read, 0, 0, bufWidth, bufHeight, imgBuf + imgBufOffset, bufWidth, bufHeight,
		GDT_Float32, bandNum, nullptr, bandNum*depth, -bufWidth*bandNum*depth, depth);

	//定义并设置高度文件
	osg::ref_ptr<osg::HeightField> heightField = new osg::HeightField();
	heightField->allocate(imgWidth, imgHeight);			//申请空间
	heightField->setOrigin(osg::Vec3(startX, startY, 0));			//起始位置	
	heightField->setXInterval(dX);			//间距X
	heightField->setYInterval(dY);			//间距Y
	heightField->setSkirtHeight(1.0f);

	//填充高度值
	for (int r = 0; r < imgHeight; r++)
	{
		for (int c = 0; c < imgWidth; c++)
		{
			size_t m = (size_t)r * imgWidth + c;
			heightField->setHeight(c, r, imgBuf[m]);
		}
	}

	//释放
	delete[] imgBuf;
	imgBuf = nullptr;

	//节点
	osg::Geode* geode = new osg::Geode();
	osg::ref_ptr<osg::ShapeDrawable> heightShape = new osg::ShapeDrawable(heightField.get());
	geode->addDrawable(heightShape);

	//设置纹理
	osg::ref_ptr<osg::Image> texImage = osgDB::readImageFile(texFile);
	osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
	tex->setImage(texImage);
	tex->setDataVariance(osg::Object::DYNAMIC);

	//渲染状态
	osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
	stateset->setTextureAttributeAndModes(0, tex.get(), osg::StateAttribute::ON);
	geode->setStateSet(stateset.get());

	return geode;
}

int main()
{	
	osgViewer::Viewer viewer;
	osg::ref_ptr<osg::Group> group = new osg::Group;

	std::string heightFile = "D:\\Data\\dst.tif";
	std::string texFile = "D:\\Data\\dom3_Level_19.jpg";
	group->addChild(createHeightField(heightFile, texFile));

	viewer.setSceneData(group);
	viewer.setUpViewInWindow(100, 100, 800, 600);
	return viewer.run();
}

其运行结果如下,显示的是美国大峡谷(Grand Canyon)中的一小块:

1) 使用TIF格式的DEM

因为不太清楚别的网上资料里面地形文件是jpg格式的,要知道jpg格式只能8位且没有地理信息,所以在这里我直接使用的是GTiff格式的DEM。很奇怪我这里用osgDB读取TIF文件失败了,所以直接采用了GDAL读取。

2) 描述HeightField

使用GDAL打开高程文件(DEM),能够获取地形的起点位置和间距,将其填充到HeightField中,这样OSG就确定了高程点的XY位置。在使用GDAL读取高程文件(DEM)存储的高程值到内存中之后,依次填充到HeightField,就确定了地形的Z位置。最后绘制到节点,地形图也就绘制出来了。

2.存在问题

可以看到我这里采用的纹理文件是一个处理好的,范围刚刚好能够覆盖的jpg文件。其纹理是自动贴到四个角点的。其实我最初的设想是采用一个DOM(正射影像图)来实现,通过其地理位置确定纹理坐标,最终无视范围大小,实现一个DEM(高程)与DOM(影像)的自动叠加。 问题就在于HeightField的点是内部绘制的,我给其赋予的纹理坐标总是不正确。我初步尝试发现一个网格点需要2个纹理坐标才能把整个纹理填满。在这里希望大家批评指正下,究竟如何给HeightField的点设置纹理位置。

3.参考文档

  1. osg三维重建的两种方法剖析:三角面片(osgUtil::DelaunayTriangulator)和四角面片(osg::HeightField)
  2. OSG从高程图创建地形-可运行
  3. OSG从高程图创建地形
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-03-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.解决方案
    • 1) 使用TIF格式的DEM
      • 2) 描述HeightField
      • 2.存在问题
      • 3.参考文档
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档