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

本篇我们回归主线。首先是将我们前面两个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

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

您正在使用您的 WordPress.com 账号评论。 登出 /  更改 )

Google photo

您正在使用您的 Google 账号评论。 登出 /  更改 )

Twitter picture

您正在使用您的 Twitter 账号评论。 登出 /  更改 )

Facebook photo

您正在使用您的 Facebook 账号评论。 登出 /  更改 )

Connecting to %s

%d 博主赞过: