昨天尝试了使用Qt5集成的OsgEarth,使用C++的开发人员毕竟少,而使用WinForm画界面就方便多了,如何将OsgEarth集成到WInForm中,思路如下:
使用C++封装相应的代码,提供dll接口注入winform渲染句柄的传入。
使用的OsgEarth版本3.1、.net 版本5.0。
源代码下载路径:
(8条消息) OsgEarthWrapper.7z-C++文档类资源-CSDN文库
实现的效果如下:
1.C++接口的封装
此处代码参考了osg的示例程序osgviewerMFC
OSGEarthWrapper.h
#pragma once
#include <windows.h>
#include <string>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/api/win32/GraphicsWindowWin32>
#include <osgGA/TrackballManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgDB/DatabasePager>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>
#include <osgGA/StateSetManipulator>
#include <osgEarth/EarthManipulator>
#include <osgEarth/Map>
#include <osgEarth/MapNode>
#include <osgEarth/TMS>
//#include <osgEarthDrivers/model_feature_geom/FeatureGeomModelOptions>
// 3.1 FeatureSourceFactory / OGRFeatureOptions removed ->OGRFeatureSource
//#include <osgEarthDrivers/feature_ogr/OGRFeatureOptions>
#include <osgEarth/OGRFeatureSource>
#include <osgEarthDrivers/cache_filesystem/FileSystemCache>
#include <osgEarth/EarthManipulator>
#include <osgEarth/GeodeticGraticule>
#include <osgEarth/LatLongFormatter>
#include <osgEarth/Controls>
#include <osgEarth/MouseCoordsTool>
#include <osgEarth/AutoClipPlaneHandler>
#include <osg/PositionAttitudeTransform>
#include <osg/Group>
#include <osg/Node>
#include <osgDB/ReadFile>
#include <osgEarth/ImageLayer>
#include <osgEarth/Notify>
#include <osgEarth/EarthManipulator>
#include <osgEarth/ExampleResources>
#include <osgEarth/MapNode>
//3.1ThreadingUtils ->Threading
//#include <osgEarth/ThreadingUtils>
#include <osgEarth/Threading>
#include <osgEarth/Metrics>
class OSGEarthWrapper
{
public:
OSGEarthWrapper(HWND hWnd);
~OSGEarthWrapper();
void InitOSG(std::string filename);
void InitManipulators(void);
void InitSceneGraph(void);
void InitCameraConfig(void);
void PreFrameUpdate(void);
void PostFrameUpdate(void);
void Done(bool value) { mDone = value; }
bool Done(void) { return mDone; }
osg::ref_ptr<osgViewer::Viewer> getViewer() { return viewer; }
osg::ref_ptr<osgEarth::Util::EarthManipulator> getEm() { return manip; }
osg::ref_ptr<osg::Group> getRoot() { return mRoot; }
osg::ref_ptr<osgEarth::Map> getMap() { return mMap; }
osg::ref_ptr<osgEarth::MapNode> getMapNode() { return mMapNode; }
private:
bool mDone;
std::string m_ModelName;
HWND m_hWnd; //实际需要显示的窗体句柄
osg::ref_ptr<osgViewer::Viewer> viewer;
osg::ref_ptr<osg::Group> mRoot;
osg::ref_ptr<osg::Node> mModel;
osg::ref_ptr<osgEarth::Map> mMap;
osg::ref_ptr<osgEarth::MapNode> mMapNode;
osg::ref_ptr < osgEarth::Util::EarthManipulator> manip;
};
class CRenderingThread : public OpenThreads::Thread
{
public:
CRenderingThread(OSGEarthWrapper* ptr);
CRenderingThread(OSGEarthWrapper* ptr, bool is3dThread);
virtual ~CRenderingThread();
void Done(bool);
bool isEnd();
void setOsgRuningFlag(bool);
bool getOsgRuningState();
virtual void run();
protected:
OSGEarthWrapper* _ptr;
bool _done;
bool _is3Dthread;
bool _osgRuningFlag;
bool _osgRuningState;
};
OSGEarthWrapper.cpp
#include "pch.h"
#include "OSGEarthWrapper.h"
OSGEarthWrapper::OSGEarthWrapper(HWND hWnd) :
m_hWnd(hWnd)
{
}
OSGEarthWrapper::~OSGEarthWrapper()
{
viewer->setDone(true);
Sleep(100);
viewer->stopThreading();
viewer.~ref_ptr();
delete viewer;
}
void OSGEarthWrapper::InitOSG(std::string modelname)
{
// Store the name of the model to load
m_ModelName = modelname;
// Init different parts of OSG
InitManipulators();
InitSceneGraph();
InitCameraConfig();
}
void OSGEarthWrapper::InitManipulators(void)
{
}
void OSGEarthWrapper::InitSceneGraph(void)
{
// Init the main Root Node/Group
mRoot = new osg::Group;
int argc = 2;
char* argv[2];
argv[0] = _pgmptr;
argv[1] = (char*)m_ModelName.c_str();
osg::ArgumentParser arguments(&argc, argv);
// Create the viewer for this window
viewer = new osgViewer::Viewer();
// Load the Model from the model name
mModel = osgEarth::Util::MapNodeHelper().load(arguments, viewer);
if (!mModel) return;
// Optimize the model
osgUtil::Optimizer optimizer;
optimizer.optimize(mModel);
optimizer.reset();
// Add the model to the scene
mRoot->addChild(mModel);
}
void OSGEarthWrapper::InitCameraConfig(void)
{
// Local Variable to hold window size data
RECT rect;
// Add a Stats Handler to the viewer
viewer->addEventHandler(new osgViewer::StatsHandler);
// Get the current window size
::GetWindowRect(m_hWnd, &rect);
// Init the GraphicsContext Traits
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
// Init the Windata Variable that holds the handle for the Window to display OSG in.
osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd);
// Setup the traits parameters
traits->x = 0;
traits->y = 0;
traits->width = rect.right - rect.left;
traits->height = rect.bottom - rect.top;
traits->windowDecoration = false;
traits->doubleBuffer = true;
traits->sharedContext = 0;
traits->setInheritedWindowPixelFormat = true;
traits->inheritedWindowData = windata;
// Create the Graphics Context
osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits.get());
// Init Master Camera for this View
osg::ref_ptr<osg::Camera> camera = viewer->getCamera();
// Assign Graphics Context to the Camera
camera->setGraphicsContext(gc);
// Set the viewport for the Camera
camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
// set the draw and read buffers up for a double buffered window with rendering going to back buffer
camera->setDrawBuffer(GL_BACK);
camera->setReadBuffer(GL_BACK);
// Set projection matrix and camera attribtues
camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
camera->setClearColor(osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
camera->setProjectionMatrixAsPerspective(
30.0f, static_cast<double>(traits->width) / static_cast<double>(traits->height), 1.0, 1000.0);
viewer->setCamera(camera.get());
osgEarth::MapNode* mapNode = osgEarth::MapNode::findMapNode(mRoot);
mMapNode = mapNode;
osgEarth::Map* map = mapNode->getMap();
mMap = map;
double equatorRadius = map->getSRS()->getEllipsoid()->getRadiusEquator();
viewer->getCamera()->addCullCallback(new osgEarth::Util::AutoClipPlaneCullCallback(mapNode));
manip = new osgEarth::Util::EarthManipulator();
manip->setHomeViewpoint(osgEarth::Util::Viewpoint("北京", 116.3, 39.9, 0, 0, -90, equatorRadius * 4));
viewer->setCameraManipulator(manip);
// Set the Scene Data
viewer->setSceneData(mRoot);
viewer->setThreadingModel(osgViewer::ViewerBase::ThreadingModel::SingleThreaded);
viewer->addEventHandler(new osgViewer::StatsHandler);
viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
viewer->addEventHandler(new osgViewer::ThreadingHandler);
viewer->addEventHandler(new osgViewer::RecordCameraPathHandler);
viewer->addEventHandler(new osgViewer::LODScaleHandler);
viewer->addEventHandler(new osgViewer::ScreenCaptureHandler);
viewer->realize();
}
void OSGEarthWrapper::PreFrameUpdate()
{
// Due any preframe updates in this routine
}
void OSGEarthWrapper::PostFrameUpdate()
{
// Due any postframe updates in this routine
}
CRenderingThread::CRenderingThread(OSGEarthWrapper* ptr)
: OpenThreads::Thread(), _ptr(ptr), _done(false)
{
_osgRuningFlag = true;
_osgRuningState = true;
}
CRenderingThread::CRenderingThread(OSGEarthWrapper* ptr, bool is3dThread)
: OpenThreads::Thread(), _ptr(ptr), _done(false)
{
_is3Dthread = is3dThread;
_osgRuningFlag = true;
_osgRuningState = true;
}
CRenderingThread::~CRenderingThread()
{
_done = true;
if (isRunning())
{
cancel();
join();
}
}
void CRenderingThread::Done(bool flag)
{
_done = flag;
}
void CRenderingThread::setOsgRuningFlag(bool b)
{
_osgRuningFlag = b;
}
bool CRenderingThread::getOsgRuningState()
{
return _osgRuningState;
}
bool CRenderingThread::isEnd()
{
osgViewer::Viewer* viewer = _ptr->getViewer();
if (!testCancel() && !viewer->done() && !_done)
return false;
else
return true;
}
void CRenderingThread::run()
{
if (!_ptr)
{
_done = true;
return;
}
osgViewer::Viewer* viewer = _ptr->getViewer();
do
{
if (_osgRuningFlag)
{
_ptr->PreFrameUpdate();
viewer->frame();
_ptr->PostFrameUpdate();
_osgRuningState = true;
}
else
{
_osgRuningState = false;
Sleep(5);
}
} while (!testCancel() && !viewer->done() && !_done);
}
提供对外的DLL入口:
#pragma once
extern "C"
{
//传入控件句柄,初始化控件为OSG三维显示
NativeExport int InitOsgEarth(HWND _hwnd);
//销毁OSG渲染窗口
NativeExport int DestroyOsgEarth();
};
#include "pch.h"
#include "api.h"
#include "OSGEarthWrapper.h"
//窗口全局唯一变量
OSGEarthWrapper* mOSG = nullptr;
//渲染线程全局变量
CRenderingThread* mThreadHandle = nullptr;
NativeExport int InitOsgEarth(HWND _hwnd)
{
//通过传入的句柄初始化cOSG对象
mOSG = new OSGEarthWrapper(_hwnd);
mOSG->InitOSG("simple.earth");
//创建渲染线程并开始渲染
mThreadHandle = new CRenderingThread(mOSG);
mThreadHandle->start();
return 0;
}
NativeExport int DestroyOsgEarth()
{
if (mThreadHandle != nullptr)
{
mThreadHandle->Done(true);
while (!mThreadHandle->isEnd())
{
Sleep(10);
}
delete mThreadHandle;
mThreadHandle = nullptr;
}
if (mOSG != 0)
{
delete mOSG;
mOSG = nullptr;
}
return 2;
}
2.DotNet客户端的调用
public partial class Form1 : Form
{
[DllImport("OsgEarthWrapper.dll", EntryPoint = "InitOsgEarth", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern int InitOsgEarth(IntPtr x);
[DllImport("OsgEarthWrapper.dll", EntryPoint = "DestroyOsgEarth", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
public static extern int DestroyOsgEarth();
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
this.FormClosed += Form1_FormClosed;
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
DestroyOsgEarth();
}
private void Form1_Load(object sender, EventArgs e)
{
IntPtr ptr = this.MapPanel.Handle;
InitOsgEarth(ptr);
}
}