osg开发配置与第一个osg程序

目录

1.前言

2.osg简介

3.OSG开发环境配置

3.1下载安装VS2022

3.2获取osg库

4.编写、编译并运行第一个osg程序

4.1编写第一个C++ CMake程序

4.2编写第一个osg程序

4.3一个xue微有点追求的osg程序


1.前言

本文介绍开源图形库osg的开发环境配置和编写第一个osg程序的完整过程。这是一个教程,也是一个与各位图形从业者的交流平台。

开发环境:Windows10 专业版、Visual Studio 2022、osg3.6.5;

项目构建:CMake。

Visual Studio从版本2017开始支持CMake项目,本文编写时VS的最新版本是VS2022,我们就使用最新版本。CMake 是一个跨平台、开源的元构建系统,广泛应用于C/C++项目的源码构建,它可以为make、ninja等构建系统生成构建脚本。CMake根据用户在CMakeLists.txt编写的各种命令构建工程,本文对涉及到的CMake命令会进行介绍。

2.osg简介

OpenSceneGraph简称osg,是基于标准C++语言和OpenGL编写的图形引擎,详细介绍见osg主页

3.OSG开发环境配置

3.1下载安装VS2022

VS官网下载VS2022。VS2022分为社区版,个人版和企业版,其中社区版可免费使用,个人版和企业版可免费使用30天。如使用个人版和企业版,请用你懂得的方式进行,如想减轻使用盗版软件带来的负罪感,社区版也是够用的。

VS安装时需注意,勾选项"用于Windows的C++ CMake 工具"和"MSVC V142 - VS 2019 C++ x64/x86 生成工具"。如下图所示

在此解释一下勾选这两项的原因:

  1. 勾选"用于Windows的C++ CMake 工具"是为了使VS支持CMake工程;
  2. 勾选"MSVC V142 - VS 2019 C++ x64/x86 生成工具"是因为本文使用的osg库是使用VS2019编译的,需要支持2019编译的库。

3.2获取osg库

获取osg库至少有三种方式:

  1.  使用osg的源码编译。在osg的github主页下载osg3.6.5源码并自行编译,网上有很多这类教程,不在此详细描述。如果您想调试osg的源码,请选此方法。本篇教程不需要调试osg源码,因此选用最快的方法,即方法3。
  2. 使用vcpkg编译安装。网上也有很多这类教程,不在此详细描述。由于vcpkg下载速度是个严重的问题,要想快速搭建开发环境也不推荐此方法。
  3. 下载编译好的osg库。要想最快搭建osg的开发环境,推荐此方法。本文使用Objexx编译并提供给osg开源社区的osg库。 下载页面地址:https://objexx.com/OpenSceneGraph.html

本文例子使用Visual C++ 2019编译的64位osg3.6.5 

下载Release和Debug版,并解压到本地硬盘。假设Release版和Debug版的保存路径分别为:"E:/osg/OpenSceneGraph-3.6.5-VC2019-64-Release/ "和 "E:/osg/OpenSceneGraph-3.6.5-VC2019-64-Debug/"。库的目录组织如下图:

 bin目录存放可执行的二进制文件,即exe文件和dll文件,包括实用工具"模型/场景查看器" osg_viewer.exe、"格式转换工具"osg_conv.exe等;include目录存放头文件;lib目录存放.lib库文件。

为了简化本篇教程,本例子只用Debug库,涉及Debug和Release的切换问题,将在后续教程介绍。

至此,所需的软件都已准备就绪。下面我们将创建第一个osg程序。

4.编写、编译并运行第一个osg程序

本着由简入繁、一步一个脚印的原则,我们将首先使用VS2022创建一个CMake工程,并使用标准C++编写一个最简单的程序(Hello World: "没错,就是我!"),程序正常编译和运行后再引入osg库并创建第一个osg窗口,而后创建一个简单的场景,这一切都正常编译运行后,我们的第一个osg程序任务就可以完美结束了。

4.1编写第一个C++ CMake程序

首先我们先用VS2022创建一个CMake工程。

这时候有的同学要问了,为什么要用CMake呢,VS的工程(.sln)不可以吗?

答案是:可以。VS工程经过界面化的配置就可以开发运行osg程序,但是我依然推荐大家使用CMake工程,因为在程序员生涯中,您一定会接触开源、跨平台的C++项目,您甚至会自己开发一套开源软件,而在这个过程中一定绕不开CMake,所以CMake命令虽然入门有难度,但是学习它是很有必要的。因此在此文中,我将创建CMake工程,并与大家一起探索和使用这个优秀的工具。

言归正传,我们开始创建第一个CMake工程。

1.新建文件夹"learn_osg_01",在文件夹内创建文件"CMakeLists.txt"和文件"main.cpp",此时两个文件都是空的。

2.打开VS2022,选择"打开本地文件夹",并选择"learn_osg_01"目录。

 3.此时VS经过一番自动操作,完成了CMake工程的生成工作。可以发现此时在"learn_osg_01"目录下多了两个文件夹".vs"和"out",其中".vs"目录下会生成VS的项目配置、缓存等文件,由VS自动维护,我们可以不用关心,甚至可以在关闭工程时删除(再次打开VS还会重新生成);"out"目录下将存放将来编译、链接生成的各种文件。

4.在"main.cpp"中编写"Hello World"程序。

#include <iostream>

int main(int argc, char** argv)
{
	std::cout << "Hello, osg!" << std::endl;
	return 0;
}

5.这是一个可正常编译运行的C++源程序,正确使用CMake可生成可执行程序。CMake如何知道怎么构建呢?答案是通过"CMakeLists.txt"文件的指令。我们在"CMakeLists.txt"中输入以下代码并保存:

project("learn_osg_01")
add_executable(${PROJECT_NAME} main.cpp)

6.点击VS菜单的"生成-全部生成",VS会自动调用相关工具生成"learn_osg_01.exe",F5可运行调试,此时在控制台上已经可以输出"Hello, osg!"。

至此,第一个CMake C++程序已经完成了。在进行下一步之前请容我简要介绍一下用到的两条CMake指令。

project("learn_osg_01")

project()指令的作用是设置项目名称,并存放在变量PROJECT_NAME中,如果在顶层的CMakeLists.txt中调用此指令,会同时把项目名称存放在变量CMAKE_PROJECT_NAME中,同时还会自动设置以下变量:

PROJECT_SOURCE_DIR:  项目源码的绝对路径,在此例中是"E:/一坨路径.../learn_osg_01"

PROJECT_BINARY_DIR: 项目二进制目录的绝对路径,在此例中是"E:/一坨路径.../learn_osg_01/out/build/x64-Debug"

另外project()指令还可指定版本,语言等。

add_executable(${PROJECT_NAME} main.cpp)

add_executable()指令的作用是使用指定的源文件生成目标可执行文件,指令的第一个参数是要生成可执行文件(Windows系统中是exe文件)的名称,本例中会生成"learn_osg_01.exe",名字后边的参数是源文件列表,此例中目前只有一个源文件,即"main.cpp",如有多个源文件,要依次列在后边,用空格或换行隔开。

我们已经搞明白了这几行代码,接下来我们要开始编写基于osg的程序了。

4.2编写第一个osg程序

写过Visual C++项目的同学一定了解,在VC++项目中,通过图形界面就可配置库,非常方便。对于CMake工程,我们要用自己勤劳的双手输入指令代码去完成配置。

我们要引入osg库,首先要告诉编译器库头文件的位置。在CMake中使用include_directories()指令实现。

include_directories("E:/osg/OpenSceneGraph-3.6.5-VC2019-64-Debug/include")

include_directories()指令告诉编译器搜索头文件的路径,把目录加入到属性INCLUDE_DIRECTORIES中。

我们还要告诉编译器库文件的位置。在CMake中使用link_directories()指令实现。

link_directories("E:/osg/OpenSceneGraph-3.6.5-VC2019-64-Debug/lib")

link_directories()指令告诉链接器器搜索库文件的路径,把目录加入到属性LINK_DIRECTORIES中。

接下来我们还要告诉编译器,具体链接哪个库文件。在CMake中使用target_link_libraries()指令实现。

target_link_libraries(${PROJECT_NAME} 
	osgd
	osgViewerd
)

target_link_libraries()指令指定哪些库需要链接到目标上。本例的目标是最终要生成的exe文件,由上文中add_executable()指令指定,需要链接的库是osgd.lib和osgViewerd.lib。

至此本例的CMake库配置已经基本完成,目前为止CMakeLists.txt文件的全部内容如下:

project("learn_osg_01")

set(OSG_DIR "E:/osg/OpenSceneGraph-3.6.5-VC2019-64-Debug")
include_directories(${OSG_DIR}/include)
link_directories(${OSG_DIR}/lib)

add_executable(${PROJECT_NAME} main.cpp)

target_link_libraries(${PROJECT_NAME} 
	osgd
	osgViewerd
)

注意到include_directories()指令和link_directories()指令都用到了osg库的根目录,本着方便快捷、便于维护的目的,我们使用set()指令把osg库根目录赋值给变量OSG_DIR,本文件后续再使用可以直接引用此变量。

接下来我们就可以在代码中调用osg库了。

我们创建一个osgViewer::Viewer对象,并运行该Viewer的主循环。main.cpp文件中的代码改造如下

#include <osgViewer/Viewer>
#include <iostream>

int main(int argc, char** argv)
{
	std::cout << "Hello, osg!" << std::endl;
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	return viewer->run();
}

F7启动目标生成,可以看到目标已经成功生成。

 此时,您一定迫不及待的要按下F5,想让程序跑起来了。遗憾的是,目标还不能正常运行,因为找不到动态链接库。

 解决这个问题至少有两个办法:

  1. 将动态链接库路径配置到系统环境变量;
  2. 将动态链接库拷贝到exe目录。

第一个办法最简单也最节省硬盘空间,但是如果您在同时开发多个项目,而每个项目使用的osg版本是不同的,那这个办法会引起意想不到的错误;

接下来我们介绍一下第二种办法。

有同学可能会想到手动去拷贝dll文件,这是一个解决方案但显然有点low,那有什么看起来比较有调性的方法呢?用CMake!

file(GLOB OSG_DLLS ${OSG_DIR}/bin/*.dll)
file(COPY ${OSG_DLLS} DESTINATION ${CMAKE_BINARY_DIR})

使用file()指令可自动拷贝源路径下的所有.dll文件到目标路径。file()指令可对文件系统进行操作,它的功能远不止本例中用到的这些,感兴趣的同学可以继续研究一下。

在CMakeLists.txt文件中增加上两行指令并保存,CMake会自动完成文件拷贝,这时F5启动程序,您将看到一个全屏显示的osg窗口,第一个osg程序终于运行起来了!

有的同学要问了:“我不想全屏启动应用程序怎么办?”

在main.cpp中添加一行代码,指定窗口的位置和大小

viewer->setUpViewInWindow(50, 50, 800, 600);

运行结果如下图所示

 至此,一个空场景的osg窗口已经运行起来了。

 CMakeLists.txt的完整代码是:

project("learn_osg_01")

set(OSG_DIR "E:/osg/OpenSceneGraph-3.6.5-VC2019-64-Debug")
include_directories(${OSG_DIR}/include)
link_directories(${OSG_DIR}/lib)

add_executable(${PROJECT_NAME} main.cpp)

target_link_libraries(${PROJECT_NAME} 
	osgd
	osgViewerd
)

file(GLOB OSG_DLLS ${OSG_DIR}/bin/*.dll)
file(COPY ${OSG_DLLS} DESTINATION ${CMAKE_BINARY_DIR})

main.cpp的完整代码是:

#include <osgViewer/Viewer>
#include <iostream>

int main(int argc, char** argv)
{
	std::cout << "Hello, osg!" << std::endl;
	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	viewer->setUpViewInWindow(50, 50, 800, 600);
	return viewer->run();
}

此教程到此可以告一段落了,但是作为一个有追求的程序员,空场景显然不符合我们的调性,因此我们继续折腾一下,让场景里显示一个三维物体。

4.3一个xue微有点追求的osg程序

我们在场景中创建一个地球模型。

首先在坐标(0,0,0)处创建一个半径为1.0的球,main.cpp函数中添加代码:

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

...

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

...

    osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(), 1.0f)));
	viewer->setSceneData(geode);

...
}

编译运行结果如下:

 这是一个没有灵魂的球,我们将为这个球注入地球的灵魂,通过——贴纹理。

本例子使用的纹理下载链接

 下载后放于"E:/test/"目录下。

在main.cpp中添加代码

#include <osg/Texture2D>
#include <osgDB/ReadFile>

...

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

...

	osg::ref_ptr<osg::Texture> texture = new osg::Texture2D(osgDB::readRefImageFile("E:/test/world.png"));
	auto stateSet = geode->getOrCreateStateSet();
	stateSet->setTextureAttributeAndModes(0, texture);

...

}

在CMakeLists.txt中添加代码:

target_link_libraries(${PROJECT_NAME} 
	osgDBd
)

file(GLOB OSG_PLUGIN_DLLS ${OSG_DIR}/bin/osgPlugins-*/osgdb_png*.dll)
file(COPY ${OSG_PLUGIN_DLLS} DESTINATION ${CMAKE_BINARY_DIR})

引入osgDB库,同时将插件库中的png文件读写插件dll拷贝到可执行文件同目录下。

编译运行,出现三维地球的场景终于出现了,如下图

osg默认为我们增加了相机操控器,可以通过鼠标操作浏览场景。

按下鼠标坐标左键并拖动:旋转场景;

按下鼠标中键并拖动:平移场景;

按下鼠标右键并拖动:缩放场景;

鼠标滚轮:缩放场景;

键盘空格键:恢复初始相机视角;

键盘ESC键:退出。

本教程的代码已经全部编写完成。代码不多,但篇幅略长,每句代码都有说明,有些更是踩过坑后总结的经验,旨在为新手同学提供详细、友好的入门教程,同时希望对老手也有所启发。感谢各位能阅读到此,希望与大家在学习探索osg的旅程上结伴同行。

最后附上完整代码。

CMakeLists.txt

project("learn_osg_01")

set(OSG_DIR "E:/osg/OpenSceneGraph-3.6.5-VC2019-64-Debug")
include_directories(${OSG_DIR}/include)
link_directories(${OSG_DIR}/lib)

add_executable(${PROJECT_NAME} main.cpp)

target_link_libraries(${PROJECT_NAME} 
	osgd
	osgViewerd
    osgDBd
)

file(GLOB OSG_DLLS ${OSG_DIR}/bin/*.dll)
file(COPY ${OSG_DLLS} DESTINATION ${CMAKE_BINARY_DIR})
file(GLOB OSG_PLUGIN_DLLS ${OSG_DIR}/bin/osgPlugins-*/osgdb_png*.dll)
file(COPY ${OSG_PLUGIN_DLLS} DESTINATION ${CMAKE_BINARY_DIR})

main.cpp

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

#include <iostream>

int main(int argc, char** argv)
{
	std::cout << "Hello, osg!" << std::endl;

	osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
	viewer->setUpViewInWindow(50, 50, 800, 600);
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(), 1.0f)));
	osg::ref_ptr<osg::Texture> texture = new osg::Texture2D(osgDB::readRefImageFile("E:/test/world.png"));
	auto stateSet = geode->getOrCreateStateSet();
	stateSet->setTextureAttributeAndModes(0, texture);
	viewer->setSceneData(geode);
	return viewer->run();
}

  • 42
    点赞
  • 113
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
OSG开发中,有时候需要将OSG的场景嵌入到QT应用程序中。常见的做法是使用osgQt库来实现这一功能,但是有时候也可以不使用osgQt重写类来嵌入QT应用程序。 在不使用osgQt的情况下,我们可以通过以下几个步骤来实现OSG场景的嵌入。 首先,需要在QT应用程序中创建一个QOpenGLWidget控件,用于显示OSG场景。接着,我们需要创建一个OSG的GraphicsWindowOpenGL对象,将其与QOpenGLWidget控件进行绑定。 然后,我们需要创建一个OSG的Camera对象,并将其设置为主相机。同时,我们需要创建一个OSG的Viewer对象,将之前创建的GraphicsWindowOpenGL对象作为参数传入。 接着,我们可以开始创建场景,并将其添加到Viewer对象中。 在QT应用程序中,我们可以通过重写QOpenGLWidget的resizeGL()函数和paintGL()函数来设置场景的大小和绘制场景。 最后,我们需要在QT应用程序中启动一个定时器,不断更新和绘制场景。可以通过调用Viewer对象的frame()函数来实现。 通过以上的步骤,我们可以实现在QT应用程序中嵌入OSG场景的效果,而不使用osgQt库。 不使用osgQt重写类嵌入QT应用程序的好处是简化了开发过程,并且提供了更多灵活性。我们可以更加自由地控制场景的绘制和更新,以及与其他QT控件的交互。 当然,osgQt库也提供了更多的功能和封装,适用于更复杂的场景嵌入需求。在选择是否使用osgQt时,可以根据具体的开发需求和项目要求进行取舍。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值