Unity URP渲染管线学习

unity版本2023.2.20f1c1,urp版本16.0.6

Universal Render Pipeline (URP) ,unity提供的Scriptable Render Pipeline;

1. 开始使用URP:

1. 使用urp模板创建新项目:

        

2. 将现有项目切换为urp:

        1. 安装Universal RP package:

                

        2. 配置urp:

                1. 创建Universal Render Pipeline Asset:

                        

                        

                        Universal Render Pipeline Asset 包含全局渲染和品质设置;

                        同时也创建了一个渲染管线实例(包含中间资源和渲染管线实现);

                2. 设置URP为激活的渲染管线:

                        

                        也可以给不同的品质设置不同的 URP Asset;

                        

                        如果是使用模板新创建的项目,会自动包含几个不同品质的URP Asset;

3. 导入urp例子:

        

        

        每个例子使用各自的URP Asset,如果要构建的话,得进行Graphics设置;

4. 创建场景模板:

        

        Basic (URP):包含一个摄像机和一个线性光;

        Standard (URP):包含一个摄像机,一个线性光和一个全局Volume(各种后处理);

5. 可以给每个品质创建一个URP Asset,这样运行时方便动态切换URP Asset:

        

        通过API QualitySettings.SetQualityLevel() 更改品质;

        脚本更改URP Asset:

UniversalRenderPipelineAsset data = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
data.renderScale = 1.0f;

6. 性能优化:

使用Unity Profiler 或者 GPU profiler (RenderDoc or Xcode),检查urp使用的内存,cpu和gpu;

 配置URP Asset,可做相关优化:

        1. 减少cpu占用,如关闭每帧刷新volumes;

                

        2. 减少纹理内存,如关闭HDR;

                

        3. 减少渲染纹理拷贝到内存(移动平台影响很大),如关闭depth texture;

                

        4. 减少渲染Pass,如关闭opaque texture和additional lights阴影投射;

                

        5. 减少发送到gpu的drawcall数,如开启SRP Batcher;

                

        6. 减少渲染到屏幕的像素数量(移动平台影响很大),如减小render scale;

                

优化点分类:

        1. 选择合适的rendering path,urp支持3中pass(后续说明);

        2. 减少urp内存占用:

            URP Asset:

                关闭Depth Texture(除非shader需要采样depth);
                关闭Opaque Texture(所有不透明物体快照,相当于GrabPass);
                使用延迟渲染路径时,关闭Use Rendering Layers;
                关闭High Dynamic Range (HDR),如果需要,设置HDR Precision 为 32 Bit;
                减小Main Light > Shadow Resolution;
                减小Additional Lights > Shadow Atlas Resolution;
                关闭Light Cookies或者减小Cookie Atlas Resolution 和 Cookie Atlas Format;

                        

                设置Store Actions 为 Auto or Discard;

            Universal Renderer asset(渲染实例):

                设置Intermediate Texture 为 Auto;

            其他:

                减少使用Decal Renderer Feature,因为需要额外的pass来渲染Decal;

                shader变体裁剪;

        3. 减少cpu处理时间:

            URP Asset:

                设置Volume Update Mode 为 Via Scripting,这样不必每帧刷新volumes;
                低端设备使用Reflection Probes时,关闭Probe Blending 和 Box Projection;
                减小Shadows > Max Distance,较少的对象执行shadow pass(节省gpu处理时间);
                减少Shadows > Cascade Count,这样减少了渲染pass数目(节省gpu处理时间);
                关闭Additional Lights > Cast Shadows,节省gpu处理时间和urp使用内存;

            减少相机使用数量;

        4. 减少gpu处理时间:

            URP Asset:

                减小或关闭Anti-aliasing (MSAA):
                        这样URP不会使用内存带宽来拷贝帧缓冲到内存或从内存复制出来;
                关闭Terrain Holes;
                开启SRP Batcher:
                        减少GPU在draw call之间的状态设置;
                        使材质球数据持续保存在GPU内存中;
                移动平台低端设备,关闭LOD Cross Fade,这样不会使用alpha test;
                使用前向渲染时,设置Additional Lights 为 Disabled, or Per Vertex;
                关闭Soft Shadows或者减小Quality;

            Universal Renderer asset(渲染实例):

                开启Native RenderPass(Vulkan, Metal or DirectX 12 graphics APIs);
                        URP自动减少将渲染纹理复制到内存和拷贝出去的频率,减少urp使用的内存量;
                使用Forward or Forward+ rendering path时, 设置Depth Priming Mode:
                        对于pc或者主机平台, 设为 Auto or Forced;
                        对于移动平台,设为Disabled;
                设置Depth Texture Mode 为 After Transparents:
                        避免在不透明通道和透明通道之间切换渲染目标;

            其他:

                避免使用Complex Lit shader,或者关闭Clear Coat;
                低端设备,静态对象使用Baked Lit shader,动态对象使用Simple Lit shader;
                使用Screen Space Ambient Occlusion (SSAO),注意相关设置;

2. URP概念:

1. URP Asset:

显示所有属性;

        

Rendering:

        

        Depth Texture:

                创建 _CameraDepthTexture,作为所有相机默认的depth texture;

        Opaque Texture:

                创建_CameraOpaqueTexture ,相当于GrabPass;

        Opaque Downsampling:

                降采样设置;

        Terrain Holes:

                关闭时,移除所有Terrain hole Shader变体;

        SRP Batcher:

                对于使用相同 Shader 的不同材质球非常有用;

                加上cpu渲染提交,优先于dynamic batching;

                需要 Shader 兼容SRP;

        Dynamic Batching:

                自动合并使用相同材质球的较小的mesh;

                适合于不支持 GPU instancing 的设备,否则应该关闭;

        Debug Level:

                Profiling: 给FrameDebugger提供更加详细的信息标签;

        Store Actions:

                丢弃或存储pass的渲染目标;

                开启时内存带宽显著增大(移动平台和基于瓦片的gpu);

                Auto:默认为Discard,如果检测到任何注入pass,则Store;

Quality:

        HDR:
                开启HDR,图像中最亮的值可超过1,用于获得大的范围光照计算或bloom effects;

         HDR Precision:

                颜色缓冲的精度;

        Anti Aliasing (MSAA):

                多重采样抗锯齿;

                移动平台不支持 StoreAndResolve 存储操作,若开启Opaque Texture,则忽略MSAA;

        Render Scale:

                缩放渲染目标分辨率;

        Upscaling Filter:

                放大渲染结果时使用的滤波器;

        LOD Cross Fade:

                关闭时,unity移除所有LOD cross-fade shader变体;

Lighting:

        关闭不需要的选项,会移除相关shader变体,提供性能和减少构建时间;

        Main Light:

                影响主要的平行光,即被设置为Sun Source或这最亮的平行光;

        Cast Shadows:

                主光源是否投射阴影;

        Shadow Resolution:

                控制shadow map texture大小,如果内存和渲染时间是瓶颈,则减小;

        Light Probe System:

                Light Probe Groups (Legacy):与内置渲染管线相同;

                Probe Volumes: 

                        Memory Budget:控制烘培全局照明贴图的大小;

                        SH Bands:L2提供更精确的结果,但更耗资源;

        Additional Lights:

                额外光源相关设置;

        Use Rendering Layers:

                光源只影响指定layer的对象;

        Mixed Lighting:

                开启后构建会包含混合光照的shader变体;

Shadows:

        Max Distance:

                从相机开始,unity渲染阴影的最远距离;

        Working Unit:

                Shadow Cascades 距离单位;

        Cascade Count:

                增加会影响性能,作用于main light;

        Split 1:

                级联1结束或者级联2开始的距离;

        Last Border:

                设置阴影淡出距离,在Max Distance,阴影淡出到零;

        Depth Bias:减少 shadow acne

        Normal Bias:减少 shadow acne

        Soft Shadows:

                对阴影纹理额外处理,使阴影看起来平滑;

                性能影响大;

                Quality:

                        Low:适合移动平台;

                        Medium:适合pc平台;

        Conservative Enclosing Sphere:

                新项目建议开启,该选项会影响shadows cascade distances计算;

                启用可能提高性能;

Post-processing:

        调整全局后处理设置;

        渲染实例上的设置:

                

                关闭的话,在构建时也会排除后处理的shader以及贴图;

                Data:包含对后处理需要的shader和贴图的引用;

        Grading Mode:

                使用Low Dynamic Range;

        LUT Size:

                设置urp色彩分级使用的 look-up texture 大小;

                默认32就好;

        Fast sRGB/Linear Conversions:

                快速伽马空间和线性空间转换;

Volumes:

        Volume Update Mode:

                Every Frame;

                Via Scripting;

        Volume Profile:

                设置场景默认的Volume Profile;

2. URP Global Settings:

Default Volume Profile:

        所有场景使用的Default Volume;

        urp显示所有可覆盖的属性;

Rendering Layers (3D):

        用于光照的layer;

Shader Stripping:

        Shader Variant Log Level:

        Strip Debug Variants:启用后就不能使用Rendering Debugger;

        Strip Unused Post Processing Variants:

                只保留Volume Profiles用到的 Shader Variants;

        Strip Unused Variants:

                更强力的裁剪,有可能多裁剪了;

3. Universal Renderer(渲染实例):

Rendering Paths:

        Forward Rendering Path
        Forward+ Rendering Path
        Deferred Rendering Path

3种渲染路径比较:

        

每个相机实时光源限制:

        Desktop and console platforms: 1 Main Light, and 256 Additional Lights;

        Mobile platforms: 1 Main Light, and 32 Additional Lights;
        OpenGL ES 3.0 and earlier: 1 Main Light, and 16 Additional Lights;

Universal Renderer asset 属性设置:

        

Filtering:

        Opaque Layer Mask:渲染不透明物体的Layer;

        Transparent Layer Mask:渲染透明物体的Layer;

Rendering:

        Rendering Path:

        Depth Priming Mode:

                使用一个 depth prepass 决定后续是否需要执行片元着色器;

                Disabled:

                Auto:

                        如果有一个渲染pass需要depth prepass,unity执行它并进行深度测试;

                        On Android, iOS, and Apple TV,不会启用;

                Forced:基于瓦片的延迟渲染会忽略这个属性;

        Depth Texture Mode:

                指定在渲染管线什么阶段拷贝场景深度到深度贴图;

                        After Opaques:在不透明物体渲染pass之后;

                        After Transparents:在透明物体渲染pass之后;

                        Force Prepass:执行depth prepass来生成深度贴图;

                在移动平台,After Transparents 可以显著降低内存带宽:

                        Copy Depth pass会导致渲染目标在不透明pass和透明pass之间进行切换;

                        渲染目标变更前,unity将颜色缓冲区的内容保存到主内存中;

                        当执行完Copy Depth pass,再将主内存中的颜色值加载到颜色缓冲区中;

                        在使用MSAA 时,更严重,因为还需要额外保存和加载MSAA数据;

        Native RenderPass:

                使用URP's Native RenderPass API;

                OpenGL ES 上没效果;

        Shadows:

                Transparent Receive Shadows:在透明物体上渲染阴影;

        Overrides:

                Stencil:进行目标测试;

                        

        Compatibility:

                Intermediate Texture:

                        是否通过中间纹理渲染;

                        Auto:需要时开启;

                        Always:在某些平台上对性能有大的影响;

        Renderer Features:

                Renderer Features列表;

4. URP 延迟渲染路径:

启用延迟渲染:

        

延迟渲染额外要求:

        Shader Model 4.5;

        不支持OpenGL 和 OpenGL ES API;

如果设备不满足延迟渲染条件,自动回退到 Forward Rendering Path;

延迟渲染实现细节:

        首先对每个GameObject 执行一次 G-Buffer pass,将材质球属性存储到G-Buffer中;

        然后在屏幕空间中使用 Lighting pass,基于G-Buffer中的信息进行光照计算;

G-buffer 中内容分布:

        

延迟渲染路径事件序列:

        

        Depth, or depth and normal prepass:

                对于不支持延迟渲染的材质球,需要执行depth prepass 或 depth and normal prepass;

                如果有 SSAO Renderer Feature,则需要执行 depth and normal prepass:

                        SSAO 使用屏幕空间深度和法线缓冲来计算环境遮挡;

        Forward-only Pass:

                不支持延迟渲染的pass,如:

                复杂的shader,G-buff无法存储足够多的材质球信息;

                不需要计算实时光的shader;

                自定义的shader,不支持延迟渲染;

5. Forward+ Rendering Path:

        

相比Forward Rendering Path,Forward+ Rendering Path具有如下优势:

        每个对象不限光源数量;

        支持2个以上reflection probes混合;

        使用ECS时支持多个灯光;

        程序绘制更灵活;

使用 Forward+ Rendering Path,Unity忽略一些 URP Asset 属性:

        Main Light:默认Per Pixel;

        Additional Lights:默认Per Pixel;

        Additional Lights > Per Object Limit:忽略;

        Reflection Probes > Probe Blending:默认开启;

6. Pre-built effects (Renderer Features):

        添加内置的效果到 URP Renderer;

添加 Renderer Feature 到 Renderer:

        选择一个Renderer:

                

                

3. Renderer Feature:

1. Render Objects Renderer Feature:

渲染所有的具有指定 Layer 的游戏对象,可指定时机和材质球;

使用 Render Objects 渲染位于物体背后的轮廓:

        

        使用两个Render Objects,一个渲染位于物体后面的轮廓,一个正常渲染;

        1. 指定一个Layer,用于渲染该类对象:

                

                

        2. 设置Renderer > Opaque Layer Mask,默认不渲染该Layer的物体:

                

                

        3. 添加Render Objects,使用指定的材质球渲染位于物体后面的轮廓:

                

                

        4. 添加Render Objects,正常渲染指定Layer的游戏对象:

                

                

Render Objects Renderer Feature属性:

        

2. Decal Renderer Feature:

将指定的材质球(贴花)投射到场景中其他的物体上;

贴花与场景中的灯光相互作用,并包裹在mesh周围;

使用贴花渲染功能:

1. 添加 Decal Renderer Feature 到 URP Renderer:

        

2. 创建一个材质球,使用Graphs/Decal shader,设置贴图:

        

3. 创建一个 game object,添加Decal Projector 组件:

        

        

贴花不能作用在透明物体上;

Decal Renderer Feature属性:

        

Technique:

        

        当前有两种技术渲染贴花;

        Automatic:

                根据构建平台,以及 Accurate G-buffer normals 选项;

        DBuffer:

                将贴花渲染到 Decal buffer (DBuffer) 中,随后在渲染不透明物体时将贴花覆盖在上面;

                Surface Data:

                        

                        指定将贴花哪些表面属性与底层网格混合;

                限制条件:

                        不支持OpenGL 和 OpenGL ES API;

                        需要先执行 DepthNormal prepass,在基于瓦片的gpu上性能低;

                        不适用于粒子和地形细节;

        Screen Space:

                在渲染完不透明物体后,使用从深度贴图构建的法线 或者 G-buff 中的法线 渲染贴花;

                该技术只支持 normal blending;

                        延迟渲染开启Accurate G-buffer normals时,法线混合不支持;

                Normal Blend:

                        

                        从深度贴图构建法线时,设置深度贴图的采样次数;

                Max Draw Distance:

                        unity渲染贴花距离摄像机的最大距离;

Decal Projector component:

        

        投影贴花到场景中其他对象上;

        必须使用具有 Decal Shader 的材质球;

        渲染贴花时,由于使用 Material property blocks,不支持SRP Batcher,为了减少draw call,将多个贴花使用的贴图合并为一个图集,然后使用相同的材质球,开启gpu instance渲染;

3. Screen Space Ambient Occlusion (SSAO) Renderer Feature:

环境遮挡效果使折痕、孔洞、交叉点和彼此接近的表面变暗;

在渲染不透明物体前先渲染SSAO纹理,然后在渲染不透明物体时使用该纹理;urp提供的shader支持该功能;

添加 SSAO Renderer Feature:

        

        

Method:

        噪声类型;

        性能影响微不足道;

Intensity:

        变暗强度;

Radius:

        法线贴图采样半径;

        性能影响大;

Falloff Distance:

        应用SSAO 距离相机最大距离;

Quality:

        Source:法线来源,SSAO 使用法线来计算表面暴露程度;

        Downsample:渲染 SSAO 纹理尺寸缩小为 1/2;

        After Opaque:在渲染不透明物体后再计算和应用 SSAO效果;

                当使用Depth 作为 Source时,直接使用已存在的深度值,无需执行depth prepass;

4. Screen Space Shadows Renderer Feature:

        

        屏幕空间阴影,使用单张贴图来计算和渲染主平行光阴影,避免使用多张阴影级联纹理;

        前向渲染使用该技术可能导致渲染加快,因为不需要访问多张阴影级联纹理;

        缺陷:

                需要执行 depth prepass 来构建深度纹理;

                需要内存来创建 screen-space shadows texture;

5. Full Screen Pass Renderer Feature:

使用材质球渲染全屏效果,例如插图和模糊;

创建一个自定义后处理效果:

        

4.  URP中的渲染:

渲染流程:

        

Camera loop:

Setup Culling Parameters:

        配置渲染对象,灯光和阴影的剔除参数;

Culling:

        使用上一步的参数挑选出摄像机可见的对象,阴影投射和灯光;

Build Rendering Data:

        构建渲染数据;

Setup Renderer:

        构建一个pass列表;

Execute Renderer:

        执行队列中的渲染pass;

Rendering Layers:

        用于配置灯光只影响指定的游戏对象;

        还可以在光源上单独配置阴影投射Layer:

                

        贴花也支持配置Layer;

缺陷:

        不支持 OpenGL 和 OpenGL ES API;

5. urp中的光照:

Light component:

        

        Bias:避免错误的自阴影;

                urp渲染管线不明显,使用内置渲染管线很容易观察到相关现象:

                

                (未添加Bias)

                

                (添加Bias)

                Depth:

                        渲染阴影纹理时深度添加偏移,以便相同的位置不被自身遮挡;

                Normal:

                        感觉是沿着法线缩小物体,使投射的阴影范围缩小;

Lighting Mode:

        

        决定场景中混合灯光的行为;

        

unity支持的Lighting Modes:

        Baked Indirect;

        Subtractive;

        Shadowmask;

Baked Indirect:

        将间接光烘培到光照贴图中,其他走实时光照处理;

        对于动态的游戏对象:

                接收实时直接光照;

                使用Light Probes接收间接光照;

        对于静态的游戏对象:

                接收实时直接光照;

                使用 lightmaps 接收间接光照;

Shadowmask:

        类似 Baked Indirect ,走实时直接光照和烘培间接光照;

        区别在于渲染阴影:

                让unity在运行时结合实时和烘培阴影,从而在远距离渲染阴影;

                需要一张额外的 lightmap,即 shadow mask,并在光照探针里存储额外的信息;

        在所有照明模式中提供最高保真度的阴影,但消耗最高的性能和内存;

        适合渲染逼真的场景,其远处的对象是可见的,如开放世界;

        设置Shadowmask品质:

                

        Distance Shadowmask:

                对于动态游戏对象:

                        在 Shadow Distance 内使用实时阴影;

                        在 Shadow Distance 外使用 Light Probes 接收静态物体的烘培阴影;

                对于静态游戏对象:

                        在 Shadow Distance 内使用实时阴影;

                        在 Shadow Distance 外使用 shadow mask 接收静态物体的烘培阴影;

        Shadowmask:

                对于动态游戏对象:

                        在 Shadow Distance 内接收动态物体的实时阴影;

                        在 Shadow Distance 内外使用 Light Probes 接收静态物体的烘培阴影;

                对于静态游戏对象:

                        在 Shadow Distance 内接收动态物体的实时阴影;

                        在 Shadow Distance 内外使用 shadow mask 接收静态物体的烘培阴影;

Subtractive:

        烘培直接和间接光照;

        将静态对象的阴影烘培到光照贴图;

        主平行光提供实时阴影给动态物体;

        适用于低端设备;

        对于动态游戏对象:

                接收实时直接光照;

                使用 Light Probes 接收间接光照;

                接收 被主光源照亮的动态物体投射的实时阴影,直到Shadow Distance;

                使用Light Probes接收静态物体投射的阴影;

        对于静态对象:

                使用lightmaps接收直接关和间接光;

                使用lightmaps接收来自静态物体的烘培阴影;

                接收 被主光源照亮的动态物体投射的实时阴影,直到Shadow Distance;

Universal Additional Light Data component:

        urp用来做内部数据存储;

        扩展和覆写标准Light组件;

URP 中的阴影:

urp中每盏光使用的 shadow map 数量取决于光源类型:

        A Spot Light :1张;

        A Point Light:6张,每个面对应一张;

        Directional Light:每级对应1张;

urp根据 shadow atlas 的尺寸以及 shadow map 的数量,来确定最合适的每个shadow map大小;

urp使用一个shadow map atlas给线性光,再使用一个shadow map atlas给其他的所有实时光;

Probe Volumes:

        光照探针相关;

Reflection probes:

        反射探针相关;

Lens flares:

        镜头光晕;

6. Cameras:

Universal Additional Camera Data component:

        urp用来做内部数据存储;

        扩展和覆盖标准相机功能;

UniversalAdditionalCameraData cameraData = camera.GetUniversalAdditionalCameraData();
Render Type:

        Base:渲染到屏幕或渲染纹理的常规相机;

        Overlay:在另一个相机的输出上渲染;

可将Base相机的输出与一个或多个Overlay相机结合起来,这被叫做 Camera stacking;

在场景中可以有多个 Base 相机;

Overlay 相机必须位于 Camera Stacking 系统中,有一个 Base 相机;

单独的 Overlay 相机不执行渲染流程,Overlay 相机可位于多个 Camera stacking中;

Overlay 相机只支持设置部分属性,其他的共用Base 相机;

后处理只能作用于单独的Base 相机或者Camera stacking;

Camera Stacking:

        

多个相机渲染到相同的目标:

        可将多个Base相机和 Camera Stacks 渲染到相同的目标,实现分屏渲染效果;

        在Base相机上设置渲染目标和渲染区域Viewport Rect;

渲染到渲染纹理:

        在urp中,渲染到纹理的相机比渲染到屏幕的相机先渲染,保证Render Texture中数据有效;

Motion vectors:

        使用一个全屏纹理保存屏幕空间的运动矢量;

        只在需要时才会去渲染运动矢量贴图;

        使用每个像素的 rg 通道记录渲染对象在屏幕上的uv偏移;

运动矢量有两类:

Camera motion vectors:

        单纯相机自身运动导致;

        只需要一个全屏的pass就可以渲染相机的运动矢量;

Object motion vectors:

        世界空间物体运动以及相机运动;

        每个物体都需要一个专门pass来计算物体运动,同时需要考虑相机的运动;

注意mesh renderer相关设置:

        

unity渲染物体运动矢量的条件:

        1. shader需要有一个 MotionVectors pass;

        2. 通过如下方式渲染:

                SkinnedMeshRenderer;

                MeshRenderer:Motion Vectors属性不设置为 Camera Motion Only;

                使用相关api渲染时,MotionVectorMode 不设置为 Camera;

        3. 如下的任一条件满足:

                1. MotionVectorMode设置为 ForceNoMotion,这时需要一个pass来清掉相机运动矢量;

                2. 在材质球上开启MotionVectors:

                        

                3. 材质球上关闭MotionVectors:

                        模型位置矩阵在当前帧与上一帧不匹配;

                        有 skeletal animation;

MeshRenderer 属性 Motion Vectors:

        

        Camera Motion Only:

                只使用相机运动矢量,不执行每个对象各自的motion vector pass;

        Per Object Motion:

                每个对象执行各自的motion vector pass;

        Force No Motion:

                每个对象执行各自的motion vector pass,通过一个shader变量指定渲染值为0;

urp 在 BeforeRenderingPostProcessing 事件渲染运动矢量;

urp通过2步渲染运动矢量纹理:

        1. 通过一个全屏pass渲染相机运动矢量;

        2. 执行需要渲染 motion vector 对象的 motion vector pass;

使用 motion vector texture:

        在自定义Renderer Feature中,在AddRenderPasses回调中

        添加ScriptableRenderPassInput.Motion标志;

        shader中:
                 //声明贴图
                TEXTURE2D_X(_MotionVectorTexture);
                SAMPLER(sampler_MotionVectorTexture); 
                //采样
                SAMPLE_TEXTURE2D_X(_MotionVectorTexture, sampler_MotionVectorTexture, uv);

抗锯齿:

        量化数据时,不能真实反应实际信息,存在锯齿;

摄像机后处理抗锯齿分类:

        

Fast Approximate Anti-aliasing (FXAA):

        使用一个全屏pass平滑像素边缘;

        最省资源;

Subpixel Morphological Anti-aliasing (SMAA):

        寻找图像边缘模式并依据模式混合边缘像素,比FXAA效果好;

Temporal Anti-aliasing (TAA):

        在多个帧中平滑边缘,但在物体快速移动时容易出现残影;

        使用运动矢量;

        开启TAA后,不能使用如下功能:

                Multisample anti-aliasing (MSAA);

                Camera Stacking;

                Dynamic Resolution;

硬件抗锯齿:

Multisample Anti-aliasing (MSAA):

        通过采样每个像素深度和模板值来计算最终值;

        解决空间锯齿问题,尤其三角形边缘锯齿问题;

        不能解决shader锯齿问题,如高光和纹理锯齿;

在大多数硬件上,MSAA比其他形式的抗锯齿更耗费资源;

在瓦片gpu上,没有后处理抗锯齿和自定义render features时,MSAA 更廉价;

MSAA是一种硬件抗锯齿方式,可与其他抗锯齿结合使用(除了TAA);

在不支持 StoreAndResolve 保存操作的移动平台,如果开启Opaque Texture, unity忽略MSAA;

7. 后处理:

urp包含了集成的后处理实现;

不支持 OpenGL ES 2.0;

添加后处理到场景:

        1. 相机开启后处理:

                

        2. 创建一个Game Object,添加 Volume 组件:

                

        3. 创建 Volume Profile:

                

                

        4. 添加 Volume Override:

                

Volumes:

使用 Volumes 应用后处理到部分或整个场景;

一个gameObject上可包含多个 Volume  组件;

urp遍历场景中所有激活的 Volume 组件,确定每个 Volume 组件对最终设置的权重;

使用相机与 Volume 组件的属性来确定权重,然后根据权重在多个 Volume 进行插值确定最终属性

两种 volume 类型:

        Global:无论相机在哪都生效;

        Local:相机靠近碰撞体时才生效;

每个 Volume 组件引用一个 Volume Profile;

有两个默认的全局 Volume :

        URP Global Settings:

                

                列出所有的 Volume Overrides,可修改属性值,但是不能禁用和删除 Overrides;

        每个品质对应 URP Asset:

                

                可修改属性,并添加或删除 Overrides;

Volume 组件:

        Mode:该Volume影响相机的方式;

                Global:Volume 无边界,影响场景中的每个相机;

                Local: 使用 Collider 来指定边界,只影响范围内的相机;

        Blend Distance:从Collider 开始,混合的最远距离;

        Weight:使用这个乘以urp使用相机位置和Blend Distance计算的值,获得最终的权重;

        Priority:多个Volume overrides存在时,使用Priority最大的;

Effect List:

        各种后处理效果使用;

        使用时参阅各个参数设置,注意性能影响;

8. Shaders and Materials:

内置渲染管线光照计算的shader不兼容urp,Unlit shader兼容urp;

SRP Batcher 兼容:

        在一个名为 UnityPerMaterial 的 CBUFFER 中 声明所有的材质球属性;

        在一个名为 UnityPerDraw 的 CBUFFER 中 声明所有的内置引擎属性;

                unity_ObjectToWorld ,unity_WorldTransformParams

urp中的光照模型:

        Physically Based Shading,基于物理的渲染;

        Simple Shading,经典光照模型;

        Baked Lit Shading,烘培光照;

        No lighting,不计算光照;

Physically Based Shading:

        遵守能量守恒,使用微面元模型;

        光照射到表面时,部分反射,部分折射;

                直接反射的光称为镜面反射;

                折射到物体内部的光又经过反射后最终散射出物体,称为漫反射;

        金属物体,表面会吸收和改变光;非金属物体反射部分光;

        代表 shader:

                Lit;

                Particles Lit;

Simple Shading:

        使用 Blinn-Phong 光照模型,非能量守恒,用于低端设备或者风格化渲染;

        代表 shader:

                Simple Lit;

                Particles Simple Lit;

Baked Lit Shading:

        不计算实时光;

        代表 shader:

                Baked Lit Shading;

No lighting:

        不计算实时光和烘培光;

        代表 shader:

                Unlit;

                Particles Unlit;

Material Variants:

        类似于 Prefab Variants;

urp不自持 Surface Shaders;

内置 shader 兼容urp和 SRP Batcher:

        1. 替换 CGPROGRAM, ENDCG HLSLPROGRAM, ENDHLSL;

        2. 替换 include语句为:

                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

        3. 添加 "RenderPipeline" = "UniversalPipeline" shader tag;

        4. v2f 结构体的名字替换为Varyings(urp命名约定):

struct Varyings
{
    float4 positionHCS : SV_POSITION;
    float2 uv: TEXCOORD0;
};

        5. 在 include 语句后,struct Varyings 语句前,声明输入struct Attributes:

struct Attributes
{
    float4 positionOS: POSITION;
    float2 uv : TEXCOORD0;
};

        6. 使用 TransformObjectToHClip 将顶点从对象空间转到裁剪空间:

o.positionHCS = TransformObjectToHClip (i.positionOS.xyz);

                urp在变量后面添加后缀表示space;

        7. 使用 CBUFFER  包含材质球的属性:

CBUFFER_START(UnityPerMaterial)
    float4 _Color;
    sampler2D _MainTex;
CBUFFER_END

                为了 SRP Batcher 兼容,同一个 subshader 有多个pass时,得使用相同的cbuff;

        8. urp shader不支持 fixed 类型;

        9. 让纹理采样支持 tiling and offset:

                urp 约定主纹理名 _BaseMap;

                添加 ShaderLab 属性 [MainTexture] 和 [MainColor];

                在 CBUFFER 前声明纹理和采样器:

            TEXTURE2D(_BaseMap);        //Texture2D _BaseMap
            SAMPLER(sampler_BaseMap);   //SamplerState sampler_BaseMap

                在 CBUFFER 中声明纹理缩放和偏移变量:

            CBUFFER_START(UnityPerMaterial)
                float4 _BaseMap_ST;
                float4 _Color;
            CBUFFER_END

                顶点着色器中应用贴图缩放和偏移:

            o.uv = TRANSFORM_TEX(i.uv, _BaseMap);

                片元着色器采样贴图:

            half4 texel = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv);

        10. 使用模型法线:

            struct Attributes
            {
                float4 positionOS: POSITION;

                half3 normal: NORMAL;        //NORMAL语义

                float2 uv : TEXCOORD0;
            };

            struct Varyings
            {
                float4 positionHCS : SV_POSITION;
                float2 uv: TEXCOORD0;

                half3 normal: TEXCOORD1;    //TEXCOORD1语义
            };

            Varyings vert(Attributes i)
            {
                Varyings o;

                o.positionHCS = TransformObjectToHClip (i.positionOS.xyz);
                o.uv = TRANSFORM_TEX(i.uv, _BaseMap);

                //法线变换到世界空间
                o.normal = TransformObjectToWorldNormal(i.normal);

                return o;
            }

        11. 从深度贴图获取像素的世界坐标:

                首先设置URP Asset,获取深度贴图:

                        

                包含头文件:

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"

                片元着色器计算屏幕贴图uv坐标:

            float2 UV = IN.positionHCS.xy / _ScaledScreenParams.xy;

                        片元positionHCS.xy = 顶点positionHCS.xy / 顶点positionHCS.w * 屏幕宽高

                        片元positionHCS.z = 顶点positionHCS.z / 顶点positionHCS.w;

                获取深度值:

            // Sample the depth from the Camera depth texture.
            #if UNITY_REVERSED_Z
                //反向缓冲,深度值为1到0,1代表近处物体,0代表远处物体
                real depth = SampleSceneDepth(UV);
            #else
                // Adjust Z to match NDC for OpenGL ([-1, 1])
                //这种情况下 UNITY_NEAR_CLIP_VALUE 为 -1
                real depth = lerp(UNITY_NEAR_CLIP_VALUE, 1, SampleSceneDepth(UV));
            #endif

                        SampleSceneDepth 返回 [0,1] 的深度值;

                        ComputeWorldSpacePosition需要NDC下的深度值:

                                D3D,  深度值范围 [0,1];

                                OpenGL,深度值范围 [-1, 1] ;

                计算世界位置:

            // Reconstruct the world space positions.
            float3 worldPos = ComputeWorldSpacePosition(UV, depth, UNITY_MATRIX_I_VP);
urp shader中的辅助方法:
shader库位置:

        urp:Packages/com.unity.render-pipelines.universal/ShaderLibrary/

        srp:Packages/com.unity.render-pipelines.core/ShaderLibrary/

坐标变换相关函数(ShaderVariablesFunction.hlsl):

float2 GetNormalizedScreenSpaceUV(float2 positionInClipSpace):

        获取屏幕空间uv,输入为屏幕坐标;

half3 GetObjectSpaceNormalizeViewDir(float3 positionInObjectSpace):

        获取对象空间的观察方向;

half3 GetWorldSpaceNormalizeViewDir(float3 positionInWorldSpace):

float3 GetWorldSpaceViewDir(float3 positionInWorldSpace):

        获取世界空间的观察方向;

VertexNormalInputs GetVertexNormalInputs(float3 normalOS, float4 tangentOS):

        输入对象空间的法线和切线,返回世界空间下的法线,切线,父切线;

VertexPositionInputs GetVertexPositionInputs(float3 positionInObjectSpace):

        输入对象空间的顶点位置,获取世界空间,观察空间,裁剪空间位置以及归一化设备坐标;

相机相关函数(ShaderVariablesFunction.hlsl):

float3 GetCameraPositionWS():

        获取相机世界空间位置;

float4 GetScaledScreenParams():

        获取屏幕像素宽高;

float3 GetViewForwardDir():

        返回摄像机在世界空间的正向;

bool IsPerspectiveProjection():

        是否是透视相机;

half LinearDepthToEyeDepth(half linearDepth):

        将 [0,1] 之间的深度值转化为 [near, far];

void TransformScreenUV(inout float2 screenSpaceUV):

        翻转uv坐标;

光照相关的函数:

添加头文件:

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

Light GetMainLight():

        获取主光源;

Light GetAdditionalLight(uint lightIndex, float3 positionInWorldSpace):

        返回世界空间指定位置的光源信息;

int GetAdditionalLightsCount():

        返回额外光源数量;

half3 LightingLambert(half3 lightColor, half3 lightDirection, half3 surfaceNormal):

        兰伯特漫反射光照;

half3 LightingSpecular(half3 lightColor, half3 lightDirection, half3 surfaceNormal, half3                 viewDirection, half4 specularAmount, half smoothnessAmount):

        BlinnPhong高光反射;

half SampleAmbientOcclusion(float2 normalizedScreenSpaceUV):

        返回屏幕空间中遮挡值,0为遮挡,1为不遮挡;

AmbientOcclusionFactor GetScreenSpaceAmbientOcclusion(float2 normalizedScreenSpaceUV)

        返回间接光照和直接光照的环境遮挡值;

阴影相关函数:

float4 GetShadowCoord(VertexPositionInputs vertexInputs):

        获取阴影坐标;

float4 TransformWorldToShadowCoord(float3 positionInWorldSpace):

        将世界坐标下的位置转换到阴影坐标;

计算阴影:

主光源需要的指令:

#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN

额外光源需要的指令:

#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS

Light GetMainLight(float4 shadowCoordinates):

         获取主光源,包含在指定 shadowCoordinates 处的 shadowAttenuation;

half ComputeCascadeIndex(float3 positionInWorldSpace):

        返回级联阴影的索引;

half MainLightRealtimeShadow(float4 shadowCoordinates):

        返回指定位置的主光源阴影值;

half AdditionalLightRealtimeShadow(int lightIndex, float3 positionInWorldSpace):

        返回指定位置的指定额外光源的阴影值;

half GetMainLightShadowFade(float3 positionInWorldSpace):

        返回主光源阴影消失的程度;

half GetAdditionalLightShadowFade(float3 positionInWorldSpace):

        返回额外光源阴影消失的程度;

float3 ApplyShadowBias(float3 positionInWorldSpace, float3 normalWS, float3 lightDirection):

        添加阴影偏移;

urp Pass tags:

LightMode使渲染管线决定使用哪个pass,默认为 SRPDefaultUnlit ;

UniversalForward:

        渲染物体几何和计算所有光照,用于前向渲染路径;

UniversalGBuffer:

        渲染物体几何信息,用于延迟渲染路径;

UniversalForwardOnly:

        使用前向渲染,不管 URP Renderer 使用哪个渲染路径;

DepthNormals:

        渲染深度和法线;

DepthNormalsOnly:

        延迟渲染路径使用;

Universal2D:

        2D渲染使用;

ShadowCaster:

        将光源视角的深度渲染到阴影纹理或深度纹理;

DepthOnly:

        仅渲染摄像机视角的深度信息到深度纹理;

Meta:

        编辑器下烘培光照贴图使用;

SRPDefaultUnlit:

        默认值;

MotionVectors:

        渲染运动矢量;

9. 自定义渲染和后处理:

Scriptable Render Pass:

注入脚本化渲染pass到渲染管线来获取自定义视觉效果;

创建 Scriptable Render Pass:

using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class RedTintRenderPass : ScriptableRenderPass
{
    //每帧调用一次,一个相机调用一次
    //实现渲染逻辑,发送drawcall
    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        
    }
}

自定义渲染pass的例子:

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class RedTintRenderPass : ScriptableRenderPass
{
    private Material material;

    //渲染纹理属性描述
    private RenderTextureDescriptor textureDescriptor;

    //临时纹理索引
    private RTHandle textureHandle;

    //构造函数,用于传参
    public RedTintRenderPass(Material material)
    {
        this.material = material;

        textureDescriptor = new RenderTextureDescriptor(Screen.width, Screen.height, RenderTextureFormat.Default, 0);
    }

    //在执行渲染pass前调用
    //用于配置 渲染目标,状态清除,创建临时渲染目标纹理,默认渲染到摄像机的渲染目标
    public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
    {
        textureDescriptor.width = cameraTextureDescriptor.width;
        textureDescriptor.height = cameraTextureDescriptor.height;

        //纹理不存在或者发生变更时,回收旧的,创建新的
        RenderingUtils.ReAllocateIfNeeded(ref textureHandle, textureDescriptor);
    }

    //每帧调用一次,一个相机调用一次
    //实现渲染逻辑,发送drawcall
    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        //Get a CommandBuffer from pool.
        CommandBuffer cmd = CommandBufferPool.Get();

        //获取摄像机渲染纹理
        RTHandle cameraTargetHandle = renderingData.cameraData.renderer.cameraColorTargetHandle;

        // Blit from the camera target to the temporary render texture,
        // using the first shader pass.
        Blit(cmd, cameraTargetHandle, textureHandle, material, 0);
        // Blit from the temporary render texture to the camera target,
        // using the second shader pass.
        Blit(cmd, textureHandle, cameraTargetHandle, material, 1);

        //Execute the command buffer and release it back to the pool.
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }

    //用于销毁临时资源,得在外部手动调用
    public void Dispose()
    {
        textureHandle.Release();
    }
}

通过 MonoBehaviour 脚本注入自定义渲染pass:

using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering;

[ExecuteAlways]
public class EnqueuePass : MonoBehaviour
{
    public Material material;

    private RedTintRenderPass redTintRenderPass;

    private void OnEnable()
    {
        redTintRenderPass = new RedTintRenderPass(material);
        redTintRenderPass.renderPassEvent = RenderPassEvent.AfterRenderingSkybox;

        // Subscribe the OnBeginCamera method to the beginCameraRendering event.
        //注意每个相机都会触发
        RenderPipelineManager.beginCameraRendering += OnBeginCamera;
    }

    private void OnDisable()
    {
        RenderPipelineManager.beginCameraRendering -= OnBeginCamera;

        redTintRenderPass.Dispose();
    }

    private void OnBeginCamera(ScriptableRenderContext context, Camera cam)
    {
        // Use the EnqueuePass method to inject a custom render pass
        cam.GetUniversalAdditionalCameraData().scriptableRenderer.EnqueuePass(redTintRenderPass);
    }
}
Scriptable Renderer Features:

添加到 renderer 的组件,用于更改渲染;

Scriptable Renderer Features 控制 Scriptable Render Passes 何时如何应用到renderer;

适用于实现通用的效果;

自定义 Scriptable Renderer Features:

using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class MyRendererFeature : ScriptableRendererFeature
{
    /// <summary>
    /// When the Renderer Feature loads the first time.
    /// When you enable or disable the Renderer Feature.
    /// When you change a property in the inspector of the Renderer Feature.
    /// </summary>
    public override void Create()
    {
        
    }

    /// <summary>
    /// Unity calls this method every frame, once for each camera
    /// inject one or multiple ScriptableRenderPass into the scriptable Renderer
    /// </summary>
    /// <param name="renderer"></param>
    /// <param name="renderingData"></param>
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        
    }
}

然后就可以添加 Renderer Feature 到 Universal Renderer asset;

在 Renderer Feature 中 添加 Scriptable Render Passes:

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class MyRendererFeature : ScriptableRendererFeature
{
    [SerializeField]
    private Material material;
    private RedTintRenderPass redTintRenderPass;

    /// <summary>
    /// When the Renderer Feature loads the first time.
    /// When you enable or disable the Renderer Feature.
    /// When you change a property in the inspector of the Renderer Feature.
    /// </summary>
    public override void Create()
    {
        if (material && redTintRenderPass == null)
        {
            redTintRenderPass = new RedTintRenderPass(material);
            redTintRenderPass.renderPassEvent = RenderPassEvent.AfterRenderingSkybox;
        }
    }

    /// <summary>
    /// Unity calls this method every frame, once for each camera
    /// inject one or multiple ScriptableRenderPass into the scriptable Renderer
    /// </summary>
    /// <param name="renderer"></param>
    /// <param name="renderingData"></param>
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        if (redTintRenderPass == null)
            return;

        if (renderingData.cameraData.cameraType == CameraType.Game)
        {
            renderer.EnqueuePass(redTintRenderPass);
        }
    }

    protected override void Dispose(bool disposing)
    {
        redTintRenderPass?.Dispose();
    }
}
使用 Renderer Feature 实现模糊效果:

自定义 Renderer Feature:

using System;
using UnityEngine;
using UnityEngine.Rendering.Universal;

[Serializable]
public class BlurSettings
{
    [Range(0, 0.4f)]
    public float horizontalBlur;

    [Range(0, 0.4f)]
    public float verticalBlur;
}

public class BlurRendererFeature : ScriptableRendererFeature
{
    [SerializeField]
    private BlurSettings settings;

    [SerializeField]
    private Material material;

    private BlurRenderPass blurRenderPass;

    public override void Create()
    {
        if(material && blurRenderPass == null)
        {
            blurRenderPass = new BlurRenderPass(material, settings);
            blurRenderPass.renderPassEvent = RenderPassEvent.AfterRenderingSkybox;
        }
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        if (blurRenderPass == null)
            return;

        var cameraType = renderingData.cameraData.cameraType;
        if (cameraType == CameraType.Game || cameraType == CameraType.SceneView)
        {
            renderer.EnqueuePass(blurRenderPass);
        }
    }

    protected override void Dispose(bool disposing)
    {
        blurRenderPass?.Dispose();
    }
}

自定义 Render Pass:

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class BlurRenderPass : ScriptableRenderPass
{
    private BlurSettings defaultSettings;
    private Material material;
    private RenderTextureDescriptor blurTextureDescriptor;
    private RTHandle blurTextureHandle;

    public BlurRenderPass(Material material, BlurSettings defaultSettings)
    {
        this.material = material;
        this.defaultSettings = defaultSettings;
        blurTextureDescriptor = new RenderTextureDescriptor(Screen.width, Screen.height, RenderTextureFormat.Default, 0);
    }

    public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
    {
        blurTextureDescriptor.width = cameraTextureDescriptor.width;
        blurTextureDescriptor.height = cameraTextureDescriptor.height;
        blurTextureDescriptor.colorFormat = cameraTextureDescriptor.colorFormat;
        RenderingUtils.ReAllocateIfNeeded(ref blurTextureHandle, blurTextureDescriptor);
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        CommandBuffer cmd = CommandBufferPool.Get();

        RTHandle cameraTargetHandle = renderingData.cameraData.renderer.cameraColorTargetHandle;
        UpdateBlurSettings();

        // Blit from the camera target to the temporary render texture,
        // using the first shader pass.
        Blit(cmd, cameraTargetHandle, blurTextureHandle, material, 0);
        // Blit from the temporary render texture to the camera target,
        // using the second shader pass.
        Blit(cmd, blurTextureHandle, cameraTargetHandle, material, 1);

        //Execute the command buffer and release it back to the pool.
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }

    private static readonly int horizontalBlurId = Shader.PropertyToID("_HorizontalBlur");
    private static readonly int verticalBlurId = Shader.PropertyToID("_VerticalBlur");

    private void UpdateBlurSettings()
    {
        if (material == null)
            return;

        var volumeComponent = VolumeManager.instance.stack.GetComponent<BlurVolume>();
        float horizontalBlur, verticalBlur;
        if(volumeComponent && volumeComponent.horizontalBlur.overrideState)
        {
            horizontalBlur = volumeComponent.horizontalBlur.value;
            verticalBlur = volumeComponent.verticalBlur.value;
        }
        else
        {
            horizontalBlur = defaultSettings.horizontalBlur;
            verticalBlur = defaultSettings.verticalBlur;
        }

        material.SetFloat(horizontalBlurId, horizontalBlur);
        material.SetFloat(verticalBlurId, verticalBlur);
    }

    public void Dispose()
    {
        blurTextureHandle?.Release();
        blurTextureHandle = null;
    }
}

自定义 volume component,来设置Render Pass中使用的相关参数:

using System;
using UnityEngine.Rendering;

[Serializable]
public class BlurVolume : VolumeComponent
{
    public ClampedFloatParameter horizontalBlur = new ClampedFloatParameter(0.05f, 0, 0.5f);

    public ClampedFloatParameter verticalBlur = new ClampedFloatParameter(0.05f, 0, 0.5f);
}

编写模糊效果使用的shader:

Shader "Custom/Blur"
{
    HLSLINCLUDE
    
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        // The Blit.hlsl file provides the vertex shader (Vert),
        // the input structure (Attributes), and the output structure (Varyings)
        #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"

        float _VerticalBlur;
        float _HorizontalBlur;
    
        float4 BlurVertical (Varyings input) : SV_Target
        {
            const float BLUR_SAMPLES = 64;
            const float BLUR_SAMPLES_RANGE = BLUR_SAMPLES / 2;
            
            float3 color = 0;
            float blurPixels = _VerticalBlur * _ScreenParams.y;
            
            //邻近像素卷积
            for(float i = -BLUR_SAMPLES_RANGE; i <= BLUR_SAMPLES_RANGE; i++)
            {
                float2 sampleOffset = float2 (0, (blurPixels / _BlitTexture_TexelSize.w) * (i / BLUR_SAMPLES_RANGE));
                color += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, input.texcoord + sampleOffset).rgb;
            }
            
            return float4(color.rgb / (BLUR_SAMPLES + 1), 1);
        }

        float4 BlurHorizontal (Varyings input) : SV_Target
        {
            const float BLUR_SAMPLES = 64;
            const float BLUR_SAMPLES_RANGE = BLUR_SAMPLES / 2;
            
            UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
            float3 color = 0;
            float blurPixels = _HorizontalBlur * _ScreenParams.x;
            for(float i = -BLUR_SAMPLES_RANGE; i <= BLUR_SAMPLES_RANGE; i++)
            {
                float2 sampleOffset = float2 ((blurPixels / _BlitTexture_TexelSize.z) * (i / BLUR_SAMPLES_RANGE), 0);
                color += SAMPLE_TEXTURE2D(_BlitTexture, sampler_LinearClamp, input.texcoord + sampleOffset).rgb;
            }
            return float4(color / (BLUR_SAMPLES + 1), 1);
        }
    
    ENDHLSL
    
    SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"}
        LOD 100
        ZWrite Off Cull Off
        Pass
        {
            Name "BlurPassVertical"

            HLSLPROGRAM
            
            #pragma vertex Vert
            #pragma fragment BlurVertical
            
            ENDHLSL
        }
        
        Pass
        {
            Name "BlurPassHorizontal"

            HLSLPROGRAM
            
            #pragma vertex Vert
            #pragma fragment BlurHorizontal
            
            ENDHLSL
        }
    }
}
Blit :

复制一种纹理到目的纹理;

在urp中避免使用 CommandBuffer.Blit,需使用 Blitter.BlitCameraTexture;

创建全屏 blit 效果,并使用 _CameraOpaqueTexture 纹理:

Renderer Feature:

using UnityEngine;
using UnityEngine.Rendering.Universal;

internal class ColorBlitRendererFeature : ScriptableRendererFeature
{
    public Material m_Material;
    public float m_Intensity;

    ColorBlitPass m_RenderPass = null;

    public override void Create()
    {
        m_RenderPass = new ColorBlitPass(m_Material);
    }

    //Callback after render targets are initialized
    public override void SetupRenderPasses(ScriptableRenderer renderer, in RenderingData renderingData)
    {
        if (m_RenderPass != null && renderingData.cameraData.cameraType == CameraType.Game)
        {
            // Calling ConfigureInput with the ScriptableRenderPassInput.Color argument
            // ensures that the opaque texture is available to the Render Pass.
            // 即在shader中可使用_CameraOpaqueTexture
            m_RenderPass.ConfigureInput(ScriptableRenderPassInput.Color);

            //设置pass参数
            m_RenderPass.SetTarget(renderer.cameraColorTargetHandle, m_Intensity);
        }
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        if (m_RenderPass != null && renderingData.cameraData.cameraType == CameraType.Game)
            renderer.EnqueuePass(m_RenderPass);
    }
}

Render Pass:

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

internal class ColorBlitPass : ScriptableRenderPass
{
    ProfilingSampler m_ProfilingSampler = new ProfilingSampler("ColorBlit");

    Material m_Material;
    RTHandle m_CameraColorTarget;
    float m_Intensity;

    public ColorBlitPass(Material material)
    {
        m_Material = material;

        //后处理前执行
        renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
    }

    public void SetTarget(RTHandle colorHandle, float intensity)
    {
        m_CameraColorTarget = colorHandle;
        m_Intensity = intensity;
    }

    //在渲染相机前执行,用于设置渲染目标
    public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
    {
        //其实不用设置,默认就是相机
        ConfigureTarget(m_CameraColorTarget);
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        var cameraData = renderingData.cameraData;
        if (cameraData.camera.cameraType != CameraType.Game)
            return;

        if (m_Material == null)
            return;

        CommandBuffer cmd = CommandBufferPool.Get();
        using (new ProfilingScope(cmd, m_ProfilingSampler))
        {
            m_Material.SetFloat("_Intensity", m_Intensity);
            Blitter.BlitCameraTexture(cmd, m_CameraColorTarget, m_CameraColorTarget, m_Material, 0);
        }
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }
}

ColorBlit shader:

Shader "Custom/ColorBlit"
{
        SubShader
    {
        Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"}
        LOD 100
        ZWrite Off Cull Off
        Pass
        {
            Name "ColorBlitPass"

            HLSLPROGRAM
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            // The Blit.hlsl file provides the vertex shader (Vert),
            // input structure (Attributes) and output strucutre (Varyings)
            #include "Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl"

            #pragma vertex Vert
            #pragma fragment frag

            TEXTURE2D_X(_CameraOpaqueTexture);
            SAMPLER(sampler_CameraOpaqueTexture);

            float _Intensity;

            half4 frag (Varyings input) : SV_Target
            {
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
                float4 color = SAMPLE_TEXTURE2D_X(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, input.texcoord);
                return color * float4(0, _Intensity, 0, 1);
            }
            ENDHLSL
        }
    }
}
Scriptable Renderer Feature 方法:

AddRenderPasses:用于添加一个或多个渲染pass;

Create:初始化;

Dispose:释放资源;

SetupRenderPasses:设置渲染pass,相比AddRenderPasses,该函数调用时存在渲染目标;

Scriptable Render Pass 方法:

Execute:执行渲染逻辑;

OnCameraSetup:用于配置渲染目标或者状态清除;

OnCameraCleanup:用于清除渲染时创建的资源;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值