OpenGL在MFC下的多视图显示在很多场合都能用到,而且表现力够强。前段时间自己需要做一个类似于MAX之类的场景编辑工具,用来编辑自己正在做的FPS游戏中所需要的场景。由于自己不懂美工、不会用MAX,所以在学习MAX与做一个自己更容易操作的编辑器两者间,就一直很纠结,最终还是选择做一个自己的编辑器。现在看来这个选择是明智的,因为用自己的编辑器来处理自己胡思乱想出来的场景时能更方便地与自己的游戏进行融合,对后期的工作带来了很大的便利。
编辑器的显示界面与MAX的类似,多个窗口分别显示3D、前、侧、俯四个投影视图。在MFC中创建多个视图就不用说了,初学MFC的都会搞。在创建完分割视图、搭完程序的框架之后即需要将初图与OpenGL进行关联。我最初采用的方法也是很原始的那种:在整个程序中创建一个OpenGL的RC,然后在需要刷新视图时将视图的DC逐个与这个唯一存在的RC进行关联,然后绘制,在绘制完之后再解除当前的关联并与下一个视图进行关联……,如此循环。在这个过程中,不说繁琐的关联DC与RC的过程了,最要命的就是这个过程是灰常慢的,在实现时发现,对于当前的活动视图刷新率还行,但对于其它的非活动视图,那个刷新率就不能容忍了(这里面可能是由于我最初的实现代码有问题,按理说几个视图的刷新率应该差不多才对呀,是不?但即便这样也还是很低),这样很不爽,所以感觉有很必要大改,一查资料,发现这个是普遍问题,解决办法就是多线程下的多初图,于是就用多线程对自己的编辑器进行了大改。
整个程序以MainFrm为单位进各个子视图进行管理,各个子视图对应一个自己的渲染线程,每个线程里边有一个相互独立的GL RC,这几个RC之间的状态不会相互影响,因此在绘制的时间各个视图间也是相互独立的。
在具体实现中用一个类似于如下的类来对RC及DC及其它相应的资源进行管理:
class CMultiThreadRCManager
{
private:
int m_viewNums;
HGLRC* m_hglRCList;
CDC** m_hDCList;
//…
//…
}
在实现过程中发现有如下一些问题需要特别注意:
1. 在线程中要注意资源的上锁与解锁,否则就会造成越界访问,这是属于多线程的相关内容,而且是很容易出bug的地方。
2. 在我的实现里边用MainFrm来作为所有操作的主体,用它来对视图及相关的线程进行操作维护,感觉效果挺好。
3. 在视图线程的主循环中加上一定的延时,Sleep(time),可使线程间的调度更加流畅,降低CPU的工作负载。
4. 使用临界区来对线程间共享的资源进行管理时(我在实现时是利用临界区进行资源管理),界区对象CCriticalSection应保证能被所有读写此资源的线程所访问,否则不能起到资源临界的作用。若有多个共享资源,最好对每个共享资源设置临界区,可以线程之间进行更好的调度。
总之,OpenGL多线程的多视图渲染最容易出现问题的地方就是多线程时的资源读写操作,如果这部分顺利搞定,其他地方一般不会有什么问题的。最终,我的程序跑起来了,在ATI3470上测试,对于四个视图,每个视图都能达到90帧以上的刷新率,效果还可以,能满足自己丑陋的编辑器的需要了。