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

《Unity Shader 入门精要》从Bulit-in 到URP (HLSL)Chapter13.3-基于深度纹理的雾效(屏幕后措置)

[复制链接]
发表于 2024-7-15 18:17 | 显示全部楼层 |阅读模式
前言:
已经进入“高级篇”啦,但愿大师多多撑持,多多存眷,这将对我发生非常愉悦的正反馈~

“《Unity Shader 入门精要》从Bulit-in 到URP”是一个辅佐Unity Shader学习者以冯乐乐女神《Unity Shader 入门精要》为基础学习用HLSL语言编写URP着色器的案例教学系列。

作者自学能力有限,抛砖引玉,如有建议和问题请各位大佬和同仁交流斧正。
如安在URP中实现后措置参见:

Bulit-in版:
  1. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
  2. Shader ”Unity Shaders Book/Chapter 13/Fog With Depth Texture” {
  3.         Properties {
  4.                 _MainTex (”Base (RGB)”, 2D) = ”white” {}
  5.                 _FogDensity (”Fog Density”, Float) = 1.0
  6.                 _FogColor (”Fog Color”, Color) = (1, 1, 1, 1)
  7.                 _FogStart (”Fog Start”, Float) = 0.0
  8.                 _FogEnd (”Fog End”, Float) = 1.0
  9.         }
  10.         SubShader {
  11.                 CGINCLUDE
  12.                
  13.                 #include ”UnityCG.cginc”
  14.                
  15.                 float4x4 _FrustumCornersRay;
  16.                
  17.                 sampler2D _MainTex;
  18.                 half4 _MainTex_TexelSize;
  19.                 sampler2D _CameraDepthTexture;
  20.                 half _FogDensity;
  21.                 fixed4 _FogColor;
  22.                 float _FogStart;
  23.                 float _FogEnd;
  24.                
  25.                 struct v2f {
  26.                         float4 pos : SV_POSITION;
  27.                         half2 uv : TEXCOORD0;
  28.                         half2 uv_depth : TEXCOORD1;
  29.                         float4 interpolatedRay : TEXCOORD2;
  30.                 };
  31.                
  32.                 v2f vert(appdata_img v) {
  33.                         v2f o;
  34.                         o.pos = UnityObjectToClipPos(v.vertex);
  35.                        
  36.                         o.uv = v.texcoord;
  37.                         o.uv_depth = v.texcoord;
  38.                        
  39.                         #if UNITY_UV_STARTS_AT_TOP
  40.                         if (_MainTex_TexelSize.y < 0)
  41.                                 o.uv_depth.y = 1 - o.uv_depth.y;
  42.                         #endif
  43.                        
  44.                         int index = 0;
  45.                         if (v.texcoord.x < 0.5 && v.texcoord.y < 0.5) {
  46.                                 index = 0;
  47.                         } else if (v.texcoord.x > 0.5 && v.texcoord.y < 0.5) {
  48.                                 index = 1;
  49.                         } else if (v.texcoord.x > 0.5 && v.texcoord.y > 0.5) {
  50.                                 index = 2;
  51.                         } else {
  52.                                 index = 3;
  53.                         }
  54.                         #if UNITY_UV_STARTS_AT_TOP
  55.                         if (_MainTex_TexelSize.y < 0)
  56.                                 index = 3 - index;
  57.                         #endif
  58.                        
  59.                         o.interpolatedRay = _FrustumCornersRay[index];
  60.                                           
  61.                         return o;
  62.                 }
  63.                
  64.                 fixed4 frag(v2f i) : SV_Target {
  65.                         float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv_depth));
  66.                         float3 worldPos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz;
  67.                                                
  68.                         float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart);
  69.                         fogDensity = saturate(fogDensity * _FogDensity);
  70.                        
  71.                         fixed4 finalColor = tex2D(_MainTex, i.uv);
  72.                         finalColor.rgb = lerp(finalColor.rgb, _FogColor.rgb, fogDensity);
  73.                        
  74.                         return finalColor;
  75.                 }
  76.                
  77.                 ENDCG
  78.                
  79.                 Pass {
  80.                         ZTest Always Cull Off ZWrite Off
  81.                                     
  82.                         CGPROGRAM  
  83.                        
  84.                         #pragma vertex vert  
  85.                         #pragma fragment frag  
  86.                           
  87.                         ENDCG  
  88.                 }
  89.         }
  90.         FallBack Off
  91. }
复制代码
URP版:

Unity项目源码:
  1. Shader ”Unlit/Chapter13-FogWithDepthTexture”
  2. {
  3.     Properties {
  4.                 _MainTex (”Base (RGB)”, 2D) = ”white” {}
  5.                 _FogDensity (”Fog Density”, Float) = 1.0
  6.                 _FogColor (”Fog Color”, Color) = (1, 1, 1, 1)
  7.                 _FogStart (”Fog Start”, Float) = 0.0
  8.                 _FogEnd (”Fog End”, Float) = 1.0
  9.         }
  10.     SubShader
  11.     {
  12.         Tags { ”RenderPipeline” = ”UniversalPipeline” }
  13.         
  14.         HLSLINCLUDE
  15.         #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl”
  16.                 #include ”Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl”
  17.         CBUFFER_START(UnityPerMaterial)
  18.             float4x4 _FrustumCornersRay;
  19.                
  20.             half4 _MainTex_TexelSize;
  21.             half _FogDensity;
  22.             half4 _FogColor;
  23.             float _FogStart;
  24.             float _FogEnd;
  25.         CBUFFER_END
  26.         TEXTURE2D(_MainTex);       SAMPLER(sampler_MainTex);
  27.         TEXTURE2D(_CameraDepthTexture);       SAMPLER(sampler_CameraDepthTexture);
  28.         //如果在URP Asset设置下勾选 depth texture选项系统会自动生成一张以_CameraDepthTexture为名的深度图,抽时间会写一篇相关文章并把链接补充到本篇中。
  29.         struct appdata{
  30.             float4 vertex : POSITION;
  31.             float2 texcoord : TEXCOORD0;
  32.         };
  33.         struct v2f {
  34.                         float4 pos : SV_POSITION;
  35.                         half2 uv : TEXCOORD0;
  36.                         half2 uv_depth : TEXCOORD1;
  37.                         float4 interpolatedRay : TEXCOORD2;
  38.         };
  39.         v2f vert(appdata v) {
  40.                         v2f o;
  41.                        
  42.                         o.pos = TransformObjectToHClip(v.vertex);
  43.                        
  44.                         o.uv = v.texcoord;
  45.             o.uv_depth = v.texcoord;
  46.             #if UNITY_UV_STARTS_AT_TOP
  47.                         if (_MainTex_TexelSize.y < 0)
  48.                                 o.uv_depth.y = 1 - o.uv_depth.y;
  49.                         #endif
  50.             int index = 0;
  51.                         if (v.texcoord.x < 0.5 && v.texcoord.y < 0.5) {
  52.                                 index = 0;
  53.                         } else if (v.texcoord.x > 0.5 && v.texcoord.y < 0.5) {
  54.                                 index = 1;
  55.                         } else if (v.texcoord.x > 0.5 && v.texcoord.y > 0.5) {
  56.                                 index = 2;
  57.                         } else {
  58.                                 index = 3;
  59.                         }
  60.                         #if UNITY_UV_STARTS_AT_TOP
  61.                         if (_MainTex_TexelSize.y < 0)
  62.                                 index = 3 - index;
  63.                         #endif
  64.                        
  65.                         o.interpolatedRay = _FrustumCornersRay[index];
  66.             //尽管我们这里使用了很多判断语句,但由于屏幕后措置所用的模型是一个四边形网格,只包含4个顶点,因此这些操作不会对性能造成很大影响。
  67.                                          
  68.                         return o;
  69.                 }
  70.         half4 frag(v2f i) : SV_Target {
  71.                         float linearDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture,i.uv_depth), _ZBufferParams);
  72.             //使用LinearEyeDepth得到视角空间下的线性深度值
  73.                         float3 worldPos = _WorldSpaceCameraPos + linearDepth * i.interpolatedRay.xyz;
  74.                                                
  75.                         float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart);
  76.                         fogDensity = saturate(fogDensity * _FogDensity);
  77.                        
  78.                         half4 finalColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
  79.                         finalColor.rgb = lerp(finalColor.rgb, _FogColor.rgb, fogDensity);
  80.                        
  81.                         return finalColor;
  82.                 }
  83.                
  84.                 ENDHLSL
  85.                
  86.                 Pass {
  87.                         ZTest Always Cull Off ZWrite Off
  88.                                     
  89.                         HLSLPROGRAM  
  90.                        
  91.                         #pragma vertex vert  
  92.                         #pragma fragment frag  
  93.                           
  94.                         ENDHLSL  
  95.                 }
  96.         }
  97.         FallBack ”Packages/com.unity.render-pipelines.universal/FallbackError”
  98. }
复制代码
URP后措置脚本

因为和上面提供的(Post-processing : RenderFeature + VolumeComponent)模板有些许差异,因此在此提供对应源码。
  1. using System;
  2. using UnityEngine;
  3. using UnityEngine.Rendering;
  4. using UnityEngine.Rendering.Universal;
  5. public class FogWithDepthTexture : ScriptableRendererFeature
  6. {
  7.     [Serializable, VolumeComponentMenu(”Ding Post-processing/13.3 FogWithDepthTexture”)]
  8.     public class CustomVolumeComponent : DingVolumeComponentBase
  9.     {
  10.         public ClampedFloatParameter FogDensity = new ClampedFloatParameter(1.0f, 0, 3.0f);
  11.         public MinFloatParameter FogStart = new MinFloatParameter(0f, 0f);
  12.         public MinFloatParameter FogEnd = new MinFloatParameter(2.0f, 0f);
  13.         public ColorParameter FogColor = new ColorParameter(Color.white, false, false, true);
  14.    
  15.         public override bool IsActive() => isRender.value;
  16.         public override bool IsTileCompatible() => false;
  17.     }
  18.     class CustomRenderPass : ScriptableRenderPass
  19.     {
  20.         
  21.         public Material material;
  22.         private Matrix4x4 frustumCorners;
  23.         //RT的滤波模式
  24.         public FilterMode filterMode {get; set;}
  25.         //当前衬着阶段的colorRT
  26.         //RenderTargetIdentifier、RenderTargetHandle都可以理解为RT,Identifier为camera提供的需要被应用的texture,Handle为被shader措置衬着过的RT
  27.         private RenderTargetIdentifier source {get; set;}
  28.         //private RenderTargetHandle destination {get; set;}
  29.         //辅助RT
  30.         private RenderTargetHandle tempTexture;
  31.         string m_ProfilerTag;
  32.         //Profiling上显示
  33.         public CustomVolumeComponent volume;
  34.         ProfilingSampler m_ProfilingSampler = new ProfilingSampler(”URPDing”);
  35.         public CustomRenderPass(RenderPassEvent renderPassEvent, Shader shader, CustomVolumeComponent volume, string tag){
  36.             //确定在哪个阶段插入衬着
  37.             this.renderPassEvent = renderPassEvent;
  38.             this.volume = volume;
  39.             if(shader == null){return;}
  40.             this.material = CoreUtils.CreateEngineMaterial(shader);
  41.             m_ProfilerTag = tag;
  42.             //初始化辅助RT的名字
  43.             tempTexture.Init(”_TempRTexture”);
  44.         }
  45.         public void Setup(RenderTargetIdentifier source){
  46.             this.source = source;
  47.             //this.destination = destination;
  48.         }
  49.         
  50.         
  51.         public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
  52.         {
  53.             if (!volume.IsActive()) {
  54.                 return;
  55.             }
  56.             CommandBuffer cmd = CommandBufferPool.Get(”m_ProfilerTag”);
  57.             //using 方式可以实此刻FrameDebug上查看衬着过程
  58.             using(new ProfilingScope(cmd, m_ProfilingSampler)){
  59.                 Camera camera = renderingData.cameraData.camera;
  60.                 //获取摄像机
  61.                 Transform cameraTransform = camera.transform;
  62.                 float fov = camera.fieldOfView;
  63.                 float near = camera.nearClipPlane;
  64.                 float far = camera.farClipPlane;
  65.                 float aspect = camera.aspect;
  66.                 float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
  67.                 Vector3 toRight = cameraTransform.right * halfHeight * aspect;
  68.                 Vector3 toTop = cameraTransform.up * halfHeight;
  69.                 Vector3 topLeft = cameraTransform.forward * near + toTop - toRight;
  70.                 float scale = topLeft.magnitude / near;
  71.                 topLeft.Normalize();
  72.                 topLeft *= scale;
  73.                 Vector3 topRight = cameraTransform.forward * near + toRight + toTop;
  74.                 topRight.Normalize();
  75.                 topRight *= scale;
  76.                 Vector3 bottomLeft = cameraTransform.forward * near - toTop - toRight;
  77.                 bottomLeft.Normalize();
  78.                 bottomLeft *= scale;
  79.                 Vector3 bottomRight = cameraTransform.forward * near + toRight - toTop;
  80.                 bottomRight.Normalize();
  81.                 bottomRight *= scale;
  82.                 frustumCorners.SetRow(0, bottomLeft);
  83.                 frustumCorners.SetRow(1, bottomRight);
  84.                 frustumCorners.SetRow(2, topRight);
  85.                 frustumCorners.SetRow(3, topLeft);
  86.                 material.SetMatrix(”_FrustumCornersRay”, frustumCorners);
  87.                 material.SetMatrix(”_ViewProjectionInverseMatrix”, (camera.projectionMatrix * camera.worldToCameraMatrix).inverse);
  88.                 material.SetFloat(”_FogDensity”, volume.FogDensity.value);
  89.                 material.SetFloat(”_FogStart”, volume.FogStart.value);
  90.                 material.SetFloat(”_FogEnd”, volume.FogEnd.value);
  91.                 material.SetColor(”_FogColor”, volume.FogColor.value);
  92.                 //创建一张RT
  93.                 RenderTextureDescriptor cameraTextureDesc = renderingData.cameraData.cameraTargetDescriptor;
  94.                 cameraTextureDesc.depthBufferBits = 0;
  95.                 cameraTextureDesc.msaaSamples = 1;
  96.                 //打消抗锯齿措置,抗锯齿会影响unity自动在DX与OpenGL间的坐标转换
  97.                 cmd.GetTemporaryRT(tempTexture.id, cameraTextureDesc, filterMode);
  98.                
  99.                 //将当前帧的colorRT用着色器(shader in material)衬着后输出到之前创建的贴图(辅助RT)上
  100.                 Blit(cmd, source, tempTexture.Identifier(), material, 0);
  101.                     //将措置后的辅助RT从头衬着到当前帧的colorRT上
  102.                 Blit(cmd, tempTexture.Identifier(), source);
  103.             }
  104.             //执行衬着
  105.             context.ExecuteCommandBuffer(cmd);
  106.             //释放回收
  107.             CommandBufferPool.Release(cmd);
  108.         }
  109.         public override void FrameCleanup(CommandBuffer cmd){
  110.             base.FrameCleanup(cmd);
  111.             cmd.ReleaseTemporaryRT(tempTexture.id);
  112.         }
  113.     }
  114.     [System.Serializable]
  115.     public class Settings{
  116.         public RenderPassEvent Event = RenderPassEvent.AfterRenderingTransparents;
  117.         public Shader shader;
  118.     }
  119.     public Settings settings = new Settings();
  120.     CustomVolumeComponent volume;
  121.     CustomRenderPass m_ScriptablePass;
  122.    
  123.     /// <inheritdoc/>
  124.     //feature被创建时调用
  125.     public override void Create()
  126.     {
  127.         var stack = VolumeManager.instance.stack;
  128.         volume = stack.GetComponent<CustomVolumeComponent>();
  129.         if (volume == null) {
  130.             CoreUtils.Destroy(m_ScriptablePass.material);
  131.             return;
  132.         }
  133.         m_ScriptablePass = new CustomRenderPass(settings.Event, settings.shader, volume, name);
  134.     }
  135.     //每一帧城市调用
  136.     public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
  137.     {
  138.         var src = renderer.cameraColorTarget;
  139.         //var dest = RenderTargetHandle.CameraTarget;
  140.         if(settings.shader == null){
  141.             Debug.LogWarningFormat(”shader丢掉”,GetType().Name);
  142.             return;
  143.         }
  144.         //将当前衬着的colorRT传到Pass中
  145.         m_ScriptablePass.Setup(src);
  146.         //将Pass添加到衬着队列中
  147.         renderer.EnqueuePass(m_ScriptablePass);
  148.     }
  149.     protected override void Dispose(bool disposing)
  150.     {
  151.         base.Dispose(disposing);
  152.    
  153.     }
  154. }
复制代码
效果图:

因为我在sense中使用的是图片,图片上没有深度分歧,所以无法在图片上不雅察看到深度分歧的雾效区别,图片以外区域可以感到感染到稍微明显的深度雾效。


如有收获,请留下“存眷”和“附和”~

本帖子中包含更多资源

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

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

本版积分规则

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

GMT+8, 2024-12-22 09:45 , Processed in 0.138931 second(s), 28 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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