在 Unity 技术开放日-上海站活动中,我们邀请到紫龙游戏 blackjack studio 的技术总监李知洋带来精彩分享,《基于 Unity SRP 的 Render Graph》。李知洋老师结合 GDC2017 上 EA 的《Frame Graph Extensible Rendering Architecture in Frostbite》中的思路和 Unity SRP 接口设计,实现了基于 Unity SRP 的 Render Graph 来满足多个在研项目多平台、高质量、多风格的渲染要求,Frame Graph Rendering Architecture、Unity SRP based Render Graph 的设计和实现,以及 Render Graph 的应用。
本文节选了部分精彩内容,完整内容已上传至 Unity 社区中的技术专栏。滑至文末,点击“阅读原文”,即可跳转至技术专栏学习:
https://unity.cn/projects/openday-blackjack-studio
紫龙游戏技术总监李知洋
大家好,我是紫龙游戏技术总监李知洋,今天的分享主要是分四个方面:
因为 Frame Graph 的概念来自 2017 年 GDC 在他们 Frostbite 当中做的这么一件事情。
因为我们是用 Unity SRP 做的开发。所以我会把 Unity 重要的 SPR 接口介绍一下。
介绍一下我们 Render Graph 的结构到底是怎样的。
具体对于我们在 SRP 开发当中遇到的实际问题,我们的设计跟实际遇到的项目当中的需求有些问题是怎么解决的。
Frame Graph
一开始是在 2017 年的 GDC Frostbite 里做的这件事情,Frostbite 寒霜引擎大家都比较熟悉,它是 EA 的 Inhouse 引擎,是 DICE 自己内部开发的,但是服务于了非常多 EA 游戏的项目,包括像《非法侵占》等等游戏,它涵盖的游戏不仅品类多,而且它的类型非常丰富 RPG,Racing,Sports,Action,FPS,TPS 等等都有。它们其实是用一套的渲染系统去支持上述类型的所有游戏,它的通用性非常强,不同的系统可以用同样的一套。
它对于不同的项目的这套渲染管线在不同项目当中的维护成本要尽可能的低,也就意味着这个管线要尽可能去兜底,把所有项目原本需要重复做的事情,它自己一个个把这个做掉。最后一个,它们有非常大的新项目,有很新的需求,每个项目的需求是不一样的,这个管线的扩展性要足够强,每个项目可以做自己的东西。
上面右下角那张图大家可以看到,Frame Graph 在整个系统当中处于中间的这层,对上对所有渲染类的 features,它的 features 抽象权在这,对下对的是 Resources 和 Shading system,对底层是你上层使用 Frame Graph 的人不需要关注底层跨平台 GFX 那层到底怎么去做的这一块内容,所以是在渲染系统中间承上启下的一个部分。
Frame Graph 本质上来说是通过图去组织渲染逻辑,我这引用 PPT 当中的一句话:“High level representation of Render Passes andresources”也就是说它对于渲染 Passes 和渲染资源很高程度的抽象,除此之外,它是 Full knowledge of the frame”,就是你看这个图就知道你这一帧要干什么,这一帧渲染逻辑是什么样的情况。
你看到下面这两张图,左边这张是他们在《战地 4》当中的一张图,可以看到它整个图上七七八八连了好几百个节点,所有这些节点无归于两类节点,一类节点是 Pass 节点,掌管你渲染逻辑的结果导致。另外一个节点叫 Resource,它是帮你去指定你的渲染 Resource 节点,比如 RT 等等渲染 Resource。
其实在整个 Graph 当中,大家看右下角那个图它是一个有向无环图去表示你渲染管线过程当中它的所有行为,除此之外,还有你在过程中所有用到的 Resource,最终 Resource 就是 RT 的这种 Resource。所以它其实本质上来说就是一张图,去描述你所有渲染管线,你一帧渲染到底有什么逻辑去走,你是用什么样的行为,你的名词有哪些,你所用的资源有哪些。
Frame Graph 的目标跟引擎本质:
因为它是在不同的工作室、在不同的游戏当中重复被使用到的一个引擎,所以他们想做这件事情是它需要简化渲染管线资源的管理,不需要你手动管理所有的资源,需要尽可能自动的方式去管理你渲染过程当中的所有这些资源。
它希望简化管线配置,你的管线发生变动了之后不需要重新去修改你的代码,然后去重新编译,然后再重新去发布,它不想这样,你希望做成数据驱动的方式去控制和编辑你的管线。
这是跟一些 High level 的 feature 相关,asynccompute 和资源 barrier 做CPU 并行同步处理。
它们希望能够去提供一个自洽的高效的渲染管线模块化,渲染管线就像乐高一样,插上去用乐高块能够编出来你自己渲染管线完整的逻辑。
可视化,因为它们是数据驱动的,所以需要可视化这种方式方便他们去 debuggging。
上面就是 Frame Graph 的介绍。下面介绍一下 Unity SRP 相关的内容。
Unity SRP 接口
如果你用过 SRP,会对这个非常熟悉。Unity SRP 本质上跟 Unity 原本的 Builtin 管线相比的最大优点是它的自由化程度足够高,在 SRP 管线中主要提供两个接口类,一个是 UnityEngine.Rendering.RenderPipeline,另一个是 UnityEngine.Rendering.RenderPipelineAsset ,这两个东西是各司其职。
其一、RenderPipeline 提供了一个 Render 的接口,它接口非常少。你可以通过调用这个 Render 接口对整个 Unity 的管线进行绘制,Unity 的渲染通过 Render 接口就接过来了,你完全为这个东西负责。
RenderPipeline 还会负责设置管帐的状态,比如你的 Render 怎么去设置都可以通过 RenderPipeline 去设置。RenderPipeline 同时还会管 Global 管线资源,管线不同 Pass 的资源可能会用 RenderPipeline 去管理。
其二、下面这是RenderPipelineAsset,它有以下这几个作用:
首先是用来创建 RenderPipeline。
其次是用于管理默认资源。比如有时候我们创建一个新的场景,希望这个新的场景在使用 SRP 的过程当中,这个新的场景很多默认资源,比如你的后处理的 Setting 希望是默认的,这个地方 RenderPipelineAsset 可以做这个事情。
最后是去管理 RenderPipeline 的设置数据,相信用过 URP 或者 HDRP 的同学都知道它有各种各样的设置,都可以在 Asset 上进行,这个设置之后 RenderPipeline 可以从 Asset 设置中把数拿出来,然后用来去设置自己管线内部的状态,这个东西更多是我对于游戏内的不同 level 都统一的一套设置,比如整个数量非常适合做一个全局的设置。
这是 Unity SRP 两个主要的接口类,分别介绍一下:RenderPipeline,阁下提到 Render 是 Unity SRP 每一帧更新的接口,它的那个 native 直接调出来后就到 Render 这块,它是唯一的接口。这个东西有两个参数,下面那个图是我们从代码里截出来的。
第一个参数是 ScriptableRenderContext,这个参数本身定义了 URP 中需要的管线状态和绘制指令,具体来说,它可以做几件事情:
第一个是去负责 CameraCulling,你把每个 Camera Culling 的传到你的这个 ScriptableRenderContext 当中,用这个东西 culling 出来的东西,Unity 帮你 culling 出来 camera 所能看到的这些绘制对象。
第二个是通过 DrawRenderers,ExecuteCommandBuffer 那套系统在这里面进行你所有必须的绘制。
第三个是你会去通过它的 submit 接口提交你的接口到 GPU 去。
Cameras 保留当前Unity所帮你捕获到这些 cameras 的信息,你场景中加一个 cameras,或者 Unity 自身所带的 cameras,都会在这个 cameras 的清单中展现。
这个 cameraslist 后面着重说一下 ScriptableRenderContext ,这个东西其实有几个比较重要的点:
一是CullingResults,这个里面其实存的,就是 Unity 如果你不是改原码的话基本拿不到一些绘制对象,你只能拿到的是很抽象的一坨东西,这个东西帮你 Culling 好了,这个东西排序什么都在里面。
二是DrawSettings,DrawSettings 对于 Scriptable Render Context 来说,它本质上描述了一件事情,这件事情就是我怎么去绘制我这一帧,包括我所有绘制对象,CullingResults 里面那些所有东西的排序,以及绘制的 ShaderPass,以及你需要设置的 perObjectData,是否开启 Instancing,是否开启 Dynamic Batching 等等这些设置都是在 DrawSettings 里做的。
三是FilterSettings,它是决定你画什么,比如 Unity 有 layerMask 这些东西,帮你去说这个是 Alayer,这个是 Blayer,这个是 Clayer,FilterSettings 本质上就是说这个 Pass 帮我把东西全部 culling 上了,我决定到底选择哪几个 layers 里的对象进行绘制。Unity 本身还提供了一个 RenderingLayerMask,其实本质也是一个 layerMask,但是它更轻量级,它只负责渲染这边的 layerMask 的对象,不会造成影响,所以非常推荐去使用。
四是DrawRenders,它是一个行为,它本质上来说是你设置了 DrawSettings,你设置了 DrawFilter 的 Settings,你有自己的 CullingResults,在这个过程中使用 CullingResults 对这个所有我想要绘制的对象进行我想要他进行的绘制,这是它本身四个比较重要的点。
Camera 就是 Render 参数的第二个参数,它其实是一个 camera 数组,是 Unity 提供给你在 scene 当前正在使用的 camera。比如你现在 Enable 的 camera,还有 Unity 自己提供的所有这些 camera。Unity camera有各种各样的类型:Scene View,Game,Reflection,Preview,VR。如果用 SRP 去驱动 Unity 的渲染,Unity不同对应的窗口需要用不同的 camera 去跟它对应,比如 Unity 有 Scene View、Game View、Material Preview,Material Preview 还有两个窗口,一个是 64×64 那个小的,你能看到的那个正方形的窗口,还有你点了 Material 之后右下角出现一个可以拉伸的窗口,以及 Unity 的烘焙等所有这些东西都是走的渲染管线。
所以用 SRP 要接的话,对每种不同的 RenderPathes 都要提供一个 RenderPathes 去使用。RenderPathes 是被分成了根据它的 CamerasType 和 CameraDrawState 来对它进行区分,到底这个 cameras 对应 Unity 里面哪个 View 渲染,这个东西是这么个情况。一般来说,如果你开个 SceneView,Unity 它自己提供 SceneView,它不会是你在场景当中放的那个 SceneView,但是如果是 Game 的话用的是 GameView,需要在 SRP 管线中做不同的处理的。
前面介绍了 Frame Graph,也介绍了 Unity SPR 比较重要的接口,下面说一下我们做的东西。
渲染管线是个需求,本质上来说,我们是个中台部门,中台部门是辐射各个项目,跟多个项目对接,我们同时支持多个项目。并且每个项目可能是跨平台的,项目可能是 mobile、 pc、console,所以管线需求完全不一样,硬件提供的完全不一致,所以管线拆的话要能够拆得出来。
通用性。因为我们的项目体量不一样,有的是小项目,有的是大项目,每个项目你可能 RenderPathes 不一样,但是你通过构建 RenderPathes 系统是同一套系统。
高可维护性。这个东西到那个项目当中去的,它从那根枝上生出来的果子要好维护,它不能在那边做太多的东西,然后反过来影响你主干的相关内容,你主干要提供足够的可维护性,尽量做很多不需要项目单独做的每个事情。
高可扩张性。因为 feature 会越来越多,美术同学有非常多创造,提出非常棒的 feature,这些新的 feature 可能需要有些新的开发,那么每一个新的 feature 的开发如果涉及到跟管线,不仅仅是材质,如果涉及到跟管线相关,我们需要很方便的把新的 feature 添加到渲染管线当中去。
我们其实之前用过 URP 和 HDRP,我们觉得这个写得非常棒,但是不够自由,有很高的参考价值,所以在我们实践过程中也对 Unity 自己实现的这套 URP、HDRP 做了参考。
我们先看一个视频,直观的感受一下这个 RenderGraph 到底是什么。
现在本质上来说,我现在是个 2T 直接连的,我屏幕上什么都没有,因为什么都没画,现在连的是一个场景当中不透明的物体,我把这个全部连上了,现在屏幕上画出来一个白色的小球,这个就是场景当中那个透明的物体,用的是 Unity 那个东西。我现在没有天空盒,我旁边还有一个天空盒的节点,我把管线的资源全不一下,然后整个天空盒也画出来了。
这个过程中,我没有进行如果代码编辑,我也不需要重新编译所有这些代码。本质上来说,我只要通过图的编辑,就可以去运行时改变我的管线以及处理好所有管线的执行顺序,以及它所有资源的管理。
李知洋老师还分享了 SRP Render Graph 的结构,以及在 SRP 开发当中遇到的实际问题和解决方案。完整内容已上传至 Unity 社区中的技术专栏,点击“阅读原文”,即可跳转至技术专栏学习:
https://unity.cn/projects/openday-blackjack-studio
Unity 官方微信
第一时间了解Unity引擎动向,学习最新开发技巧
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.