从零开始手敲次世代游戏引擎(三十一)

本篇我们回归主线。首先是将我们前面两个Mac特别篇所写的代码统合进来。在这个过程当中发现几个问题:

【1】 OpenGL环境仍然是2.1的。

查阅资料发现,这是因为Apple考虑到兼容性,缺省状态下的OpenGL环境被一律限制到2.1,而如果要使用更高的版本,需要在初始化的时候指定特别的参数,如下粗体字所示(CocoaOpenGLApplication::Initialize):

     NSOpenGLPixelFormatAttribute attrs[] = {
            NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
            NSOpenGLPFAColorSize,32,
            NSOpenGLPFADepthSize,16,
            NSOpenGLPFADoubleBuffer,
            NSOpenGLPFAAccelerated,
            0
        };

注意这里指定的是创建OpenGL Context时候的下限。实际创建的环境会有不同。比如在我的机器上,实际创建的环境是4.1的:

chenwenlideMacBook-Pro:GameEngineFromScratch chenwenli$ ./build/Platform/Darwin/MyGameEngineCocoaOpenGL.app/Contents/MacOS/MyGameEngineCocoaOpenGL 
OpenGL Version 4.1 loaded

【2】 C++部分gladGLLoader出现Segmentation Fault

需要注意的就是C++代码部分执行OpenGL Loader(我们用的是glad)的时机。细心的读者可能会发现,我们从零开始手敲次世代游戏引擎(MacOS特别篇 贰)所写的MacOS版OpenGL的程序,所使用的GraphicsManager是作为基类的GraphicsManager,而不是RHI/OpenGL里面的OpenGLGraphicsManager。这是因为在写前面这篇文章的时候,遇到了C++当中glad一旦Load就出现段错误(Segmentation Fault)。

这个问题现在解决了。原因其实和之前写Windows版或者Linux版OpenGL程序的时候反复强调的一个问题(好吧,我自己忘记了)一样,就是在动态加载OpenGL函数的时候有一个前提条件,那就是OpenGL的Context已经创建并且被设置为Current Context。

所以,其实解决的方法很容易,就是在调用glad之前(也就是初始化RHI/OpenGL/OpenGLGraphicsManager之前),保证OpenGL Context创建完成并被设置为Current Context。这个工作在Cocoa版当中是CocoaOpenGLApplication的工作。我们在CocoaOpenGLApplication::Initialize当中(但是实际创建OpenGL Context的是CocoaOpenGLApplication::_openGLContext,也就是GLView,所以其实是在GLView::initWithFrame当中),靠近函数出口的地方,加入下面这么一行代码:

 [_openGLContext makeCurrentContext];

RHI/OpenGL/OpenGLGraphicsManager的初始化问题就可以得到解决了。

【3】除了背景,啥都没有。

这个其实不是一个问题,因为我们还没有将SceneManager和GraphicsManager结合起来,当然什么都没有了。╮(╯▽╰)╭

解决的方法就是结合SceneManager——那估计还需要好几篇文章的篇幅,所以我们先把从零开始手敲次世代游戏引擎(十三)写的代码临时放进OpenGLGraphicsManager用用吧。

【4】没有动画效果。就是画面当中的正方体不会转动。

这是因为窗口没有接到刷新的通知。与Windows/Linux不同,MacOS系统不会自动刷新窗口,除非窗口的大小发生改变等。解决的方法有好几种,比如使用一个定时器定期触发窗口更新;又比如通过DisplayLink监视屏幕的垂直同步(vsync)进行画面的刷新(这是Apple推荐的方法)

注意使用DisplayLink的时候,监视DisplayLink的动作是发生在另外一个线程,callback也是从另外一个线程调用过来的。这里处理不好容易发生crash。

因为后面我们还会有驱动模块,专门负责这些定期事件的驱动和调度,我这里就直接在App的IRuntimeModule::Tick()接口当中触发了窗口的重新绘制事件。只不过目前我们没有驱动模块,是在main函数当中直接loop。

下面是Mac版的显示效果:

[KGVID]http://mygallery.chenwenli.com/2017/12/article_31.mov[/KGVID]

以及Windows版本的显示效果:

Linux环境

结果上和从零开始手敲次世代游戏引擎(十三)是一样一样的。从十三写到三十一,我们到底干了些啥?╮(╯▽╰)╭

参考引用

  1. OpenGL Application Design Strategies
  2. NSOpenGLView not redrawing
  3. Driving OpenGL Rendering Loops
  4. Introduction to Core Video Programming Guide

留下评论