【小沐学GIS】基于OpenSceneGraph(OSG)绘制三维数字地球Earth

发布时间:2024年01月15日
🍺三维数字地球系列相关文章如下🍺:
1【小沐学GIS】基于C++绘制三维数字地球Earth(OpenGL、glfw、glut)第一期
2【小沐学GIS】基于C++绘制三维数字地球Earth(OpenGL、glfw、glut)第二期
3【小沐学GIS】基于OpenSceneGraph(OSG)绘制三维数字地球Earth

1、简介

OpenSceneGraph是一个开源的三维引擎,被广泛的应用在可视化仿真、游戏、虚拟现实、科学计算、三维重建、地理信息、太空探索、石油矿产等领域。OSG采用标准C++和OpenGL编写而成,可运行在所有的Windows平台、OSX、GNU/Linux、IRIX、Solaris、HP-Ux、AIX、Android和FreeBSD 操作系统。
在这里插入图片描述

OSG是有版权的开源引擎,基于LGPL,OSG也生成了自己的许可(OSGPL)。
在这里插入图片描述
官网地址:
https://www.openscenegraph.com/

在这里插入图片描述
https://github.com/openscenegraph/OpenSceneGraph
在这里插入图片描述
(1)快速开发。OSG场景图形内封装了几乎全部的OpenGL底层接口,并随时支持最新的扩展特性。应用程序的开发者可以将中心放在三维程序开发的实质性内容以及与各种场景对象交互的方法上,而不再过多关注底层的代码。

(2)高品质。OSG经历了许多开发成员的反复检查、测试和改善,参与OSG核心代码开发并有贡献的人数很多。

(3)高性能。OSG的核心代码支持多种场景的裁剪技术、细节层次节点、渲染状态排序、顶点数组、显示列表、VBO、PBO、FBO、OpenGL着色器语言等;以及文字显示,粒子系统,阴影系统;雨、雪、火焰、烟雾等特效模拟,场景的东塔调度,线程渲染等各种机制。它们共同使OSG逐渐成为一个高性能的三维渲染引擎。

(4)高质量代码

(5)可扩展性。基于场景图形的扩展思想,OSG提供了强大的可扩展能力,包括各种类型的扩展节点(NodeKits,节点工具箱)、扩展渲染属性、扩展回调、扩展交互事件处理器等,为用户的程序开发提供了灵活的支持能力。

(6)可移植性。OSG提供了Windows、UNIX、Linux、Mac OS X、IRIX、Solaris、HP-UX、AIX和FreeBSD系统的移植能力,基于OSG开发的程序只要经过一次编写,就可以编译并运行在这些平台上,不需要关心更多的代码移植的细节。

(7)低费用。开源意味着免费,使用和发布基于OSG开发的程序和软件是不需要额外许可费用的。

(8)没有知识产权问题。对于开源且易于所有人阅读的代码而言,不存在侵犯软件专利的可能性。

2、下载和编译

2.1 下载OSG源码

https://www.openscenegraph.com/index.php/download-section/stable-releases
在这里插入图片描述
解压后文件夹如下:
在这里插入图片描述

2.2 下载OSG编译后的二进制文件

https://objexx.com/OpenSceneGraph.html
在这里插入图片描述
解压后文件夹如下:
在这里插入图片描述

2.3 下载OSG依赖的第三方库文件

http://www.openscenegraph.com/index.php/download-section/dependencies
在这里插入图片描述
解压后文件夹如下:
在这里插入图片描述

2.4 下载OSG测试数据和文件

http://www.openscenegraph.com/index.php/download-section/data
数据资源页面提供了指向 OpenSceneGraph 可读取的各种数据库和影像文件的链接。

在这里插入图片描述
解压后文件夹如下:
在这里插入图片描述
通过cmake自动生成vs2017的工程打开如下:
在这里插入图片描述

3、代码测试

3.1 绘制最简单的形状

#include<osg/ShapeDrawable>
#include<osg/Geode>
#include<osgViewer/Viewer>

int main(int argc, char *argv[]){
    (void) argc;
    (void) argv;
    
    osg::ref_ptr<osg::ShapeDrawable> shape1 = new osg::ShapeDrawable;
    shape1->setShape(new osg::Box(osg::Vec3(-3.0f, 0.0f, 0.0f), 2.0f, 2.0f, 1.0f));
    
    osg::ref_ptr<osg::ShapeDrawable> shape2 = new osg::ShapeDrawable;
    shape2->setShape(new osg::Cone(osg::Vec3(0.0f, 0.0f, 0.0f), 1.0f, 1.0f));
    shape2->setColor(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
    
    osg::ref_ptr<osg::ShapeDrawable> shape3 = new osg::ShapeDrawable;
    shape3->setShape(new osg::Sphere(osg::Vec3(3.0f, 0.0f, 0.0f), 1.0f));
    shape3->setColor(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
    
    osg::ref_ptr<osg::Geode> root = new osg::Geode;
    root->addDrawable(shape1.get());
    root->addDrawable(shape2.get());
    root->addDrawable(shape3.get());
    
    osgViewer::Viewer viewer;
    viewer.setSceneData(root.get());
    
    return viewer.run();
}

在这里插入图片描述

3.2 绘制一个彩色正方形


#include<osg/Geometry>
#include<osg/Geode>
#include<osgViewer/Viewer>

int main(int argc, char *argv[]) {

	osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
	vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
	vertices->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
	vertices->push_back(osg::Vec3(1.0f, 0.0f, 1.0f));
	vertices->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));

	osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array;
	normals->push_back(osg::Vec3(0.0f, -1.0f, 0.0f));

	osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array;
	colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
	colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
	colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
	colors->push_back(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));

	osg::ref_ptr<osg::Geometry> quad = new osg::Geometry;
	quad->setVertexArray(vertices.get());
	quad->setNormalArray(normals.get());
	quad->setNormalBinding(osg::Geometry::BIND_OVERALL);
	quad->setColorArray(colors.get());
	quad->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
	quad->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));

	osg::ref_ptr<osg::Geode> root = new osg::Geode;
	root->addDrawable(quad.get());

	osgViewer::Viewer viewer;
	viewer.setSceneData(root.get());

	return viewer.run();
}

在这里插入图片描述

3.3 绘制多个模型文件

#include <osg/Node>
#include <osgDB/ReadFile>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>

int main(int argc, char* argv[])
{
	osgViewer::Viewer viewer;
	osg::ref_ptr<osg::Group> root = new osg::Group;
	osg::ref_ptr<osg::Group> group = new osg::Group;

	root->addChild(osgDB::readNodeFile("glider.osg"));
    group->addChild(osgDB::readNodeFile("axes.osgt"));
	root->addChild(group);

	viewer.setSceneData(root);
	viewer.realize();

	viewer.addEventHandler(new osgViewer::WindowSizeHandler);
	viewer.addEventHandler(new osgViewer::StatsHandler);

	return viewer.run();

}

在这里插入图片描述

3.4 绘制osg模型文件

#include "osgViewer/Viewer"
#include "osgDB/ReadFile"

int main(int argc, char** argv)
{
	osgViewer::Viewer viewer;
	viewer.setSceneData(osgDB::readNodeFile("cow.osg"));
	return viewer.run();
}

在这里插入图片描述

3.5 绘制osgb倾斜摄影模型文件

#include <iostream>
#include <Windows.h>

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>

using namespace std;

int main()
{
	string osgPath = "Tile_+000_+000.osgb";
	osg::Node * node = osgDB::readNodeFile(osgPath);
	osgViewer::Viewer viewer;
	viewer.setSceneData(node);
	viewer.setUpViewInWindow(100, 100, 800, 600);
	return viewer.run();
}

在这里插入图片描述

3.6 绘制简化模型

#include <osg/Node> //节点类
#include <osg/Geode> //是个几何节点,可以说是一个几何Group节点,一般的可绘制几何体都是通过它来传向root进行渲染,是OSG几何绘制的最高管理节点
#include <osg/Group> //对节点起到组织作用,一般作为父节点或者根节点出现
#include <osg/PositionAttitudeTransform> //位置变换节点类,提供模型的位置变换、大小缩放、原点位置的设置、坐标系的变换
#include <osgDB/ReadFile>
#include <osgDB/WriteFile> 
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers> //事件监听
#include <osgGA/StateSetManipulator> //事件响应类,对渲染状态进行控制
#include <osgUtil/Optimizer> //优化器
#include <osgUtil/Simplifier> //简化几何体

/*
加载一个模型
深拷贝该模型到其他地方
对深拷贝的模型进行简化
将两个模型添加到叶节点
对场景进行优化
显示模型
按w键显示网格化模型,可以看出网格密度不同
按t键显示去表皮模型,可以看出模型相同
*/

//读取模型
osg::Node *readModel()
{
	osg::ref_ptr<osg::Node> node = osgDB::readNodeFile("cow.osg");
	return node.release();
}

//深拷贝并简化新模型
osg::Node *deepCopy(osg::Node *node)
{
	/*
	创建简化对象
	simplifier(sampleRatio, maxError)
	参数:样本比率、点的误差或边的长度
	样本比率<1 设置点的误差
	样本比率>1 设置边的长度限制
	比率越大,简化越少
	使用的是边塌陷算法
	*/
	float sampleRatio = 0.3f;
	float maxError = 4.0f;
	osgUtil::Simplifier simplifier(sampleRatio, maxError);

	//深拷贝
	osg::ref_ptr<osg::Node> deepnode = (osg::Node *)(node->clone(osg::CopyOp::DEEP_COPY_ALL));
	//创建一个位置变换节点,将之设置为新位置,将深拷贝的模型移到新位置
	osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform();
	pat->setPosition(osg::Vec3(10.0f, 0.0f, 0.0f));
	pat->addChild(deepnode);

	pat->accept(simplifier);

	return pat.release();
}

int main()
{
	//创建一个叶节点对象并添加节点 
	osg::ref_ptr<osg::Group> root = new osg::Group();
	osg::ref_ptr<osg::Node> node1 = readModel();
	osg::ref_ptr<osg::Node> node2 = deepCopy(node1);
	root->addChild(node1);
	root->addChild(node2);

	//优化场景数据
	osgUtil::Optimizer optimizer;
	optimizer.optimize(root.get());

	//显示模型
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer();
	//切换网格模式,方便比较
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	viewer->setSceneData(root.get());
	viewer->realize();

	return viewer->run();
}

在这里插入图片描述

7、地球效果

7.1 绘制单个地球

在这里插入图片描述

7.2 绘制太阳和几大行星

在这里插入图片描述
在这里插入图片描述

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(????)
感谢各位童鞋们的支持!( ′ ▽′ )ノ ( ′ ▽′)っ!!!

文章来源:https://blog.csdn.net/hhy321/article/details/135589738
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。