OpenSceneGraph之一:封装osg到CWnd子类中
上周刚接到一任务,需要对室内装修进行三维模拟,然后就想到了OpenSceneGraph,以前了解过OpenSceneGraph,但从来没编程实现过什么内容,今天打算继承一个CWnd类,在该类中渲染场景,用google检索了下,基本没有,但还有OpenSceneGraph自带了一个多文档的例子,看了下例子,然后就试了试,随便记录下。
其实蛮简单的,先在Win32下测试了一个例子:
int main(int , char **)
{
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
viewer->setSceneData( osgDB::readNodeFile( "D:\\cessna.osg" ) );
return viewer->run();
}
结果死活没有出现飞机模型,只有背景颜色,显示读取文件错误,郁闷呀。试了试编译好的osgviewer.exe显示,一切正常;发现在bin目录下osgPlugins-3.0.0文件夹,内有多个DLL,感觉应该是DLL的问题,拷贝过去,显示正常。结果如下:
正常后,接着生成 class osgWnd : public CWnd,然后再OnCreate中添加如下代码:
::GetWindowRect(m_hWnd, &rect);
osg::ref_ptr<osg::Referenced> m_Windata = new osgViewer::GraphicsWindowWin32::WindowData(this->m_hWnd);
osg::ref_ptr<osg::GraphicsContext::Traits> m_Traits = new osg::GraphicsContext::Traits;
m_Traits->x = 0;
m_Traits->y = 0;
m_Traits->width = rect.right - rect.left;
m_Traits->height= rect.bottom - rect.top;
m_Traits->windowDecoration = false;
m_Traits->doubleBuffer=true;
m_Traits->inheritedWindowData = m_Windata;
osg::ref_ptr<osg::GraphicsContext> m_Gcontext = osg::GraphicsContext::createGraphicsContext(m_Traits.get());
osg::ref_ptr<osg::Camera> m_Camera = new osg::Camera;
m_Camera->setGraphicsContext(m_Gcontext);
m_Camera->setViewport(new osg::Viewport(m_Traits->x, m_Traits->y, m_Traits->width, m_Traits->height));
m_Viewer = new osgViewer::Viewer;
m_Viewer->addSlave(m_Camera.get());
m_Viewer->setSceneData(osgDB::readNodeFile("D:\\cessna.osg"));
m_Viewer->setCameraManipulator(new osgGA::TrackballManipulator);
m_Viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
这部分和MFC中使用OpenGL中切换上下文功能相同。
然后在OnPaint中添加:
void osgWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
if(m_Viewer != 0) {
m_Viewer->frame();
}
}
关键内容就这些吧!
最后贴出完整代码:
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osgViewer/api/win32/GraphicsWindowWin32>
#include "osgDB/ReadFile"
class osgWnd : public CWnd
{
DECLARE_DYNAMIC(osgWnd)
public:
osgWnd(CWnd *parent);
virtual ~osgWnd();
osg::ref_ptr<osgViewer::Viewer> m_Viewer;
osg::ref_ptr<osg::Referenced> m_Windata;
osg::ref_ptr<osg::GraphicsContext::Traits> m_Traits;
osg::ref_ptr<osg::GraphicsContext> m_Gcontext;
osg::ref_ptr<osg::Camera> m_Camera;
protected:
DECLARE_MESSAGE_MAP()
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
afx_msg void OnPaint();
};
// osgWnd
IMPLEMENT_DYNAMIC(osgWnd, CWnd)
osgWnd::osgWnd(CWnd *parent) :
m_finished(false)
{
}
osgWnd::~osgWnd()
{
m_Viewer->setDone(true);
while(!m_finished) Sleep(10);
delete m_Viewer;
//delete m_Windata;
//delete m_Traits;
//delete m_Gcontext;
//delete m_Camera;
}
BEGIN_MESSAGE_MAP(osgWnd, CWnd)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_PAINT()
END_MESSAGE_MAP()
// osgWnd message handlers
int osgWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
osg::ref_ptr<osg::Referenced> m_Windata = new osgViewer::GraphicsWindowWin32::WindowData(this->m_hWnd);
osg::ref_ptr<osg::GraphicsContext::Traits> m_Traits = new osg::GraphicsContext::Traits;
m_Traits->x = 0;
m_Traits->y = 0;
m_Traits->width = rect.right - rect.left;
m_Traits->height= rect.bottom - rect.top;
m_Traits->windowDecoration = false;
m_Traits->doubleBuffer=true;
m_Traits->inheritedWindowData = m_Windata;
osg::ref_ptr<osg::GraphicsContext> m_Gcontext = osg::GraphicsContext::createGraphicsContext(m_Traits.get());
osg::ref_ptr<osg::Camera> m_Camera = new osg::Camera;
m_Camera->setGraphicsContext(m_Gcontext);
m_Camera->setViewport(new osg::Viewport(m_Traits->x, m_Traits->y, m_Traits->width, m_Traits->height));
m_Viewer = new osgViewer::Viewer;
m_Viewer->addSlave(m_Camera.get());
m_Viewer->setSceneData(osgDB::readNodeFile("D:\\cessna.osg"));
m_Viewer->setCameraManipulator(new osgGA::TrackballManipulator);
m_Viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
return 0;
}
void osgWnd::OnDestroy()
{
CWnd::OnDestroy();
// TODO: Add your message handler code here
}
void osgWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CWnd::OnPaint() for painting messages
if(m_Viewer != 0) {
m_Viewer->frame();
}
}
贴出来的过程中,精简了下,并有内存泄露的问题。
下一步就要分离窗口类和模型了。