上周刚接到一任务,需要对室内装修进行三维模拟,然后就想到了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(); } }
贴出来的过程中,精简了下,并有内存泄露的问题。
下一步就要分离窗口类和模型了。