当前位置: 首页 > news >正文

URP源码学习(三)渲染管线的默认实现,forward

URP源码学习(三)渲染管线的默认实现,forward

https://zhuanlan.zhihu.com/p/157473939

整体理解

这部分算是URP的核心了,可编程管线,说的就是这个,有能力的项目,可以根据需要,做出更适合项目的管线。

unity提供了两个默认实现,一个是forward,一个2D,2D有时间再细看(原谅我的懒),forward这部分还是有些东西可看的,因为默认管线,这部分是完全看不到的,只能通过framedebugger看个流程,现在有机会看看内部实现,对理解管线也是很有好处的。


核心部分,pass

ForwardRenderer可以简单理解成驱动各个pass执行的一个管理者,pass则实现了具体的渲染逻辑。

pass的功能,分为两部分,配置rt和执行最终渲染。

pass-事件

基类文件中定义了一系列的渲染事件,RenderPassEvent。每个pass,在初始化的时候,都定义了一个event,这个event用于pass的排序。id之间间隔50,可加offet以添加额外的event。

pass-配置rt

pass在渲染前需要先配置渲染目标,renderer基类调用pass的Configure抽象函数。

renderPass.Configure(cmd, cameraData.cameraTargetDescriptor); 

每个pass实现具体逻辑,pass子类调用基类的ConfigureTarget方法,配置渲染目标和clear方法,子类没实现则渲染到相机的目标。

渲染目标分两个,color和depth,depth只有一个,color是个数组,默认第一个是相机目标,最大值在SystemInfo.supportedRenderTargetCount定义。

注意这个步骤只是设置了pass内部的数据,并没有真的通知到管线。

RenderTargetIdentifier[] m_ColorAttachments = new RenderTargetIdentifier[]{BuiltinRenderTextureType.CameraTarget}; 
RenderTargetIdentifier m_DepthAttachment = BuiltinRenderTextureType.CameraTarget; 

真正设置渲染目标,是通过CommandBuffer的SetRenderTarget方法,URP在CoreUtils类封装了一个静态函数SetRenderTarget。ScriptableRenderer类在ExecuteRenderPass方法中,先调用pass的Config函数,然后取pass的color和depth数据,设置为真正的渲染目标。

梳理一下这个流程


forward逻辑

forward-初始化

做了以下几件事

  • 创建几个特殊材质,用的是配置里的shader,这几个材质会传给对应的pass。
Material blitMaterial = CoreUtils.CreateEngineMaterial(data.shaders.blitPS); 
Material copyDepthMaterial = CoreUtils.CreateEngineMaterial(data.shaders.copyDepthPS); 
Material samplingMaterial = CoreUtils.CreateEngineMaterial(data.shaders.samplingPS);
Material screenspaceShadowsMaterial = CoreUtils.CreateEngineMaterial(data.shaders.screenSpaceShadowPS); 
  • 设置模板测试StencilState结构体。
  • 创建用到的每个pass,指定渲染RenderPassEvent。
  • 设置各个rt
  • 创建ForwardLights实例,用于光源的相关计算。
  • 创建RenderingFeatures,这个类里只有cameraStacking一个bool值,像是个没开发完的功能。

forward-Setup

简单说这个函数的作用就是把一个个pass加到个list里,供后边执行每个pass。

对于只渲染深度的相机,只需要添加3个pass,opaque、skybox、transparent。

一些重要的判断

  • 后处理是否开启,URP把后处理分成了两步,一个是实现常规特效的后处理,一个是抗锯齿这种,具体逻辑在PostProcessPass内部区分。
  • 是否需要深度图。首先判断相机配置,然后区分scene和game相机,scene相机之外,检测一下是否可以从opaque pass拷贝过来,以提升性能。具体判断在CanCopyDepth函数。

对一些特殊pass的说明,按代码顺序,没有特殊操作的略过

  • DepthOnlyPass
    • 开启条件:scene相机一定开启。game相机首先读取管线配置,同时CanCopyDepth为false,也就是说要注意本来不想开depth,但是开了抗锯齿等后处理效果,depth也会开启。
    • 用法:shader要有DepthOnly pass,渲染所有的DepthOnly Pass到指定texture,shader中通过_CameraDepthTexture获取。
  • CopyColorPass
    • 复制指定颜色buffer到目标颜色buffer,可以复制不透明物的渲染结果,用于扭曲特效。
    • 降采样可作为优化。
    • shader中通过_CameraOpaqueTexture获取。
  • CopyDepth和DepthOnly是互斥的,只需要用到一个,shader都是从_CameraDepthTexture获取。

其他pass还有很多 ,以后看shader的时候再一起细看。

ScriptableRenderer-Execute

unity把这部分放到了渲染管线的基类实现,也就是这部分被定义为通用的框架层,不建议项目扩展。

执行流程

  • 获取相机数据,关闭shader关键字,执行一次clear操作
SetCameraRenderState(cmd, ref cameraData); context.ExecuteCommandBuffer(cmd); cmd.Clear(); 
  • 对pass排序,按之前定义的RenderPassEvent。
  • 设置shader定义的时间变量,SetShaderTimeValues函数实现。
  • 将pass按event顺序,分成四块
    • BeforeRendering:用于处理阴影等,不是实际的渲染,只作为功能使用
    • MainRenderingOpaque:渲染不透明物体
    • MainRenderingTransparent:透明物体
    • AfterRendering:在后处理之后,在unity的demo中没看到具体渲染了啥,可能是扩展用的吧。
  • 执行SetupLights,设置光照需要的一系列参数,细节在光照部分细说。
  • 然后先执行BeforeRendering
  • 接着是一个循环,用于处理VR,由于手游中只需要渲染一次,VR部分先不管,只按一个去看。
    • 首先设置好相机属性,执行一次commandbuffer的clear指令。
    • 然后是不透明物体渲染,depth也在这执行。
    • 渲染透明物体,要注意的是透明和不透明物体的渲染,都是DrawObjectsPass实现的,参数不同,设置了RenderQueueRange和layer。
    • 渲染AfterRendering

forward大致流程大概就这些,写了好久,大量的细节都没细写,准备放到具体的pass里,结合shader和逻辑细看。

发布于 2020-07-07

 

 

 

 

 

 

 

 

相关文章:

  • URP 文档
  • XLua 源码学习原理(一)
  • [PyQt] 使用.qrc 生成资源文件供程序中使用
  • [Qt]设置窗口图标和EXE应用程序图标
  • 蓝噪声取样(Blue noise sampling) 相关知识
  • 关于cmd运行自动进行远程连接(自动填写用户及密码)
  • mstsc保存用户名和密码,实现自动登录远程桌面
  • mstsc命令详解
  • Loading.UpdatePreloading是什么东西,为什么会突然那么高?
  • unity中Loding.UpdatePreloading占用CPU过高如何解决?
  • [总结] 漫谈HDR和色彩管理(四)HDR标准和ACES
  • 视频名词浅析——HDR
  • 虚幻引擎学习之路:渲染模块之全局光照明
  • 我所理解的DirectX Ray Tracing
  • Unity 曲线插值(Hermite插值和Catmull_Rom插值)
  • python3.6+scrapy+mysql 爬虫实战
  • @jsonView过滤属性
  • 0x05 Python数据分析,Anaconda八斩刀
  • CSS 提示工具(Tooltip)
  • JAVA_NIO系列——Channel和Buffer详解
  • Javascript设计模式学习之Observer(观察者)模式
  • JavaScript中的对象个人分享
  • js写一个简单的选项卡
  • nginx 负载服务器优化
  • Node + FFmpeg 实现Canvas动画导出视频
  • Rancher-k8s加速安装文档
  • SpiderData 2019年2月23日 DApp数据排行榜
  • Transformer-XL: Unleashing the Potential of Attention Models
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • Vue UI框架库开发介绍
  • 案例分享〡三拾众筹持续交付开发流程支撑创新业务
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 跨域
  • 十年未变!安全,谁之责?(下)
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • 从如何停掉 Promise 链说起
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • ​iOS安全加固方法及实现
  • #{}和${}的区别?
  • #define 用法
  • #基础#使用Jupyter进行Notebook的转换 .ipynb文件导出为.md文件
  • (Bean工厂的后处理器入门)学习Spring的第七天
  • (day 12)JavaScript学习笔记(数组3)
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (五)关系数据库标准语言SQL
  • (转)关于多人操作数据的处理策略
  • (转载)Linux网络编程入门
  • (转载)利用webkit抓取动态网页和链接
  • .360、.halo勒索病毒的最新威胁:如何恢复您的数据?
  • .NET “底层”异步编程模式——异步编程模型(Asynchronous Programming Model,APM)...
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008