细节决定那啥来着,一些细节虽然不是什么难事,但是一旦卡住总是会很烦心,需要太多时间去调试,耽误的是宝贵的项目进度,所以我将在这里把一些总结贴出来,愿能给国内的游戏技术圈同僚们一点小帮助,节约宝贵的时间,毕竟总是在网络上摄取营养,算是回报社会吧。
本文记录最近发现的一些 MFC 和 OGRE1.7.2版本 联姻的注意事项:
问题1:创建Ogre的CView窗口后,无法截获鼠标点击和移动信息,只能获取鼠标滚轮信息。
原因及解决方案:传递CView窗口句柄时,请一定使用externedWindowHandle的属性key,切记不要使用parentWindowHandle,因为parentWindowHandle是让CView成为渲染窗口的父窗口,鼠标键盘消息都不会路由到CView上,而是在渲染窗口里被截获;而externedWindowHandle是让CView窗口本身成为渲染窗口,所以CView才能正常截获到输入消息。
问题2:当解决问题1之后,发现使用externedWindowHandle绘制出的窗口很小,而使用parentWindowHandle时则正常
原因及解决方案:注意继承CView::OnSize()函数响应WM_SIZE消息,但请切记:千万别在OnSize中调用Ogre::RenderWindow::resize()函数,这会导致OnSize()函数的递归回调,因为Ogre::RenderWindow::resize()函数中会调用AdjustWindow()和SetWindowPos()函数,这会导致发送WM_SIZE消息并缩小窗口,从而导致问题的发生。
问题3:如何解决窗口重置大小的问题
解决方案:在OnSize()中
不能调用Ogre::RenderWindow::resize()函数,而
应该调用Ogre::RenderWindow::windowMovedOrResized()函数,通知RenderWindow在渲染前重新设置Viewport的宽高比例。
问题4:怎样确保主渲染循环
分析:上网看了一些相关的解决方案,发现大多使用WM_TIMER消息来维持OGRE的主渲染循环,这应该是下下策的方案了吧......当然还有其他的实现方案,譬如开另一个线程,这个方法还是可行的,但是总有些不对味,因为渲染明明应该在主线程中才是最佳方案。于是我就看了一下MFC闲下来的时候都干了些什么,最后发现了以下解决方案,应该算是很不错但并不难的解决办法了,为什么没见网上有人提供这样的方案让我很不理解,窝着藏着也得不到半点好处:
解决方案:使用空闲回调。该回调是需要继承CWinApp::OnIdle()函数(好像是叫这个,反正肯定带Idle这个单词),当主线程中的消息循环没有取到消息时(调用PeekMessage()没有获取到消息),就会去调用这个函数,于是......就在这个函数里调用绘制一帧吧:Ogre::RenderWindow::update(),另外有动画的话还需要调用Ogre::Root::_fireFrameRenderingQueued(),因为动画更新在这里。如果是想让所有渲染对象都更新一帧的话,直接调用Ogre::Root::renderOneFrame()吧。
解决方案不一定最好,也不一定适合你的情况,但愿能尽微薄之力,也是作为我个人的备忘吧。