我主要想说的是使用的后台的c#代码来添加osg场景。
需要实现:新建一个窗口Window1.xaml,然后在窗口中显示osg场景。
这里比较困难的地方是wpf中使用的是c#,是一种托管代码;而osg的代码是使用c++编写,是一种非托管代码。如何将二者结合起来使用就是最关键的步骤。
看网上说的可以使用C++/CLI可以实现c#和c++的混合编程,但由于一开始我就是写的wpf程序,不想再新建工程,于是想到可以将c++的osg代码写成dll文件,然后在wpf程序中引用便可。
WPF中除主窗口外再新建一个窗口Window1.xaml;再在MainWindow页面上随便画一个按钮
代码如下:
public partial class MainWindow : Window
{
//注意把
ConsoleApplication1.dll文件放到wpf的debug文件夹下
[DllImport(@"ConsoleApplication1.dll",
EntryPoint = "osgRunCow", CallingConvention = CallingConvention.Cdecl)]
public static extern void osgRunCow(IntPtr m_hWnd);
IntPtr handle;//c#中用IntPtr来保存窗口句柄,对应c++中的HWND
Thread th;
public MainWindow()
{
InitializeComponent();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Window win = new Window1();//Window1是新建的Window
win.Show();
handle = new WindowInteropHelper(win).Handle;//获取窗口句柄,提供给osgRunCow使用
th = new Thread(new ThreadStart(func));//多开一个线程防止界面假死
th.Start();
}
public void func()
{
osgRunCow(handle);
}
}
dll文件中新建一个module-definition file文件Source.def(add new item->visual c++ ->code->module definition file)
其代码如下(注意没有任何分号):
LIBRARY ConsoleApplication1.dll
EXPORTS
osgRunCow
主文件ConsoleApplication1.cpp的代码如下:
// ConsoleApplication1.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
osg::ref_ptr m_Viewer;
osg::ref_ptr m_Root; // 场景根节点
void initSG()
{
// 创建场景分类树树
m_Root = new osg::Group;
m_Root->addChild(osgDB::readNodeFile("cow.osg"));
// 优化场景数据
//osgUtil::Optimizer optimizer;
//optimizer.optimize(m_Root);
}
void initCameraCfg(HWND m_hWnd)
{
// 本地窗口Size
RECT rect;
// 为窗口创建Viewer
m_Viewer = new osgViewer::Viewer();
// 取消Esc键的事件响应
m_Viewer->setKeyEventSetsDone(0);
// 获得当前窗口大小
::GetWindowRect(m_hWnd, &rect);
// 初始化图形环境GraphicsContext Traits
osg::ref_ptr traits = new osg::GraphicsContext::Traits;
// Init the Windata Variable that holds the handle for the Window to display OSG in.
osg::ref_ptr windata = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd);
// 设置traits 参数
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;
// 创建图形环境Graphics Context
osg::ref_ptr gc = osg::GraphicsContext::createGraphicsContext(traits.get());
{
// 根据分辨率确定合适的投影来保证显示的图形不变形
double fovy =0.0;
double aspectRatio =0.0;
double zNear =0.0;
double zFar= 0.0;
m_Viewer->getCamera()->getProjectionMatrixAsPerspective(fovy,aspectRatio,zNear,zFar);
double newAspectRatio =double(traits->width)/double(traits->height);
double aspectRatioChange = newAspectRatio/aspectRatio;
if (aspectRatioChange != 1.0)
{
m_Viewer->getCamera()->getProjectionMatrix() *= osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0);
}
}
// 设置相机视口
m_Viewer->getCamera()->setViewport(traits->x,traits->y,traits->width,traits->height);
// 为相机分配图形环境
m_Viewer->getCamera()->setGraphicsContext(gc.get());
// 为Viewer的Camera添加操纵器
m_Viewer->setCameraManipulator(new osgGA::OrbitManipulator());
// 设置线程模型
m_Viewer->setThreadingModel(osgViewer::ViewerBase::SingleThreaded);
// 设置场景数据
m_Viewer->setSceneData(m_Root);
// 初始化并创建窗口
m_Viewer->realize();
}
void osgStartRender()
{
m_Viewer->run();
}
void osgRunCow(HWND m_hWnd)
{
initSG();
initCameraCfg(m_hWnd);
osgStartRender();
}
注意:对于托管和非托管我的理解并不深刻,所以使用的时候可能会出现线程安全性问题,但起码我用的时候没出什么问题。
参考工程:ssDlgFrm(网上搜应该可以查到)
有关如何新建dll工程并在wpf中调用可以参照: http://blog.csdn.net/jarvischu/article/details/6634185
有关如何调试dll工程可以参照: http://blog.163.com/yuxiangdingdang@126/blog/static/1087978520102112285825/
感谢每一个愿意分享的人。