在wpf工程中使用osg技术

我主要想说的是使用的后台的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 <osg/Group>

#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/api/win32/GraphicsWindowWin32>

#include <osgDB/ReadFile>

#include <osgGA/OrbitManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/CameraManipulator>
#include <osgGA/KeySwitchMatrixManipulat or>
#include <osgGA/GUIEventHandler>

#include <osgUtil/Optimizer>
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->setInheritedWindowPixelF ormat = 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()->getProjectionMatrixAsPer spective(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

感谢每一个愿意分享的人。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值