URP渲染管线初步解析

LWRP现在在unity2019已经成为默认的管线了,并更名为URP(通用渲染管线),替代了原来的builtin管线,以下是应用阶段的渲染流程顺序。

步骤分析

URP整个渲染的主入口在UniversalRenderPipeline,他继承的RenderPipeline,是rsp的渲染流程关键类

PipelineSettings:这里会获取UniversalRenderPipelineAsset(也就是我们外部传入的管线的参数)

ScriptableRenderer:srp渲染器,需要把UniversalRenderPipelineAsset传给他。他是渲染核心,他会收集所有当前帧要渲染的pass,以及他会拥有渲染相关的灯光和后处理等执行方法。

PerFrameBuffer:每帧设置的缓存数据

_GlossyEnvironmentColor:主要用于PBR这块的全局光照的颜色,在Lighting.hlsl的GlossyEnvironmentReflection,可以看到他主要是全局光照的高光部分颜色。

_SubtractiveShadowColor:主要用在除了主光源外的lightmap计算的阴影颜色。在SubtractDirectMainLightFromLightmap里使用。

PerCameraBuffer:每帧摄像机的缓存数据

_InvCameraViewProj:视图空间到投影空间的转置矩阵,如果用原始矩阵乘以反向矩阵结果为identity矩阵。如果一些矩阵以一个特定的方式变换向量,反向矩阵可以将他们变换回去。例如worldToLoclaMatrix和localToWorldMatrix是互逆的。

_ScaledScreenParams:屏幕缩放参数

antiAliasing:从asset中获取msaaSampleCount

Shader.globalRenderPipeline = " UniversalPipeline ";设置全局管线为UniversalPipeline

lightsDelegate:全局光照的回调

执行到Render中执行具体渲染流程:

SetupPerFrameShaderConstants:设置全局光照的数据,设置PerFrameBuffer中的_GlossyEnvironmentColor和_SubtractiveShadowColor。
其中_GlossyEnvironmentColor是通过球形谐波方程决定颜色的,最后要转到当前颜色空间(gamma空间或线性空间)
_SubtractiveShadowColor则是直接赋值具体的除去主光源后的阴影颜色,只是也有最后转到当前颜色空间的转换。

对当前Render给过来当前有哪些相机渲染的数据来进行每个相机的渲染RenderSingleCamera。
每个相机中的渲染步骤如下:

CullResults.GetCullingParameters:获取相机下的裁剪参数,如果返回false说明没有聂荣,不需要渲染这个相机。如果需要考虑到类似vr等情况需要区分左右眼的摄像机时需要把stereoAware设置为true。

CommandBuffer cmd = CommandBufferPool.Get(k_RenderCameraTag):这里从命令缓存池中获取一个gl命令缓存,CommandBuffer主要用于收集一系列gl指令,然后之后执行。

ProfilingSample是对指定名字做性能采样。

InitializeCameraData:初始化摄像机数据。

cameraData.msaaSamples:如果数量大于1说明需要多重采样。

cameraData.isSceneViewCamera:这个是查看当前要渲染的是否在unity的scene视图。

cameraData.isOffscreenRender:屏幕外渲染,如果摄像机的targettexture存在并且不是scene视图则这个为true。

cameraData.isStereoEnabled:就是左右眼做区别的摄像机,用于vr等

cameraData.isHdrEnabled:是否支持hdr,也就是高动态范围图像,就是可以在高光情况下能看清一些光照细节,提高细节渲染。

cameraData.postProcessLayer:后处理

cameraData.postProcessEnabled:是否开启后处理

cameraData.renderScale:渲染缩放比例

cameraData.opaqueTextureDownsampling:降采样

cameraData.isDefaultViewport:如果是正常的(0,0,1,1)则是默认的

cameraData.maxShadowDistance:最大阴影范围

cameraData.requiresDepthTexture:是否启用深度纹理

cameraData.requiresOpaqueTexture:是否保存非透明颜色信息

cameraData.defaultOpaqueSortFlags:默认的非透明渲染顺序

SetupPerCameraShaderConstants

PerCameraBuffer._ScaledScreenParams:是一个vector4,包括相机像素的长宽和纹素

PerCameraBuffer._InvCameraViewProj:设置摄像机视角的逆矩阵,通过GL.GetGPUProjectionMatrix获取到当前gpu正确坐标系的投影矩阵,再跟camera.worldToCameraMatrix视图矩阵相乘得到视图到投影的矩阵,再用Matrix4x4.Inverse获取逆矩阵。

cullingParameters.shadowDistance:设置阴影距离,这里会根据摄像机最远渲染距离来获得最远可达到的距离。

ScriptableRenderContext.ExecuteCommandBuffer(cmd):执行命令缓存

cmd.Clear();清除缓存数据

CullResults.Cull:根据裁剪的参数cullingParameters和context指定的渲染指令得到裁剪的灯光,物体等。

InitializeRenderingData:初始化渲染相关数据

GetMainLight:获取主光源,如果是直线光并且mainLightRenderingMode不为LightRenderingMode.PerPixel就是主光源。

mainLightCastShadows:如果可见光存在而且阴影设置存在则为true。

additionalLightsCastShadows:如果additionalLightsRenderingMode是LightRenderingMode.PerPixel并且可见光存在并且lightType是LightType.Spot且阴影存在则为true。

InitializeLightData:初始化灯光数据,这里设置了mainLightIndex(也就是GetMainLight获取的),设置additionalLightsCount获取叠加光源的数量,maxPerObjectAdditionalLightsCount最大叠加光源数量,shadeAdditionalLightsPerVertex就是是否是叠加光源,visibleLights可视光源,supportsMixedLighting支持混合光源。

InitializeShadowData:初始化阴影数据,如果有多光源会添加LWRPAdditionalLightData到光源的gameobject上,m_ShadowBiasData会设置阴影偏移和阴影发现偏移,主要用于解决自阴影的问题。

supportsMainLightShadows支持主光源阴影 。

mainLightShadowCascadesCount是阴影的级联个数,(mainLightShadowmapWidth、mainLightShadowmapHeight)主光源阴影贴图的宽高。

mainLightShadowCascadesSplit是阴影的级联分割,supportsAdditionalLightShadows是否支持多光源阴影。

additionalLightsShadowmapWidth、additionalLightsShadowmapHeight是多光源阴影贴图的宽和高都是additionalLightsShadowmapResolution。

supportsSoftShadows支持软阴影。

supportsDynamicBatching:是否支持动态批处理,这个是lwrp的动态批处理。

设置完渲染数据后就是开始设置渲染的顺序了:
renderer.Clear():再设置之前需要清理renderer的数据,不然前一帧渲染的dc是不会清掉的,dc就会越来越高。

setupToUse.Setup(renderer, ref renderingData):默认lwrp是用DefaultRendererSetup来设置的,当然你也可以实现IRendererSetup然后传入Render来自己实现。

DefaultRendererSetup:lwrp默认会有一系列渲染过程。会再Setup中确定渲染的先后。

SetupPerObjectLightIndices设置每个对象光照信息。

CreateRenderTextureDescriptor创建rt数据信息。

GetCameraClearFlag获取当前摄像机清理方式,lwrp对这层做了一些处理,主要是对深度剔除做了一些选项
如果是渲染到纹理则用CreateLightweightRenderTexturesPass这个pass执行一次渲染。

如果有渲染前要执行的pass要实现IBeforeRender接口,并且可以多个pass。

如果支持主光源阴影投放则执行MainLightShadowCasterPass的pass。

如果支持多光源阴影投放则执行AdditionalLightsShadowCasterPass。

之后执行SetupForwardRenderingPass,这个pass是必然执行的,设置摄像机到context里。

如果支持深度贴图获取的话会执行DepthOnlyPass(requiresDepthPrepass决定是否执行他),这里会用一个rt保存深度贴图新消息。

如果支持屏幕空间阴影获取,则会执行ScreenSpaceShadowResolvePass,这里会用一个rt记录屏幕空间中的阴影贴图。

然后执行SetupLightweightConstanstPass,主要设置主光源和其他光源的颜色,位置以及其他属性。如果不设置则会是默认颜色和位置等信息。

然后执行RenderOpaqueForwardPass,这个pass定义了两个pass名,LightweightForward和SRPDefaultUnlit。然后再Execute申请cmd来做不透明渲染。

如果支持后处理则会执行OpaquePostProcessPass,里面是申请一个临时rt做相关不透明的后处理。

如果是相机是天空盒清除方式的话并且天空盒不是空的话则执行DrawSkyboxPass,里面会绘制天空盒。

如果需要天空盒处理之后执行的话需要继承IAfterSkyboxPass实现相关pass。

如果是支持深度贴图的话并且没有执行requiresDepthPrepass的话(就是前面执行DepthOnlyPass的判断)则会执行CopyDepthPass,这里主要是拷贝深度贴图到全局变量_CameraDepthAttachment中,shader可以直接获取这个变量(如果有开深度贴图获取)

如果开启了接收不透明贴图的话则执行CopyColorPass,这里主要是把不透明渲染后的颜色输出到临时rt中。
然后执行RenderTransparentForwardPass,透明渲染方式。

如果支持后处理则执行TransparentPostProcessPass,也是一样申请一个临时rt做相关透明渲染的后处理。如果不需要并且不支持屏幕外渲染并且不是渲染到纹理的则要执行FinalBlitPass,这里主要设置贴图到全局变量_BlitTex,然后把颜色blit到内置rt中。

然后如果摄像机有IAfterRender的mono则会执行pass中的GetPassToEnqueue方法。

最后还会有一个EndXRRenderingPass的渲染,这个是支持立体摄像机的情况下执行的,主要是停止立体摄像机渲染。

然后再到外面renderer.Execute(context, ref renderingData);也就是把所有pass都执行一次。(前面只是加入到列表中,并没有执行每个pass的execute)

最后需要context.Submit来提交渲染,这时相应的gpu才会根据cmd来执行所有的pass。

源码分析

渲染前阶段:
根据渲染资产初始化渲染管线

      public UniversalRenderPipeline(UniversalRenderPipelineAsset asset)      {SetSupportedRenderingFeatures();    //设置渲染支持功能//PerFrameBuffer类中的参数指定PerFrameBuffer._GlossyEnvironmentColor = Shader.PropertyToID("_GlossyEnvironmentColor");PerFrameBuffer._SubtractiveShadowColor = Shader.PropertyToID("_SubtractiveShadowColor");PerFrameBuffer._Time = Shader.PropertyToID("_Time");        PerFrameBuffer._SinTime = Shader.PropertyToID("_SinTime");PerFrameBuffer._CosTime = Shader.PropertyToID("_CosTime");PerFrameBuffer.unity_DeltaTime = Shader.PropertyToID("unity_DeltaTime");PerFrameBuffer._TimeParameters = Shader.PropertyToID("_TimeParameters");PerCameraBuffer._InvCameraViewProj = Shader.PropertyToID("_InvCameraViewProj");PerCameraBuffer._ScreenParams = Shader.PropertyToID("_ScreenParams");PerCameraBuffer._ScaledScreenParams = Shader.PropertyToID("_ScaledScreenParams");PerCameraBuffer._WorldSpaceCameraPos = Shader.PropertyToID("_WorldSpaceCameraPos");// Let engine know we have MSAA on for cases where we support MSAA backbufferif (QualitySettings.antiAliasing != asset.msaaSampleCount)      //设置多重采样抗锯齿QualitySettings.antiAliasing = asset.msaaSampleCount;// For compatibility reasons we also match old LightweightPipeline tag.Shader.globalRenderPipeline = "UniversalPipeline,LightweightPipeline";  //设置渲染管线Lightmapping.SetDelegate(lightsDelegate); CameraCaptureBridge.enabled = true;RenderingUtils.ClearSystemInfoCache();}

渲染阶段
1.开始帧渲染

BeginFrameRendering(renderContext, cameras);    //开始帧渲染

2.判断色彩空间是否为线性空间

GraphicsSettings.lightsUseLinearIntensity = (QualitySettings.activeColorSpace == ColorSpace.Linear);    //色彩空间是否是线性空间

3.设置资产中的Batcher

GraphicsSettings.useScriptableRenderPipelineBatching = asset.useSRPBatcher; //设置资产中的Batcher

4.设置每帧shader参数

SetupPerFrameShaderConstants(); //设置帧着色器常量

5.排序相机

SortCameras(cameras);   //排序相机

6.遍历相机/开始相机渲染/渲染单个相机/结束相机渲染

foreach (Camera camera in cameras)      //遍历相机
{BeginCameraRendering(renderContext, camera);    //开始相机渲染#if VISUAL_EFFECT_GRAPH_0_0_1_OR_NEWER//It should be called before culling to prepare material. When there isn't any VisualEffect component, this method has no effect.VFX.VFXManager.PrepareCamera(camera);#endifRenderSingleCamera(renderContext, camera);  //渲染单个相机EndCameraRendering(renderContext, camera);  //结束相机渲染}

7.结束帧渲染

EndFrameRendering(renderContext, cameras);  //结束帧渲染

渲染单个相机流程(RenderSingleCamera)

源码分析

1.初始化剔除参数

if (!camera.TryGetCullingParameters(IsStereoEnabled(camera), out var cullingParameters))    //初始化剔除参数
return;

2.获取UniversalAdditionCameraData

UniversalAdditionalCameraData additionalCameraData = null;
if (camera.cameraType == CameraType.Game || camera.cameraType == CameraType.VR)
camera.gameObject.TryGetComponent(out additionalCameraData);

3.初始化CameraData,InitializeCameraData方法

InitializeCameraData(settings, camera, additionalCameraData, out var cameraData);

4.设置每个相机的shader参数

SetupPerCameraShaderConstants(cameraData);

SetupPerCameraShaderConstants方法:

//设置每个相机的shader参数
static void SetupPerCameraShaderConstants(CameraData cameraData)
{Camera camera = cameraData.camera;float scaledCameraWidth = (float)cameraData.camera.pixelWidth * cameraData.renderScale;float scaledCameraHeight = (float)cameraData.camera.pixelHeight * cameraData.renderScale;Shader.SetGlobalVector(PerCameraBuffer._ScaledScreenParams, new Vector4(scaledCameraWidth, scaledCameraHeight, 1.0f + 1.0f / scaledCameraWidth, 1.0f + 1.0f / scaledCameraHeight));Shader.SetGlobalVector(PerCameraBuffer._WorldSpaceCameraPos, camera.transform.position);float cameraWidth = (float)cameraData.camera.pixelWidth;float cameraHeight = (float)cameraData.camera.pixelHeight;Shader.SetGlobalVector(PerCameraBuffer._ScreenParams, new Vector4(cameraWidth, cameraHeight, 1.0f + 1.0f / cameraWidth, 1.0f + 1.0f / cameraHeight));Matrix4x4 projMatrix = GL.GetGPUProjectionMatrix(camera.projectionMatrix, false);Matrix4x4 viewMatrix = camera.worldToCameraMatrix;Matrix4x4 viewProjMatrix = projMatrix * viewMatrix;Matrix4x4 invViewProjMatrix = Matrix4x4.Inverse(viewProjMatrix);Shader.SetGlobalMatrix(PerCameraBuffer._InvCameraViewProj, invViewProjMatrix);}

5.获取ScriptableRenderer

ScriptableRenderer renderer = (additionalCameraData != null) ? additionalCameraData.scriptableRenderer : settings.scriptableRenderer;

6.填充剔除参数、CameraData

renderer.SetupCullingParameters(ref cullingParameters, ref cameraData);

7.性能采样

context.ExecuteCommandBuffer(cmd);

8.编辑器模式下Scene相机额外显示UI

#if UNITY_EDITOR
// Emit scene view UI       编辑器模式下Scene相机额外显示UI
if (cameraData.isSceneViewCamera)
ScriptableRenderContext.EmitWorldGeometryForSceneView(camer);
#endif

9.剔除

var cullResults = context.Cull(ref cullingParameters);      //剔除

10.根据管线设置、CameraData、剔除结果,初始化渲染数据RenderingData

InitializeRenderingData(settings, ref cameraData, ref cullResults, out var renderingData);

11.使用ScriptableRenderer根据RenderingData,Setup并Exute渲染上下文

renderer.Setup(context, ref renderingData);
renderer.Execute(context, ref renderingData);

12.释放CommandBufferPool

CommandBufferPool.Release(cmd);

13.提交渲染上下文

context.Submit();

URP渲染管线初步解析相关推荐

  1. Unity URP渲染管线下体积光的实现

    随着手机硬件的提高.主流手游厂商也逐渐以3D游戏为主,游戏也开始更注重3D场景渲染氛围,对渲染技术的要求也越来越高,PBR渲染.环境光遮蔽.阴影优化.场景反射.体积光等华丽的效果也逐渐成为优质画质手游 ...

  2. Unity教程:URP渲染管线实战教程系列【1】

    URP渲染管线实战解密(一) 现在越来越多的手游开发都采用URP渲染管线,来代替之前Unity引擎默认的向前渲染管线,本节通过一下几个方面来阐述URP 渲染管线,对URP渲染管线有个全面认识. (1) ...

  3. Unity3d 使用URP渲染管线实现AR阴影(阴影投射再透明地面)

    历经千辛万苦,对于一个不会写Shader的程序员,从内置渲染管线的AR阴影实现到URP渲染管线实现是多么艰辛.全网搜索资料,少的可怜. 不容易 感谢Unity 社区!!!!!!! unity-tech ...

  4. Unity Shader 学习笔记(4)URP渲染管线带阴影PBR-Shader模板 -- 新增可自定义阴影颜色

    材质面板截图 功能实现(URP渲染管线下): 1.进一步优化Shader结构和算法: 2.包含PBR材质: 3.投射和接收阴影,并升级支持自定义阴影颜色: 4.支持点光源照射(但不支持点光源阴影). ...

  5. Unity Shader 学习笔记(3)URP渲染管线带阴影PBR-Shader模板(ASE优化版本)

    此 Shader 已经不是最新版本,最新版本见本专栏的第四篇文章: Unity Shader 学习笔记(4) 材质面板截图: 功能实现(URP渲染管线下): PBR材质.投射和接收阴影. 代码展示: ...

  6. Unity URP渲染管线使用边缘高亮插件

    在URP渲染管线下使用物体边缘高亮插件 Outline 链接:https://pan.baidu.com/s/1r_YWCo9yxnrBdf9u_cTZmA 提取码:099y 按照上面的步骤 对Out ...

  7. URP Lit Shader解析(1)

    [说明] URP 版本为12.1.1,Lit Shader最复杂,明白了这个Shader,其他的都可以搞明白. 会拆分成一步步地解析,所有解析都写在源码中. 如有错误,欢迎指正! Shader &qu ...

  8. 普通管线的材质球在URP渲染管线中出现的材质丢失问题

    导入模型时发现材质球材质丢失 原因:应该是不同的渲染管线所支持的shader不一样,原shader不支持URP 解决方法:新建URP管线的普通材质球,把贴图和法线贴图放上去调一下属性再重新复制 结果:

  9. Unity-3DRPG游戏 学习笔记(1)--使用URP渲染管线

    教程地址: Unity2020 3DRPG游戏开发教程|Core核心功能01:Create Project 创建项目导入素材|Unity中文课堂_哔哩哔哩_bilibili 创建URP通用渲染管线(2 ...

最新文章

  1. 测试另外一个厂商的T254 高频功率MOS管
  2. 隐式类型转换和整型提升
  3. 设置progressbar进度条颜色
  4. php获取dropzone上传的文件,php - 如何上传文件,使用php中的dropzone将文件详细信息保存到mysql数据库 - SO中文参考 - www.soinside.com...
  5. Netsparker超轻量级Web安全漏洞扫描工具使用教程介绍
  6. rust vs java_为什么我从Java切换到Rust
  7. 创维发布四款新品 将投入65亿元建MiniLED显示科技产业园
  8. ZT pthread_detach
  9. django动态HTML转PDF方法
  10. Linux操作系统下6个应急处理小常识
  11. 如何编译并修改FBReader的package(安卓平台)
  12. 计算机硬盘使用率,硬盘占用率和速度
  13. CardView学习和使用
  14. 微信小程序 添加分割线
  15. 实验题集4:函数R6-1 面积计算器(函数重载) (10 分)
  16. qq附近的人怎么引流?如何利用手机QQ附近功能引流
  17. 安卓应用加固壳判断java厂商_使用frida来hook加固的Android应用的java层
  18. 前后落差大用什么词语_形容两个人反差特别大的成语-有明显的反差 用什么词形容-形容前后态度反差巨大的词...
  19. 小程序如何获取用户名和头像?
  20. 【前端篇】火狐浏览器打开调试器,报“Error: Incorrect contents fetched, please reload.”

热门文章

  1. 【搞事情】利用PyQt为目标检测SSD300添加界面(一)
  2. 同济计算机博士要求低,上海同济考博的一点经验分享
  3. sat求解器解哈密顿回路
  4. python教程98--python人工智能之文字识别ddddocr
  5. CSS counter计数器(content目录序号自动递增)详解
  6. minio数据迁移-mc
  7. STC 纯硬件自动下载电路 V2
  8. win10动态壁纸怎么设置_教程:iPhone/Android设置动态壁纸
  9. 架构师进阶之四redis实现分布式锁redission
  10. Haskll Lesson:Huffman编码实现文本压缩