资料介绍
URP渲染管线初步解析
LWRP现在在unity2019已经成为默认的管线了,并更名为URP(通用渲染管线),替代了原来的builtin管线,以下是应用阶段的渲染流程顺序。
步骤分析
URP整个渲染的主入口在UniversalRenderPipeline,他继承的RenderPipeline,是rsp的渲染流程关键类
PipelineSettings:这里会获取UniversalRenderPipelineAsset(也就是我们外部传入的管线的参数)
ScriptableRenderer:srp渲染器,需要把UniversalRenderPipelineAsset传给他。他是渲染核心,他会收集所有当前帧要渲染的pass,以及他会拥有渲染相关的灯光和后处理等执行方法。
_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 backbuffer if (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); #endif RenderSingleCamera(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相机额外显示UIif (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();
来源:电子创新网
- MATLAB使用教程-初步入门大全.PPT 0次下载
- 解析无线电伪码测目标距离系统的设计 0次下载
- EMI的诊断技巧与案例解析资源下载 45次下载
- 对嵌入式系统的初步认识
- 如何解析定时器产生的脉冲信号? 15次下载
- 渲染管线简单梳理
- URP中如何用多个相机?
- LWRP渲染流程梳理
- API6D的DBB及DIB型管线阀门结构解析 15次下载
- 如何选择直管线架空供热管网中的补偿器 3次下载
- 基于方位测量的地下管线探测系统设计与研究 2次下载
- 大型厂区内的地下管线探测
- 二进制无线传感器网络目标定位解析算法初步研究
- 地铁迷流对埋地管线腐蚀及抗蚀方法
- 地下管线的三维可视化研究
- 在NVIDIA Holoscan SDK中使用OpenCV构建零拷贝AI传感器处理管线 347次阅读
- CPU渲染和GPU渲染优劣分析 405次阅读
- 揭秘:实时渲染、离线渲染、云渲染和混合渲染的区别 570次阅读
- 图形渲染的威廉希尔官方网站 和原理:探索视觉效果的奇妙世界 683次阅读
- 三极管线性电源频域与时域分析 756次阅读
- 华为云渲染实践 1135次阅读
- 3D渲染——光栅化渲染原理解析 1930次阅读
- HDMI穿管线在预埋上可避免干扰问题 3569次阅读
- GPU渲染过程的几个阶段 8467次阅读
- 一文详解Unity中渲染顺序问题 1.7w次阅读
- GPU管线各个阶段知识点详细的分析理解 5324次阅读
- GPU原理 GPU渲染流程 9300次阅读
- 正向渲染和延迟渲染彼此之间有什么不同 1.1w次阅读
- 对正极材料的检测方法做一个初步的介绍 1w次阅读
- 什么是强制gpu渲染_强制渲染gpu有什么用 7712次阅读
下载排行
本周
- 1电子电路原理第七版PDF电子教材免费下载
- 0.00 MB | 1491次下载 | 免费
- 2单片机典型实例介绍
- 18.19 MB | 95次下载 | 1 积分
- 3S7-200PLC编程实例详细资料
- 1.17 MB | 27次下载 | 1 积分
- 4笔记本电脑主板的元件识别和讲解说明
- 4.28 MB | 18次下载 | 4 积分
- 5开关电源原理及各功能电路详解
- 0.38 MB | 11次下载 | 免费
- 6100W短波放大电路图
- 0.05 MB | 4次下载 | 3 积分
- 7基于单片机和 SG3525的程控开关电源设计
- 0.23 MB | 4次下载 | 免费
- 8基于AT89C2051/4051单片机编程器的实验
- 0.11 MB | 4次下载 | 免费
本月
- 1OrCAD10.5下载OrCAD10.5中文版软件
- 0.00 MB | 234313次下载 | 免费
- 2PADS 9.0 2009最新版 -下载
- 0.00 MB | 66304次下载 | 免费
- 3protel99下载protel99软件下载(中文版)
- 0.00 MB | 51209次下载 | 免费
- 4LabView 8.0 专业版下载 (3CD完整版)
- 0.00 MB | 51043次下载 | 免费
- 5555集成电路应用800例(新编版)
- 0.00 MB | 33562次下载 | 免费
- 6接口电路图大全
- 未知 | 30320次下载 | 免费
- 7Multisim 10下载Multisim 10 中文版
- 0.00 MB | 28588次下载 | 免费
- 8开关电源设计实例指南
- 未知 | 21539次下载 | 免费
总榜
- 1matlab软件下载入口
- 未知 | 935053次下载 | 免费
- 2protel99se软件下载(可英文版转中文版)
- 78.1 MB | 537793次下载 | 免费
- 3MATLAB 7.1 下载 (含软件介绍)
- 未知 | 420026次下载 | 免费
- 4OrCAD10.5下载OrCAD10.5中文版软件
- 0.00 MB | 234313次下载 | 免费
- 5Altium DXP2002下载入口
- 未知 | 233046次下载 | 免费
- 6电路仿真软件multisim 10.0免费下载
- 340992 | 191183次下载 | 免费
- 7十天学会AVR单片机与C语言视频教程 下载
- 158M | 183277次下载 | 免费
- 8proe5.0野火版下载(中文版免费下载)
- 未知 | 138039次下载 | 免费
评论
查看更多