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:用于清除渲染时创建的资源;