找回密码
 立即注册
查看: 177|回复: 0

URP 毛玻璃(升级至URP_v14.0.6)

[复制链接]
发表于 2024-7-15 18:57 | 显示全部楼层 |阅读模式
注:这篇笔记的目的不在于如何制作玻璃特效(毛玻璃作为实践的素材),目的在于升级任何使用了【cmd.Blit】这个api的URP特效,以撑持Single-Pass Instanced VR
本篇包含内容:
unity版本2021.3.8,URP版本v12.1.7:暂未能撑持Single-Pass Instanced VR;
unity版本2022.2.7,URP版本v14.0.6:可撑持Single-Pass Instanced VR;
(URP在不竭升级,技术更迭…这篇笔记里的东西过不了多久可能也会变成过时的东西,但愿能帮到此刻的你 )
0.一个BRP示例(含毛玻璃shader)

先看一个过时的BRP示例,来自: https://blog.unity.com/technology/extending-unity-5-rendering-pipeline-command-buffers
流程概括:


一个用于做Blur计算的shader(”Hidden/SeparableGlassBlur”);(下面的shader语法已改为URP)
  1. Shader ”Hidden/SeparableGlassBlur” {
  2.     Properties {
  3.         _MainTex (”Base (RGB)”, 2D) = ”” {}
  4.     }
  5.     ......//注:我喜欢把代码分块排版,这样看起来斗劲舒服,代码里呈现的【......】意思是这部门内容在长虚线下面
  6. }
  7. ------------------------------------------------------------------------------------------
  8. Subshader {
  9.     Tags { ”RenderPipeline”=”UniversalPipeline” }
  10.     Pass {
  11.         Name ”01”
  12.         Tags { ”LightMode”=”UniversalForward” }
  13.         ZTest Always
  14.         Cull Off
  15.         ZWrite Off
  16.         Fog { Mode off }
  17.         
  18.         HLSLPROGRAM
  19.         #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
  20.         #pragma fragmentoption ARB_precision_hint_fastest
  21.         #pragma vertex vert
  22.         #pragma fragment frag
  23.         ......
  24.         ENDHLSL
  25.     }
  26. }
  27. ------------------------------------------------------------------------------------------
  28. struct appdata_img {
  29.     float4 vertex : POSITION;
  30.     half2 uv : TEXCOORD0;
  31.     UNITY_VERTEX_INPUT_INSTANCE_ID
  32. };
  33. struct v2f {
  34.     float4 pos : POSITION;
  35.     float2 uv : TEXCOORD0;
  36.     float4 uv01 : TEXCOORD1;
  37.     float4 uv23 : TEXCOORD2;
  38.     float4 uv45 : TEXCOORD3;
  39. };
  40. float4 offsets;
  41. sampler2D _MainTex;
  42. v2f vert (appdata_img v) {
  43.     v2f o;
  44.     o.pos = TransformObjectToHClip(v.vertex);
  45.     o.uv.xy = v.uv.xy;
  46.     o.uv01 =  v.uv.xyxy + offsets.xyxy * float4(1,1, -1,-1);
  47.     o.uv23 =  v.uv.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 2.0;
  48.     o.uv45 =  v.uv.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 3.0;
  49.     return o;
  50. }
  51. half4 frag (v2f i) : COLOR {
  52.     half4 color = float4 (0,0,0,0);
  53.     color += 0.40 * tex2D (_MainTex, i.uv);
  54.     color += 0.15 * tex2D (_MainTex, i.uv01.xy);
  55.     color += 0.15 * tex2D (_MainTex, i.uv01.zw);
  56.     color += 0.10 * tex2D (_MainTex, i.uv23.xy);
  57.     color += 0.10 * tex2D (_MainTex, i.uv23.zw);
  58.     color += 0.05 * tex2D (_MainTex, i.uv45.xy);
  59.     color += 0.05 * tex2D (_MainTex, i.uv45.zw);
  60.    
  61.     return color;
  62. }
复制代码
一个用于衬着玻璃的shader(GlassWithoutGrab.shader);(下面的shader语法已改为URP)
  1. Shader ”FX/Glass/Stained BumpDistort (no grab)” {
  2.     Properties {
  3.         _BumpAmt  (”Distortion”, range (0,64)) = 10
  4.         _TintAmt (”Tint Amount”, Range(0,1)) = 0.1
  5.         _MainTex (”Tint Color (RGB)”, 2D) = ”white” {}
  6.         _BumpMap (”Normalmap”, 2D) = ”bump” {}
  7.     }
  8.     ......
  9. }
  10. ------------------------------------------------------------------------------------------
  11. SubShader{
  12.     // We must be transparent, so other objects are drawn before this one.
  13.     Tags { ”RenderPipeline”=”UniversalPipeline” ”Queue”=”Transparent” ”RenderType”=”Opaque” }
  14.     Pass {
  15.         Name ”BASE”
  16.         Tags { ”LightMode”=”UniversalForward” }
  17.             
  18.         HLSLPROGRAM
  19.         #pragma vertex vert
  20.         #pragma fragment frag
  21.         #pragma multi_compile_fog
  22.         #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
  23.         ......
  24.         ENDHLSL
  25.     }
  26. }
  27. ------------------------------------------------------------------------------------------
  28. struct appdata_t {
  29.     float4 vertex : POSITION;
  30.     float2 uv: TEXCOORD0;
  31. };
  32. struct v2f {
  33.     float4 vertex : POSITION;
  34.     float4 uvgrab : TEXCOORD0;
  35.     float2 uvbump : TEXCOORD1;
  36.     float2 uvmain : TEXCOORD2;
  37.     // UNITY_FOG_COORDS(3)
  38.     float fogFactor : TEXCOORD3;
  39. };
  40. float _BumpAmt;
  41. half _TintAmt;
  42. float4 _BumpMap_ST;
  43. float4 _MainTex_ST;
  44. v2f vert (appdata_t v)
  45. {
  46.     v2f o;
  47.     o.vertex = TransformObjectToHClip(v.vertex);
  48.     #if UNITY_UV_STARTS_AT_TOP
  49.     float scale = -1.0;
  50.     #else
  51.     float scale = 1.0;
  52.     #endif
  53.     o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
  54.     o.uvgrab.zw = o.vertex.zw;
  55.     o.uvbump = TRANSFORM_TEX( v.uv, _BumpMap );
  56.     o.uvmain = TRANSFORM_TEX( v.uv, _MainTex );
  57.     o.fogFactor = ComputeFogFactor(o.vertex.z);
  58.     return o;
  59. }
  60. sampler2D _GrabBlurTexture;
  61. float4 _GrabBlurTexture_TexelSize;
  62. sampler2D _BumpMap;
  63. sampler2D _MainTex;
  64. half4 frag (v2f i) : SV_Target
  65. {
  66.     // calculate perturbed coordinates
  67.     // we could optimize this by just reading the x & y without reconstructing the Z
  68.     half2 bump = UnpackNormal(tex2D( _BumpMap, i.uvbump )).rg;
  69.     float2 offset = bump * _BumpAmt * _GrabBlurTexture_TexelSize.xy;
  70.     i.uvgrab.xy = offset * i.uvgrab.z + i.uvgrab.xy;
  71.    
  72.     half4 col = tex2Dproj (_GrabBlurTexture, i.uvgrab/i.uvgrab.w);
  73.     half4 tint = tex2D(_MainTex, i.uvmain);
  74.     col = lerp (col, tint, _TintAmt);
  75.     col.rgb = MixFog(col.rgb, i.fogFactor);
  76.     return col;
  77. }
复制代码
一个担任自Monobehaviour的脚本(CommandBufferBlurRefraction.cs),没有用到RendererFeature;
把 scene color 传输给 RT_screenCopyID;
  1. CommandBufferBlurRefraction.cs脚本:
  2. OnWillRenderObject():
  3. // copy screen into temporary RT
  4. int screenCopyID = Shader.PropertyToID(”_ScreenCopyTexture”);
  5. cmd.GetTemporaryRT (screenCopyID, -1, -1, 0, FilterMode.Bilinear);
  6. cmd.Blit (BuiltinRenderTextureType.CurrentActive, screenCopyID);
  7. // 但我实在不能理解,即使我把上面的cmd.Blit替换为下面这句,毛玻璃效果也正常显示???
  8. // 但如果注释掉cmd.Blit,毛玻璃效果就会消掉,合着意思是只要有cmd.Blit,不管他source给了啥,都传 scene color 给 destination???
  9. cmd.Blit (Shader.PropertyToID(”_ttttttt”), screenCopyID);
复制代码
新建2张RT,长宽是全屏的一半,记为 RT_blurredID 和 RT_blurredID2;把 RT_screenCopyID 传输给 RT_blurredID;
  1. // get two smaller RTs
  2. int blurredID = Shader.PropertyToID(”_Temp1”);
  3. int blurredID2 = Shader.PropertyToID(”_Temp2”);
  4. cmd.GetTemporaryRT (blurredID, -2, -2, 0, FilterMode.Bilinear);
  5. cmd.GetTemporaryRT (blurredID2, -2, -2, 0, FilterMode.Bilinear);
  6. // downsample screen copy into smaller RT, release screen RT
  7. cmd.Blit (screenCopyID, blurredID);
复制代码

  • 开始倒腾:

    • 把 RT_blurredID 经SeparableGlassBlur.shader计算(偏移”2”在x标的目的加权平均)后传输给 RT_blurredID2;
    • 把 RT_blurredID2 经SeparableGlassBlur.shader计算(偏移”2”在y标的目的加权平均)后传输给 RT_blurredID;
    • 把 RT_blurredID 经SeparableGlassBlur.shader计算(偏移”4”在x标的目的加权平均)后传输给 RT_blurredID2;
    • 把 RT_blurredID2 经SeparableGlassBlur.shader计算(偏移”4”在y标的目的加权平均)后传输给 RT_blurredID;

把 RT_blurredID 传输给 ”_GrabBlurTexture”,传给用于衬着玻璃的shader(GlassWithoutGrab.shader)使用;
  1. cmd.SetGlobalTexture(”_GrabBlurTexture”, blurredID);
复制代码
1. 改用RendererFeature实现

把OnWillRenderObject这个函数里的CommandBuffer改用RendererFeature实现
下面,我们试着把它的脚本(CommandBufferBlurRefraction.cs)改为RendererFeature
参考: https://zhuanlan.zhihu.com/p/248903320
大体照搬上面链接里的脚本,就是记得把 RT_blurredID 传给 ”_GrabBlurTexture”


unity版本2021.3.8,URP版本v12.1.7
代码在[f01_v12_1_7]这个文件夹里:FrostedGlassRenderFeature.cs
  1. public class FrostedGlassRenderFeature : ScriptableRendererFeature{
  2.     //在RendererFeature类里写一个class Settings,并实例化它
  3.     [System.Serializable]
  4.     public class Settings{
  5.         public RenderPassEvent renderEvent = RenderPassEvent.AfterRenderingSkybox;
  6.         public Material blurMat;
  7.     }
  8.     public Settings settings = new Settings();
  9.     //----------------------------------------------------------------
  10.     public class FrostedGlassRenderPass : ScriptableRenderPass{......}
  11.     FrostedGlassRenderPass m_ScriptablePass;
  12.     //----------------------------------------------------------------
  13.     //在ScriptableRendererFeature的Create方式里实例化ScriptableRenderPass类
  14.     public override void Create(){
  15.         m_ScriptablePass = new FrostedGlassRenderPass(settings);
  16.     }
  17.     //----------------------------------------------------------------
  18.     //在AddRenderPasses方式里设置ScriptableRenderPass的source
  19.     public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){
  20.         var src = renderer.cameraColorTarget;
  21.         m_ScriptablePass.Setup(src);
  22.         //----------------------
  23.         renderer.EnqueuePass(m_ScriptablePass);
  24.     }
  25. }
  26. ------------------------------------------------------------------------------------------
  27. ......的部门:
  28. public class FrostedGlassRenderPass : ScriptableRenderPass{
  29.     CommandBuffer cmd;
  30.     string m_ProfilerTag;//cmd name
  31.     Material m_blurMat;
  32.     RenderTargetHandle blurredID01;
  33.     RenderTargetHandle blurredID02;
  34.     RenderTargetIdentifier source;
  35.     RenderTargetHandle m_tempColorTex;
  36.     //首先写这个ScriptableRenderPass的构造函数
  37.     public FrostedGlassRenderPass(FrostedGlassRenderFeature.Settings param){
  38.         m_ProfilerTag = ”FrostedGalss”;
  39.         this.renderPassEvent = param.renderEvent;
  40.         m_blurMat = param.blurMat;
  41.         blurredID01.Init(”_Blur01”);
  42.         blurredID02.Init(”_Blur02”);
  43.     }
  44.     //----------------------------------------------------------------
  45.     public void Setup(RenderTargetIdentifier src){
  46.         this.source = src;//传入renderer.cameraColorTarget
  47.     }
  48.     //----------------------------------------------------------------
  49.     //在Execute方式里执行CommandBuffer
  50.     public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){
  51.         if ((renderingData.cameraData.camera.cullingMask & 1<<LayerMask.NameToLayer(”UI”))>0) {
  52.             //Debug.Log(”camera的cullingMask包含UI层,返回”);//并设置Camera>CullingMask不包罗UI层
  53.             return;
  54.         }
  55.         CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag);
  56.         Vector2[] sizes = {
  57.             new Vector2(Screen.width, Screen.height),
  58.             new Vector2(Screen.width / 2, Screen.height / 2),
  59.             new Vector2(Screen.width / 4, Screen.height / 4),
  60.             new Vector2(Screen.width / 8, Screen.height / 8),
  61.         };
  62.         int numIterations = 3;
  63.         RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
  64.         opaqueDesc.depthBufferBits = 0;
  65.         // The precision of the render texture&#39;s depth buffer in bits (0, 16, 24 and 32 are supported).// 为什么加这句?
  66.         cmd.GetTemporaryRT(m_tempColorTex.id, opaqueDesc, FilterMode.Bilinear);
  67.         cmd.Blit(source, m_tempColorTex.Identifier());
  68.         for (int i = 0; i < numIterations; ++i){
  69.             cmd.GetTemporaryRT(blurredID01.id, opaqueDesc, FilterMode.Bilinear);
  70.             cmd.GetTemporaryRT(blurredID02.id, opaqueDesc, FilterMode.Bilinear);
  71.             cmd.Blit(m_tempColorTex.Identifier(), blurredID01.Identifier());
  72.             cmd.SetGlobalVector(”offsets”, new Vector4(2.0f / sizes[i].x, 0, 0, 0));
  73.             cmd.Blit(blurredID01.Identifier(), blurredID02.Identifier(), m_blurMat);
  74.             cmd.SetGlobalVector(”offsets”, new Vector4(0, 2.0f / sizes[i].y, 0, 0));
  75.             cmd.Blit(blurredID02.Identifier(), blurredID01.Identifier(), m_blurMat);
  76.             cmd.Blit(blurredID01.Identifier(), m_tempColorTex.Identifier());
  77.         }
  78.         //把最终的内容传给 ”_GrabBlurTexture”
  79.         cmd.SetGlobalTexture(”_GrabBlurTexture”, blurredID01.Identifier());
  80.         //-----------
  81.         context.ExecuteCommandBuffer(cmd);
  82.         CommandBufferPool.Release(cmd);
  83.     }
  84.     //----------------------------------------------------------------
  85.     // 释放临时资源
  86.     public override void FrameCleanup(CommandBuffer cmd){
  87.         cmd.ReleaseTemporaryRT(m_tempColorTex.id);
  88.         cmd.ReleaseTemporaryRT(blurredID01.id);
  89.         cmd.ReleaseTemporaryRT(blurredID02.id);
  90.     }
  91. }
复制代码
附:一个可以开关RendererFeature的脚本,来自<link>
错误谬误
①是用cmd.Blit实现的传输,不撑持Single-Pass Instanced VR 且URP不建议使用这个过时的API;
②没有使用RTHandle,v13.1.9之后的URP版本需要使用 RTHandle 替代 RenderTargetIdentifier、RenderTargetHandle
③玻璃后的半透明物体不成见;
④玻璃前的opaque物体也会被衬着到玻璃上,但是不太明显(大部门被玻璃前的opaque物体自身盖住了,只是边缘有点颜色溢出)
下面升级unity版本,可以撑持Single-Pass Instanced VR;
那如果不想升级版本的话,怎么撑持Single-Pass Instanced VR?
呃……我试了一个下午……好吧我不会……
URP v13.1.9之后才有【RenderingUtils.ReAllocateIfNeeded()】方式——用不了RTHandle的话,就用RenderTargetIdentifier;用不了Blitter封装好的方式,那就搬它的源码;可单是源码的话还不够啊,不知道差了什么设置才能撑持Single-Pass Instanced VR;而且不知道为什么在URP版本v12.1.7里,每用1次Blitter源码,画面就会变亮一个等级,为什么会变亮啊……
2. 迁移至URP v14.0.6

迁移至unity版本2022.2.7,URP版本v14.0.6
报错:You can only call cameraColorTarget inside the scope of a ScriptableRenderPass. Otherwise the pipeline camera target texture might have not been created or might have already been disposed.
解决方式1:参考<github/UniversalRenderingExamples/RenderPasses>在 RenderPass 的 OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)方式里获取cameraColorTarget
解决方式2:参考<Perform a full screen blit in URP(V14.0.6)>或者参考< Upgrading to version 2022.1 of URP > 在 RenderFeature 里重写SetupRenderPasses()方式,在SetupRenderPasses()方式里你可以访谒renderer.cameraColorTargetHandle
3.升级至 RTHandle & Blitter

为什么要升级?——URP官网说了:cmd.Blit是已过时的API,且不撑持 Single-Pass Instanced VR;在URP项目中,请避免使用CommandBuffer.Blit及其它依赖于它的API(比如RenderingUtils.Blit);详见:URP Blit 入门(这篇笔记还没发)
◆ 用 Blitter 替换cmd.Blit,是否就可以撑持 Single-Pass Instanced VR?是的!shader也要记得升级,见下一章节
◆ 用 RTHandle 替代 RenderTargetHandle(这个obsolete了必定要被替换的)、RenderTargetIdentifier(这个还是可以用的那要替换吗)——在试图用 Blitter 替换 cmd.Blit 的过程中,我找到的解决方式是“不要用RenderTargetIdentifier,全用RTHandle”
◆ 参与了Blit过程的材质球(shader)也需要改削:增加[_BlitTexture]变量用于绑定Blitter函数的 input texture;
详细的踩坑记录见:URP Blit 入门 -03 Class Blitter(这篇笔记还没发)
代码在[f02_v14_0_6]这个文件夹里:FrostedGlassRenderFeature.cs
(下面这个就是本篇笔记的真心实意了 真是踩了好多坑啊)
  1. public class FrostedGlassRenderFeature : ScriptableRendererFeature{
  2.     //在ScriptableRendererFeature类里写一个class Settings,并实例化它
  3.     [System.Serializable]
  4.     public class Settings{
  5.         public RenderPassEvent renderEvent = RenderPassEvent.BeforeRenderingTransparents;
  6.         public Material blurMat;
  7.     }
  8.     public Settings settings = new Settings();
  9.     //----------------------------------------------------------------
  10.     public class FrostedGlassRenderPass : ScriptableRenderPass{......}
  11.     //----------------------------------------------------------------
  12.     FrostedGlassRenderPass m_ScriptablePass;
  13.     public override void Create(){  //在Create方式里实例化ScriptableRenderPass类
  14.         m_ScriptablePass = new FrostedGlassRenderPass(settings);//实例化包含了renderPassEvent的设置
  15.     }
  16.     public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){
  17.         //m_ScriptablePass.Setup(renderer.cameraColorTargetHandle);
  18.         //上面这行放在AddRenderPasses()方式里会报错:
  19.         //可以放到RenderPass的OnCameraSetup()里;也可以放到RendererFeature的SetupRenderPasses()里;
  20.         m_ScriptablePass.ConfigureInput(ScriptableRenderPassInput.Color);
  21.         if (renderingData.cameraData.cameraType == CameraType.Game){
  22.             renderer.EnqueuePass(m_ScriptablePass);
  23.         }
  24.     }
  25. }
  26. ------------------------------------------------------------------------------------------
  27. ......
  28. public class FrostedGlassRenderPass : ScriptableRenderPass{
  29.     CommandBuffer cmd;
  30.     string m_ProfilerTag;//cmd name
  31.     Material m_blurMat;
  32.     RTHandle source;
  33.     RTHandle rth_tempTex;
  34.     RTHandle rth_Blur01;
  35.     RTHandle rth_Blur02;
  36.     //首先写这个ScriptableRenderPass的构造函数
  37.     public FrostedGlassRenderPass(FrostedGlassRenderFeature.Settings param){
  38.         m_ProfilerTag = ”FrostedGalss”;
  39.         this.renderPassEvent = param.renderEvent;
  40.         m_blurMat = param.blurMat;
  41.     }
  42.     //----------------------------------------------------------------
  43.     // This method is called before executing the render pass.
  44.     // It can be used to configure render targets and their clear state. Also to create temporary render target textures.
  45.     // When empty this render pass will render to the active camera render target.
  46.     public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) {
  47.         var renderer = renderingData.cameraData.renderer;
  48.         this.source = renderer.cameraColorTargetHandle;
  49.         RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
  50.         opaqueDesc.depthBufferBits = 0; //为什么加这句?// Color and depth cannot be combined in RTHandles
  51.         /*下面这个错误的……就当是记录下黑历史……
  52.         // int id_tempTex = Shader.PropertyToID(”_TempTex”);
  53.         // cmd.GetTemporaryRT(id_tempTex, opaqueDesc, FilterMode.Bilinear);
  54.         // rti_tempTex = new RenderTargetIdentifier(id_tempTex);
  55.         // rth_tempTex = RTHandles.Alloc(rti_tempTex);
  56.         */
  57.         RenderingUtils.ReAllocateIfNeeded(ref rth_tempTex, opaqueDesc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: ”_TempTex”);
  58.         RenderingUtils.ReAllocateIfNeeded(ref rth_Blur01, opaqueDesc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: ”_Blur01”);
  59.         RenderingUtils.ReAllocateIfNeeded(ref rth_Blur02, opaqueDesc, FilterMode.Bilinear, TextureWrapMode.Clamp, name: ”_Blur02”);
  60.         // rth_tempTex = RTHandles.Alloc(in opaqueDesc,FilterMode.Bilinear,TextureWrapMode.Clamp,name: ”_TempTex”);
  61.         // 上面这个也可以正确运行,但是记得要在OnCameraCleanup()里执行Release
  62.     }
  63.     //----------------------------------------------------------------
  64.     // Here you can implement the rendering logic. 在Execute方式里执行CommandBuffer
  65.     public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){
  66.         CommandBuffer cmd = CommandBufferPool.Get();
  67.         using(new ProfilingScope(cmd, new ProfilingSampler(m_ProfilerTag))){
  68.             Vector2[] sizes = {
  69.                 new Vector2(Screen.width, Screen.height),
  70.                 new Vector2(Screen.width / 2, Screen.height / 2),
  71.                 new Vector2(Screen.width / 4, Screen.height / 4),
  72.                 new Vector2(Screen.width / 8, Screen.height / 8),
  73.             };
  74.             int numIterations = 2;//3
  75.             Blitter.BlitCameraTexture(cmd,source,rth_tempTex);//表格里的类型|C|
  76.             for (int i = 0; i < numIterations; ++i){
  77.                 Blitter.BlitCameraTexture(cmd,rth_tempTex,rth_Blur01);//表格里的类型|C|
  78.                 cmd.SetGlobalVector(”_Offset”, new Vector4(2.0f / sizes[i].x, 0, 0, 0));
  79.                 Blitter.BlitCameraTexture(cmd, rth_Blur01, rth_Blur02, m_blurMat, 0);//表格里的类型|A|
  80.                 cmd.SetGlobalVector(”_Offset”, new Vector4(0, 2.0f / sizes[i].y, 0, 0));
  81.                 Blitter.BlitCameraTexture(cmd, rth_Blur02, rth_Blur01, m_blurMat, 0);//表格里的类型|A|
  82.                 Blitter.BlitCameraTexture(cmd, rth_Blur01, rth_tempTex);//表格里的类型|C|
  83.             }
  84.             //把最终内容Blit到一个RenderTexture上。
  85.             cmd.SetGlobalTexture(”_GrabBlurTexture”, (RenderTargetIdentifier)rth_Blur01);
  86.         }
  87.         //---------------------------------------------
  88.         context.ExecuteCommandBuffer(cmd);// Use ScriptableRenderContext to issue drawing commands or execute command buffers
  89.         cmd.Clear();
  90.         CommandBufferPool.Release(cmd);
  91.     }
  92.     //----------------------------------------------------------------
  93.     // Cleanup any allocated resources that were created during the execution of this render pass.
  94.     public override void OnCameraCleanup(CommandBuffer cmd){}
  95.     public override void FrameCleanup(CommandBuffer cmd){}
  96.     public void Dispose(){
  97.         rth_tempTex?.Release();
  98.         rth_Blur01?.Release();
  99.         rth_Blur02?.Release();
  100.     }
  101. }
复制代码
Shader改削:用于做Blur计算的shader(”Hidden/SeparableGlassBlur”)
使用[_BlitTexture]接受Blitter函数输入的source,不需要手动定义[_BlitTexture],可直接 include Blit.hlsl;
  1. #include ”Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl”
复制代码
Blit.hlsl可以提供 vertex shader (Vert), input structure (Attributes) and output strucutre (Varyings)
(不贴shader了,直接放下一章节里)
4.如何撑持 Single-Pass Instanced VR?

文档: https://docs.unity3d.com/2022.2/Documentation/Manual/SinglePassInstancing.html
我们已经用 Blitter 替换全部的cmd.Blit了,此刻只需要让shader撑持Single-Pass Instanced VR就大功告成啦
用于做Blur计算的shader:
  1. Shader ”Hidden/SeparableGlassBlur_v2” {
  2.     // Properties {}
  3.     Subshader {
  4.         Tags { ”RenderType”=”Opaque” ”RenderPipeline”=”UniversalPipeline” }
  5.         Pass {
  6.             Name ”SeparableGlassBlur”
  7.             ZTest Always
  8.             Cull Off
  9.             ZWrite Off
  10.             HLSLPROGRAM
  11.             #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
  12.             // Blit.hlsl 提供 vertex shader (Vert), input structure (Attributes) and output strucutre (Varyings)
  13.             #include ”Packages/com.unity.render-pipelines.core/Runtime/Utilities/Blit.hlsl”
  14.             #pragma vertex myVert
  15.             #pragma fragment myFrag
  16.             // 由Blit.hlsl来定义Attributes
  17.             // struct Attributes {
  18.             //  float4 posOS : POSITION;
  19.             //  half2 uv : TEXCOORD0;
  20.             //  UNITY_VERTEX_INPUT_INSTANCE_ID //Insert to support Single-Pass Instanced VR
  21.             // };
  22.             struct v2f {
  23.                 float4 posCS : SV_POSITION;//POSITION;
  24.                 float2 uv : TEXCOORD0;
  25.                 float4 uv01 : TEXCOORD1;
  26.                 float4 uv23 : TEXCOORD2;
  27.                 float4 uv45 : TEXCOORD3;
  28.                 UNITY_VERTEX_OUTPUT_STEREO //Insert to support Single-Pass Instanced VR
  29.             };
  30.             float4 _Offset;
  31.             v2f myVert (Attributes input) {
  32.                 v2f o;
  33.                 UNITY_SETUP_INSTANCE_ID(input);//Insert to support Single-Pass Instanced VR
  34.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);//Insert to support Single-Pass Instanced VR
  35.                 #if SHADER_API_GLES //拷贝自Blit.hlsl
  36.                     float4 pos = input.positionOS;
  37.                     float2 uv  = input.uv;
  38.                 #else
  39.                     float4 pos = GetFullScreenTriangleVertexPosition(input.vertexID);
  40.                     float2 uv  = GetFullScreenTriangleTexCoord(input.vertexID);
  41.                 #endif
  42.                 o.posCS = pos;
  43.                 o.uv = uv * _BlitScaleBias.xy + _BlitScaleBias.zw;
  44.                 o.uv01 =  o.uv.xyxy + _Offset.xyxy * float4(1,1, -1,-1);
  45.                 o.uv23 =  o.uv.xyxy + _Offset.xyxy * float4(1,1, -1,-1) * 2.0;
  46.                 o.uv45 =  o.uv.xyxy + _Offset.xyxy * float4(1,1, -1,-1) * 3.0;
  47.                 return o;
  48.             }
  49.             half4 myFrag (v2f i) : SV_Target {//COLOR
  50.                 UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);//Insert to support Single-Pass Instanced VR
  51.                 half4 color = float4 (0,0,0,0);
  52.                 color += 0.40 * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, i.uv);
  53.                 color += 0.15 * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, i.uv01.xy);
  54.                 color += 0.15 * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, i.uv01.zw);
  55.                 color += 0.10 * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, i.uv23.xy);
  56.                 color += 0.10 * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, i.uv23.zw);
  57.                 color += 0.05 * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, i.uv45.xy);
  58.                 color += 0.05 * SAMPLE_TEXTURE2D_X(_BlitTexture, sampler_PointClamp, i.uv45.zw);
  59.                 return color;
  60.             }
  61.             ENDHLSL
  62.         }
  63.     }
  64. }
复制代码
用于衬着玻璃的shader:
  1. Shader ”FX/Glass/Stained BumpDistort (no grab) v2” {
  2.     Properties {
  3.         _BumpAmt  (”Distortion”, Range (0,256)) = 125
  4.         _TintAmt (”Tint Amount”, Range(0,1)) = 0.1
  5.         _MainTex (”Tint Color (RGB)”, 2D) = ”white” {}
  6.         _BumpMap (”Normalmap”, 2D) = ”bump” {}
  7.     }
  8.     SubShader{
  9.         Tags {  ”RenderPipeline”=”UniversalPipeline” ”Queue”=”Transparent” ”RenderType”=”Opaque” }
  10.         Pass {
  11.             Name ”BASE”
  12.             Tags { ”LightMode”=”UniversalForward” }
  13.             HLSLPROGRAM
  14.             #pragma vertex vert
  15.             #pragma fragment frag
  16.             #pragma multi_compile_fog
  17.             #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
  18.             struct appdata_t {
  19.                 float4 vertex : POSITION;
  20.                 float2 texcoord: TEXCOORD0;
  21.                 UNITY_VERTEX_INPUT_INSTANCE_ID //Insert to support Single-Pass Instanced VR
  22.             };
  23.             struct v2f {
  24.                 float4 vertex : POSITION;
  25.                 float4 uvgrab : TEXCOORD0;
  26.                 float2 uvbump : TEXCOORD1;
  27.                 float2 uvmain : TEXCOORD2;
  28.                 float fogFactor : TEXCOORD3;
  29.                 UNITY_VERTEX_OUTPUT_STEREO //Insert to support Single-Pass Instanced VR
  30.             };
  31.             float _BumpAmt;
  32.             half _TintAmt;
  33.             float4 _BumpMap_ST;
  34.             float4 _MainTex_ST;
  35.             v2f vert (appdata_t v){
  36.                 v2f o;
  37.                 UNITY_SETUP_INSTANCE_ID(v); //Insert to support Single-Pass Instanced VR
  38.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert to support Single-Pass Instanced VR
  39.                 o.vertex = TransformObjectToHClip(v.vertex);
  40.                 #if UNITY_UV_STARTS_AT_TOP
  41.                     float scale = -1.0;
  42.                 #else
  43.                     float scale = 1.0;
  44.                 #endif
  45.                 o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;
  46.                 o.uvgrab.zw = o.vertex.zw;
  47.                 o.uvbump = TRANSFORM_TEX( v.texcoord, _BumpMap );
  48.                 o.uvmain = TRANSFORM_TEX( v.texcoord, _MainTex );
  49.                 o.fogFactor = ComputeFogFactor(o.vertex.z);
  50.                 return o;
  51.             }
  52.             sampler2D _BumpMap;
  53.             sampler2D _MainTex;
  54.             float4 _GrabBlurTexture_TexelSize;
  55.             TEXTURE2D_X(_GrabBlurTexture);// sampler2D _GrabBlurTexture; //Insert to support Single-Pass Instanced VR
  56.             SAMPLER(sampler_GrabBlurTexture);//Insert to support Single-Pass Instanced VR
  57.             half4 frag (v2f i) : SV_Target{
  58.                 UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i);//Insert to support Single-Pass Instanced VR
  59.                 // calculate perturbed coordinates
  60.                 // we could optimize this by just reading the x & y without reconstructing the Z
  61.                 half2 bump = UnpackNormal(tex2D( _BumpMap, i.uvbump )).rg;
  62.                 float2 offset = bump * _BumpAmt * _GrabBlurTexture_TexelSize.xy;
  63.                 i.uvgrab.xy = offset * i.uvgrab.z + i.uvgrab.xy;
  64.                 // half4 col = tex2Dproj (_GrabBlurTexture, i.uvgrab/i.uvgrab.w);
  65.                 half4 col = SAMPLE_TEXTURE2D_X (_GrabBlurTexture, sampler_GrabBlurTexture, i.uvgrab.xy/i.uvgrab.w);
  66.                 half4 tint = tex2D(_MainTex, i.uvmain);
  67.                 col = lerp (col, tint, _TintAmt);
  68.                 col.rgb = MixFog(col.rgb, i.fogFactor);
  69.                 return col;
  70.             }
  71.             ENDHLSL
  72.         }
  73.     }
  74. }
复制代码

完~✿
阿谁……“③玻璃后的半透明物体不成见”啊啊啊啊不想再折腾啦,下次再研究!
5. 完善的毛玻璃效果

Lit+Refraction+Frosted

  • Lit:偷懒,用ShaderGraph实现了
  • Refraction:折射是玻璃效果的本质啊!教程参考 Screen Space Refraction for Glass and Water using Shader Graph 来自 < https://www.youtube.com/watch?v=VMsOPUUj0JA>
  • Frosted:在 shader graph 里 SceneColor节点 是可以撑持single-pass instanced VR的,但如果使用我们自定义的 GrabBlurTexture 就不能撑持single-pass instanced VR了;……才发现我对single-pass instanced VR这个技术其实一点没搞懂
我的解决方式是用 Custom Function 节点,新建一个 hlsl 文件:
  1. //UNITY_SHADER_NO_UPGRADE
  2. #ifndef MYHLSLINCLUDE_INCLUDED
  3. #define MYHLSLINCLUDE_INCLUDED
  4. TEXTURE2D_X(_GrabBlurTexture);// sampler2D _GrabBlurTexture; //Insert to support Single-Pass Instanced VR
  5. SAMPLER(sampler_GrabBlurTexture);//Insert to support Single-Pass Instanced VR
  6. float4 _GrabBlurTexture_TexelSize;
  7. void SampleTextureX_float(float2 uv, out half4 col){
  8.     col = SAMPLE_TEXTURE2D_X(_GrabBlurTexture, sampler_GrabBlurTexture, uv);
  9. }
  10. #endif //MYHLSLINCLUDE_INCLUDED
复制代码
唉……


https://www.zhihu.com/video/1670856985879900160

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-10-18 13:42 , Processed in 0.101916 second(s), 28 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表