实现快速迭代的引擎设计 - Capcom RE Engine的架构与实现
[译]实现快速迭代的引擎设计 - Capcom RE Engine的架构与实现
原文(日文):ラピッドイテレーションを実現するゲームエンジンの設計
CEDEC2016上的一个Session。基本上是根据PPT的翻译(可能成为笔记更恰当一点),夹杂了一些现场听来的信息。PPT里有很多优点举例基本没什么营养就省略了。没正经的翻译过文章,有错误欢迎指正。主要是来抱囧聚大腿的。
以下正文:
引擎简介
- RE Engine是Capcom内部开发的次世代游戏引擎
- 支持PS4,XboxOne,PC(Steam/UWP)等平台
- 应用于开发中的项目生化危机7
- 引擎特征:高性能,高开发效率 <- 本文主要内容
游戏开发循环
- 编程 → Build → 确认 → ...
- DCC工具编辑 → 资源转换/导出 → 确认 → ...
- 游戏启动 → 测试/试玩 → 参数调整 → ...
- QA → Bug修正 → 打包 → ...
传统开发流程中,上面各个步骤不是费时间就是需要大量手工操作,效率相对低下。
快速开发的实现
→ 最终节省下来的时间用来提升游戏质量
- 减少等待时间(主要是Build以及资源转换等)
- 减少每回试错的时间
- 提高在运行环境(特别是主机上)中运行的频率
- 降低Bug率
RE Engine界面(译注:基本与UE4或Unity相近,支持所见即所得的编辑方式)
一些细节
- 生化7目前大约有20万行C#
- Editor里可以直接运行(整体更像UE4一点),支持所有资源的重新载入
- Scene是树状结构,有一个Master Scene,里面有Chapter1Scene等,导出Master Scene就等于是打包游戏。随着游戏流程Load/Unload Scene
- 演讲的 石田 智史 就是设计了MT Framework的人
Scene的结构示例
----------------------------------------------------------------------------------------------------------
引擎架构
(译注:演讲包括了新旧引擎的对比,但旧引擎的参考价值不大,故基本省略)
- 工具架构(Editor)
- 工具和Runtime用TCP/IP通信同步
- Runtime就算崩溃了Editor也能继续运行
- Runtime包含了各个平台的实现(如PS4的Runtime)
- 工具部分用WPF/C#开发,运行于Windows平台
- 问题点
- Runtime使用C++,而工具使用C#开发(包括游戏逻辑)
- 通信同步导致大量操作需要异步的实现,增加了复杂度
- 通信受限于传输速度
- 解决方案
- 统一通信协议:二进制通信,用C#的定义生成C++代码,Query/Response形式
- 远程对象系统:跨语言,跨进程的标识对象
- RuntimeType,RuntimeObject跟C#自己类似,成员貌似只是key-value对
- 通过ObjectID来同步(ID的正负来标识Editor/Runtime)
- 以手动同步为主,也可以注册进Observer来监视更新,对性能有影响
- Gizmo之类的辅助对象也采用类似的方法实现
- 优点
- Runtime可以自由切换
- 可以对应一些只能在实际环境确认的功能(VR,手机等)
- Runtime经常会崩溃ww
- 工具和Runtime用TCP/IP通信同步
- 资源架构
- File-Based(旧)→ Asset-Based(新):文件更容易产生冗余,并且不利于Reload
- 所有资源支持异步更新,用Cache加速资源转换,根据依赖关系优化打包速度
- 问题点
- Scene加载的时候需要预载入所有资源
- 引擎需要把握资源的载入顺序
- 需要实现异步载入的功能
- 解决方案
- 静态资源依赖关系生成
- 导入Asset的概念:在文件里追加了Metadata
- 工具启动的时候载入所有的Asset,并生成依赖关系
- 禁止代码控制的资源载入(译注:是不是完全不支持动态载入没有细说)
- 导入Asset的概念:在文件里追加了Metadata
- 严格的资源管理(译注:听起来自由度相当低,但毕竟是内部引擎估计可以根据实际需求调整而不用Hack)
- 禁止同步载入(容易导致Spike),并且异步载入有利于整体吞吐量
- 强制实现Reload
- 从游戏代码不能直接访问资源
- 静态资源依赖关系生成
资源依赖关系示例
- 脚本架构
- 旧引擎开发游戏即使用上分布式Build多的时候也要15分钟,并且容易崩溃,内存破坏
- 新引擎开发游戏时,游戏的逻辑部分完全使用C#,Build最多10秒,内存管理更好
- 问题点
- C#比C++更慢(Marshal,异常)(译注:猜测Marshal应该主要是与SDK的交互或者与第三方库的交互)
- GC导致的长时间停止
- 主机平台兼容性差(JIT禁用等)
- 解决方案
- 自制C#虚拟机(REVM)
- 以AOT为前提,不支持JIT
- 提高C++亲和性,降低Marshal开销
- 重写C#对象布局 ↓ ,包了一层C++对象在里面,Marshal的时候可以直接传指针。RC为引用计数。
- C# → C++:利用Clang解析C++代码,生成供C#访问的接口,最终和直接调用C++函数开销相同
- C++ → C#:利用template,最终和函数指针开销相同(译注:黑魔法没仔细看。。。)
- 更轻量的标准库(从Core FX搬)
- 编译
- 开发时:MicroCode(IL不适合解释执行,自制MicroCode) → 解释执行
- Release时:C++(il2cpp)→ 编译(Marshal部分inline展开)
- 编译时间:分散编译15分钟左右(跟旧引擎相近)
- 自制C#虚拟机(REVM)
C#的编译流程(Release时生成C++代码)
C#与C++的运行速度比较(有了GC当后盾对象生成快了很多)
开发时与实际运行时的效率比较(译注:可以看出来开发时候也不是特别惨)
- 自制实时垃圾回收(译注:有些概念不太懂就没详细解释了)
- 现有的GC不适合游戏
- 分代GC:Major GC导致的长时间停止
- 并行GC:GC执行中的速度低下,需要足够的空余内存
- 自动引用计数方式:循环引用的泄露,对引用计数操作的高Overhead
- 适合游戏的实时GC(FrameGC)
- 限定于游戏应用
- 主循环的同期点
- C#作为脚本的前提
- 特征
- 预测,可控的停止时间(GC中)
- 即时释放性(译注:用完的内存尽早释放)
- 可以更有效的利用所有内存
- 在多核环境下发挥性能
- 与C++的亲和性
- GC算法(译注:原ppt内有简单的流程动画说明可供参考)
- LocalObject:TLS,存在LocalTable里(当然也是TLS),C#生成的对象都作为LocalObject
- GlobalObject:所有线程都能访问,C++生成的对象都作为GlobalObject
- LocalObject → GlobalObject(译注:有点类似C#的Box只不过这里不是stack和heap的区别而是可访问线程和所属Table的区别)
- LocalFrame GC:C#的函数调用都结束的时候执行,释放所有LocalObject(译注:跟函数调用完了退栈差不多)
- Local GC:LocalTable满了的时候执行,根据引用计数释放LocalObject(实际很少发生)
- GlobalObject 释放
- 由各个线程增减引用计数,为0了就释放
- 当没有所有线程里都没有C#的栈(C#的调用都结束)的时候,执行Global GC(释放所有被有被用到的)
- 循环引用由Incremental Cycle GC释放
- (译注:基本上就是扫一遍找出循环部分)
- 每帧Check循环引用的辅助表CycleRoot,按需GC
- FrameGC的Overhead
- Write Barrier:线程内的直接Check引用计数,跨线程的利用InterlockedCAS
- LocalObject→GlobalObject:类似↑
FrameGC的一帧的Profile结果(译注:整数估计是Profile的Sample数)
----------------------------------------------------------------------------------------------------------
总结
- C#就是好!
- 生产效率大幅提升
- 杜绝应用层(游戏逻辑)产生的崩溃情况
- 执行效率没有问题!
- REVM比写的挫的C++更快
- FrameGC改变了GC不适合游戏的常识
----------------------------------------------------------------------------------------------------------
现场Q&A
- C#版本? 6.0 但是因为造了GC所以不算完全支持。
- 支持yield吗?应该不支持(?),C#的部分不支持跨帧的处理。
- 开发人数?开始2人 x 3个月,后来加了5,6人又做了几个月。(译注:听起来有点快的可怕,不过去年CEDEC的时候就有相关消息了所以实际应该更长一点)。感谢评论里@大萨比补充,现场有提到了开发速度快是因为RE引擎基于panta rhei开发。
- 序列化用了什么?第三方库?没有,因为涉及到ID之类的问题所以自己写了。
- 转成C++代码的时候出现问题了怎么办?那是bug...初期会有,现在已经基本没有了。顺便转出来的C++代码很长,VisualStudio会打不开...
- 游戏部分完全是C#吗?完全是。
- 如果开发游戏的那边提需求呢?因为是内部引擎所以可以商量,但不会让他们直接改。
- 场景中的顶点数之类的统计数据可以取得吗?Asset的meta信息里有,可以做。但是美术基本不关心这个....
- WPF的框架?Livet。
- 中间件是集成到引擎里?是的。
- 对中间件有什么要求?省内存,跑的快(笑)
实现快速迭代的引擎设计 - Capcom RE Engine的架构与实现的更多相关文章
- C++11(及现代C++风格)和快速迭代式开发
过去的一年我在微软亚洲研究院做输入法,我们的产品叫“英库拼音输入法” (下载Beta版),如果你用过“英库词典”(现已更名为必应词典),应该知道“英库”这个名字(实际上我们的核心开发团队也有很大一部分 ...
- 3D游戏引擎设计 实时计算机图形学的应用方法 第2版 pdf 带索引书签目录
3D游戏引擎设计 实时计算机图形学的应用方法 第2版 目录 第1章 概述1.1 图形硬件和游戏发展史1.2 本书版本与软件发展史1.3 章节导读 第2章 图形系统2.1 基础知识2.1.1 坐标系 ...
- 疫情期,如何用A/B测试快速迭代你的产品?
作者:友盟+数据科学家 杨玉莲.陆子骏 冠状病毒来袭牵动着每个人的心,但是病毒影响的不仅仅是我们的健康,也以极快的速度极深远地影响了整个移动互联网的发展.主流阵地原本在线下的需求,如医疗和生鲜电商,快 ...
- [连载]《C#通讯(串口和网络)框架的设计与实现》- 9.插件引擎设计
目 录 第九章 插件引擎设计... 2 9.1 框架的契约-接口... 2 9.2 插件的雏形-抽象类... 3 9.3 ...
- 引擎设计跟踪(九.14.2a) 导出插件问题修复和 Tangent Space 裂缝修复
由于工作很忙, 近半年的业余时间没空搞了, 不过工作马上忙完了, 趁十一有时间修了一些小问题. 这次更新跟骨骼动画无关, 修复了一个之前的, 关于tangent space裂缝的问题: 引擎设计跟踪( ...
- 互联网创业十问?good(快速迭代、把握核心用户应对抄袭,不需要把商业模式考虑完备,4种失败的信号,失败者没资格说趁着年轻...)
著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:曹政链接:https://www.zhihu.com/question/20264499/answer/28168079来源: ...
- 2.WF 4.5 流程引擎设计思路
本文主要给大家分享下基于WF 4.5框架的流程引擎设计思路 1.流程启动时的数据写入EventMsgPP对象中,ObjectAssemblyType记录流程启动时需要的类型,ObjectContent ...
- Nebula 架构剖析系列(二)图数据库的查询引擎设计
摘要 上文(存储篇)说到数据库重要的两部分为存储和计算,本篇内容为你解读图数据库 Nebula 在查询引擎 Query Engine 方面的设计实践. 在 Nebula 中,Query Engine ...
- 牛客寒假基础集训营 | Day1 E-rin和快速迭代(暴力 + 优化)
E-rin和快速迭代 题目描述 rin最近喜欢上了数论. 然而数论实在太复杂了,她只能研究一些简单的问题. 这天,她在研究正整数因子个数的时候,想到了一个"快速迭代"算法.设 f( ...
随机推荐
- [WinAPI] API 11 [创建目录]
编程实现创建目录是非常简单的,只要使用API函数CreateDirectory即可. (1) Createdirectory ◇参数lpPathName:输入参数,所要创建的目录名或路径.lpSecu ...
- 浅谈Entity Framework中的数据加载方式
如果你还没有接触过或者根本不了解什么是Entity Framework,那么请看这里http://www.entityframeworktutorial.net/EntityFramework-Arc ...
- JQuery以JSON方式提交数据到服务端
JQuery将Ajax数据请求进行了封装,从而使得该操作实现起来容易许多.以往我们要写很多的代码来实现该功能,现在只需要调用$.ajax()方法,并指明请求的方式.地址.数据类型,以及回调方法等.下面 ...
- artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口
artDialog是一个基于javascript编写的对话框组件,它拥有精致的界面与友好的接口 自适应内容 artDialog的特殊UI框架能够适应内容变化,甚至连外部程序动态插入的内容它仍然能自适应 ...
- apache 虚拟主机的配置
一.基于IP 1. 假设服务器有个IP地址为192.168.1.10,使用ifconfig在同一个网络接口eth0上绑定3个IP: [root@localhost root]# ifconfig et ...
- bigautocomplete实现联想输入,自动补全
bigautocomplete是一款Jquery插件.用它实现仿搜索引擎文本框自动补全插件功能很实用,使用也很简单,引入了插件之后写几行代码就可以实现,可以灵活设置. 先看效果图: 上图是通过ajax ...
- asp.net webAPI 自动生成帮助文档并测试
之前在项目中有用到webapi对外提供接口,发现在项目中有根据webapi的方法和注释自动生成帮助文档,还可以测试webapi方法,功能很是强大,现拿出来与大家分享一下. 先看一下生成的webapi文 ...
- atitit。自定义uml MOF EMF体系eclipse emf 教程o7t
atitit.自定义uml MOF EMF体系eclipse emf 教程o7t 1. 元对象机制(MOF,Meta-Object Facility)and 结构 1 2. 元模型图.模型图.对象 ...
- js 导出Excel
最近从Silverlight这边转到javascript过来,现在要导出一个导出excel的功能.上级领导指示当页显示多少数据,就导出多少数据,没有必要从后台在去数据.以前也没有接触过这方面的,在网上 ...
- js解析格式化json日期
代码: function jsonDateFormat(jsonDate) {//json日期格式转换为正常格式 try { var date = new Date(parseIn ...