技术要点提示:基于多核cpu的gpu 多线程渲染。
这里以OSG多线程渲染为例,谈谈OSG渲染引擎多线程渲染模式,再说说哪里有点“过时”了需要改进。
先谈点题外话,曾经看到知乎上一篇关于游戏引擎的设计讨论的文章,有位“大大”提出游戏引擎的设计关键在于架构设计,这是灵魂,一味强调画质如何,shader , 特效算法写的如何好,渲染的怎么真实漂亮那是舍本逐末,这些都可以照着“Real-TimeRendering” 或 是相关的 paper 实现即可。如果看过几款引擎或是自研过,就会觉得这观点很有道理,但我感觉如果架构到算法特效自己都走的通的话,心中有蓝图,引擎功能、易用性更好一些,也少走弯路。一款引擎之所以能在市场上能做成功,得到用户的认可,除了采用的技术先进,财力支持到位外,最主要的是有自己的特点,我们在甄别引擎的时候,也是根据各自行业需求,考量引擎的特点找一款认为比较合适的(“最合适”不好说)。前些年由于公司业务需要,在网上搜了一些渲染引擎对比的文章,大部分都是在不了解其特性的情况下人云亦云,把官方放出的特性罗列一下就完事了,究竟是哪个渲染引擎效率高,好在哪个方面,也没有说清楚,这样的总结还不如不总结。还有一部企业,需要渲染引擎就打算要自己开发,按我理解,大部分国内从事图形开发的程序员远没有到达市面上比较流行的渲染引擎作者的水平,还不如找个适合自己企业的第三方引擎,用一用,熟悉了再优化下,省时省心。等真的摸清了,搞透了原理,看多了再自研也不迟,除非自己企业真的有业界"大大"且舍得花钱,才适合一上来自研,闲话不多说了。
先看看 OSG 3.6.4 线程模型枚举变量的定义:
enum ThreadingModel{SingleThreaded,CullDrawThreadPerContext,ThreadPerContext = CullDrawThreadPerContext,DrawThreadPerContext,CullThreadPerCameraDrawThreadPerContext,ThreadPerCamera = CullThreadPerCameraDrawThreadPerContext,AutomaticSelection};
你会发现出现了两次等值枚举变量名称: ThreadPerContext = CullDrawThreadPerContext 和ThreadPerCamera = CullThreadPerCameraDrawThreadPerContext, 之前OSG 线程模型的定义有些让人费解,出现了“词不达意”的问题,我们在写程序“造词”的时候,一般要求看到变量或宏名或类名就知道其功能,这样便于其他人理解和阅读,ThreadPerContex 这类枚举变量不去认真分析下,还真不知道什么意思。 CullDrawThreadPerContext 表达的就很清楚了,场景对象裁剪和绘制都在设备线程中进行。CullThreadPerCameraDrawThreadPerContext 表明 相机线程负责场景裁剪,设备线程负责绘制。可以看出OSG官方也对不好理解的枚举变量定义相当于做了注解,加以修正。
从枚举变量可以看出,OSG主要有四种线程模型来适应不同的硬件或用户需求。
SingleThreaded : 单线程模型最好理解了,不做任何优化,按最常规方式渲染整个场景,OSG 没有开启另外的线程来加速场景绘制。SingleThreaded 模型并没有最大化的利用多处理器、多任务的硬件, 系统的渲染效率较低。
在这里我们先看一下OSG 渲染一帧,要经历哪几个过程:
上图是一般渲染引擎渲染一帧所经历的主要过程,各种渲染引擎大同小异,多线程也得走这个过程,只是为了对渲染效率做优化,在一定的条件下(比如Update, Draw阶段要求节点数据不存在不一致的情况)允许各阶段有所重叠。
那么针对多窗口的情况(也就是多上下文的情况, OSG 把一个窗口看成一个context, 记住Context 就是窗口,窗口就是Context ),OSG 如何优化来提升效率呢?这就是 CullDrawThreadPerContex 。
CullDrawThreadPerContex : 通俗的来说,我们为了多屏阵列显示创建了四个窗口(4contexts)来渲染整个场景,总不能做个大的渲染循环逐个窗口去绘制吧?!这样做效率很低。OSG 为每个窗口各自创建了线程,每个窗口线程负责自己的场景裁剪和绘制工作,主线程负责更新,最后再来一步帧同步操作,不就very good 了。
这里以OSG多线程渲染为例,谈谈OSG渲染引擎多线程渲染模式,再说说哪里有点“过时”了需要改进。
先谈点题外话,曾经看到知乎上一篇关于游戏引擎的设计讨论的文章,有位“大大”提出游戏引擎的设计关键在于架构设计,这是灵魂,一味强调画质如何,shader , 特效算法写的如何好,渲染的怎么真实漂亮那是舍本逐末,这些都可以照着“Real-TimeRendering” 或 是相关的 paper 实现即可。如果看过几款引擎或是自研过,就会觉得这观点很有道理,但我感觉如果架构到算法特效自己都走的通的话,心中有蓝图,引擎功能、易用性更好一些,也少走弯路。一款引擎之所以能在市场上能做成功,得到用户的认可,除了采用的技术先进,财力支持到位外,最主要的是有自己的特点,我们在甄别引擎的时候,也是根据各自行业需求,考量引擎的特点找一款认为比较合适的(“最合适”不好说)。前些年由于公司业务需要,在网上搜了一些渲染引擎对比的文章,大部分都是在不了解其特性的情况下人云亦云,把官方放出的特性罗列一下就完事了,究竟是哪个渲染引擎效率高,好在哪个方面,也没有说清楚,这样的总结还不如不总结。还有一部企业,需要渲染引擎就打算要自己开发,按我理解,大部分国内从事图形开发的程序员远没有到达市面上比较流行的渲染引擎作者的水平,还不如找个适合自己企业的第三方引擎,用一用,熟悉了再优化下,省时省心。等真的摸清了,搞透了原理,看多了再自研也不迟,除非自己企业真的有业界"大大"且舍得花钱,才适合一上来自研,闲话不多说了。
先看看 OSG 3.6.4 线程模型枚举变量的定义:
enum ThreadingModel{SingleThreaded,CullDrawThreadPerContext,ThreadPerContext = CullDrawThreadPerContext,DrawThreadPerContext,CullThreadPerCameraDrawThreadPerContext,ThreadPerCamera = CullThreadPerCameraDrawThreadPerContext,AutomaticSelection};
你会发现出现了两次等值枚举变量名称: ThreadPerContext = CullDrawThreadPerContext 和ThreadPerCamera = CullThreadPerCameraDrawThreadPerContext, 之前OSG 线程模型的定义有些让人费解,出现了“词不达意”的问题,我们在写程序“造词”的时候,一般要求看到变量或宏名或类名就知道其功能,这样便于其他人理解和阅读,ThreadPerContex 这类枚举变量不去认真分析下,还真不知道什么意思。 CullDrawThreadPerContext 表达的就很清楚了,场景对象裁剪和绘制都在设备线程中进行。CullThreadPerCameraDrawThreadPerContext 表明 相机线程负责场景裁剪,设备线程负责绘制。可以看出OSG官方也对不好理解的枚举变量定义相当于做了注解,加以修正。
从枚举变量可以看出,OSG主要有四种线程模型来适应不同的硬件或用户需求。
SingleThreaded : 单线程模型最好理解了,不做任何优化,按最常规方式渲染整个场景,OSG 没有开启另外的线程来加速场景绘制。SingleThreaded 模型并没有最大化的利用多处理器、多任务的硬件, 系统的渲染效率较低。
在这里我们先看一下OSG 渲染一帧,要经历哪几个过程:
上图是一般渲染引擎渲染一帧所经历的主要过程,各种渲染引擎大同小异,多线程也得走这个过程,只是为了对渲染效率做优化,在一定的条件下(比如Update, Draw阶段要求节点数据不存在不一致的情况)允许各阶段有所重叠。
那么针对多窗口的情况(也就是多上下文的情况, OSG 把一个窗口看成一个context, 记住Context 就是窗口,窗口就是Context ),OSG 如何优化来提升效率呢?这就是 CullDrawThreadPerContex 。
CullDrawThreadPerContex : 通俗的来说,我们为了多屏阵列显示创建了四个窗口(4contexts)来渲染整个场景,总不能做个大的渲染循环逐个窗口去绘制吧?!这样做效率很低。OSG 为每个窗口各自创建了线程,每个窗口线程负责自己的场景裁剪和绘制工作,主线程负责更新,最后再来一步帧同步操作,不就very good 了。