游戏引擎开发:Task系统

一.前言

第一次在这里写技术文章,请多指教。做了很多年游戏开发了,我很幸运,一入行就做的游戏引擎方面的工作,这么多年碰到的坑也不少,所以写下来一些经验分享给大家,希望对新人能够有个指引。

在游戏引擎当中,有一个模块很少被大家提及,也许是因为它太基础了,不值得一提,但也有很多人根本不知道它的存在,那就是Task系统。

二.详解

之所以把这个模块拿出来讲,是因为这个模块是比较基础的模块,它本身非常简单,却在很多场合下可以短平快地解决问题。它封装的是一个任务队列,先进先出,所有先加入进去的任务会先执行,后加入进去的任务会后执行,我管这个模块叫做TaskManager。这个模块同时提供两种完全不同的任务队列,一种是子线程任务队列,而另外一种是主线程慢速任务队列。

首先看子线程任务队列,我管他叫ThreadTaskManager,它首先会创建一个线程,接受主线程加入的任务,而后在子线程执行,最后在再主线程执行此任务完成的回调。


主线程用于接受task,以及执行每个已经执行完毕task的回调


线程当中真正执行每一个task,并且把执行完的task投回给主线程等待执行回调

再来看主线程慢速任务队列,我管它叫TodoManager,它接受主线程加入的任务,而后在每帧Update的时候执行这些任务。之所以叫慢速队列,是因为每帧只留给它2ms的时间去执行,2ms时间到,就不再执行任务,而放到下一帧执行。这也是这个TodoManager的精髓所在,将一个大的任务分拆成多个小任务,在不同的时间片内完成。


慢速队列中执行的任务,每帧最多执行2ms

在主线程当中添加Task,在每帧Update执行,但每帧总执行时间仅限于2ms.

三.TaskManager的使用范例

TaskManager的作用,是在子线程和主线程中按序执行任务,这两个配合使用可以解决很多棘手的问题。

举例1,运行时创建Bumpmap

有一个技术叫做Bumpmap,可以理解为它是制作法线贴图方法的简化版本。一般法线贴图需要美术去做高模来生成,但是真正开发过程中,很有可能因为工期原因根本来不及做高模。现在这个古老的技术派上用上了,它的原理就是根据美术提供的纹理每个像素周围像素的亮度差,这里称之为像素的梯度,来计算出一张法线贴图。具体原理不知道的可以搜索一下,原理很简单易懂,现在的问题是,如何应用到引擎当中。

最直接的办法,就是每张需要用到Bumpmap的模型,都离线为其制作一张,作为资源存储下来,运行时加载。不过我不想这么做,我希望运行时创建。下面来拆分一下步骤:

1.加载原始纹理

2.lock该纹理,取出所有像素值

3.针对每一个像素计算出需要的值,这些值存在跟原始纹理同样尺寸大小的内存中

4.创建一张纹理,lock,填入刚刚计算好的数据,unlock

至此,bumpmap创建完毕。

如果是运行时创建,很明显4步操作会非常耗时,特别是bumpmap如果运用到其他玩家的角色身上,随着其他玩家进入视野,一秒之内如果被请求创建十几张这样的纹理,玩家的感受就是不停的卡顿。为解决这个问题,下面就该TaskManager登场了,上面4个步骤被进一步拆分为5个Task:

1.ThreadTask:加载原始图片文件,文件内容放入到内存中

2.TodoTask:通过内存数据创建纹理

3.TodoTask,Lock该图片纹理,取得所有的像素数据

4.ThreadTask:在线程中处理像素数据,逐像素计算出bumpmap,数据存放到一块新的内存中

5.TodoTask:通过bumpamap内存数据创建新的纹理。

凡是图形相关的API,全部都不允许在子线程执行。TodoTask被限制在无论有多少待执行的Task,每帧只运行2ms,而线程执行的task,根本不会对主线程帧率造成影响。这5个拆分后的Task,使得创建过程先后在子线程和主线程中交替执行,虽然流程上更加复杂,但避免了帧率的大幅抖动,从而在保证帧率一如既往平滑的前提下,完成BumpMap的创建。

举例2. 几帧之内的大量创建请求

在游戏运行过程当中,很容易出现几帧之内的大量创建其他玩家的请求,这种集中创建的请求非常容易造成卡顿。这时就需要通过TaskManager进行创建。

如果一帧有10个骨骼模型要创建,就创建10个TodoTask,每个task中还会创建不同的TodoTask和ThreadTask来完成创建工作。这样一来,当玩家控制的角色走进人群时,由于TodoTask的每帧只执行2ms、ThreadTask完全不会对主线程帧率造成抖动的特性,帧率假如说之前是稳定在50帧,创建过程中,帧率会稳定在30帧,创建全部完毕后帧率会回升至35帧左右,而过程中不会出现任何卡顿的现象,画面则表现为其他玩家角色在零点几秒之内先后出现。

四.结语

Task系统的最大优点,就是其不会对帧率造成大幅度抖动。在遇到频频卡顿难以优化的时候,TaskManager让如何优化大量占用主线程时间请求的工作,变成了如何细致地拆分成各个Task的游戏,从而解决问题。如果运用得当,游戏加载过程不会让人察觉到卡顿,会如行云流水一般顺畅。唯一要注意的问题就是,单个TodoTask执行的时间要严格限制,不能高于2ms,也就是说,单个TodoTask的内容要足够简单,如果只是一个任务就执行了1秒钟,这就说明任务拆分得有问题,要重新考虑更精细的拆分。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • 背景 担心了两周的我终于轮到去医院做胃镜检查了!去的时候我都想好了最坏的可能(胃癌),之前在网上查的症状都很相似。...
    Dely阅读 9,233评论 21 42
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,946评论 25 707
  • 一、多线程 说明下线程的状态 java中的线程一共有 5 种状态。 NEW:这种情况指的是,通过 New 关键字创...
    Java旅行者阅读 4,673评论 0 44
  • 你在吃饭哦?嗯我在吃小馄炖……嗯嗯哈哈哈!你为什么会笑呢?因为我喜欢,小 馄饨……哈哈你为什么笑啊?呵呵呵……你为...
    呼呼你阅读 110评论 0 0
  • 罗马尼亚 康斯坦察 这里是罗马尼亚的重要港口城市,也是连接东西欧、中东、北非和亚洲的战略要地,但如今这里却成...
    白羊先生阅读 492评论 5 3