Unity Shader-后处理:景深

Unity 景深Depth Of Field 景深效果Depth Of Field是摄影界的老常客了,在游戏中也非常多见,它能够大幅提升游戏画面体验和真实度,使得物体看起来更有细节。GTA5中的景深效果Unity 当然提供了景深支持:本文我将介绍最简单直接的实现方法,不需要任何复杂的物理学只是,直截了当的就能出效果。 阅读详情

一.简介


景深一直是我最喜欢的效果之一,最早接触CE3的时候,发现CE引擎默认就支持景深的效果,当时感觉这个效果特别酷炫,如今投身于Unity的怀抱中,准备用Unity实现以下传说中的景深效果。


所谓景深,是摄影的一个专业术语:在聚焦完成后,在焦点前后的范围内都能形成清晰的像,这一前一后的距离范围,便叫做景深,也是被摄物体能清晰成像的空间深度。在景深范围内景物影像的清晰度并不完全一致,其中焦点上的清晰度是最高的,其余的影像清晰度随着它与焦点的距离成正比例下降。先附上一张正常的照片和使用景深控制的照片:


通过左右两张照片的对比,我们很容易发现,通过景深处理的照片,我们可以很容易地抓住照片的重点部分。这也就是景深最大的用处,能够突出主题,并且可以使画面更有层次感。

在摄影技术中的景深,是通过调整相机的焦距,光圈来控制景深的,这里就不多说了。而我们的游戏中要想出现这种效果,就需要下一番功夫了。首先拆分一下图像的效果,图像中主要分为两部分,后面的模糊背景和前面清晰的“主题”部分。后面的背景模糊我们可以通过前面的两篇文章Unity Shader-后处理:高斯模糊,Unity Shader后处理-均值模糊来实现,而前景部分就是一张清晰的场景图,最后通过一定的权值将两者混合,离摄像机(准确地说是焦距)越远的部分,模糊图片的权重越高,离摄像机越近的部分,清晰图片的权重越高。那么问题来了,我们怎么知道哪个部分离摄像机更近呢?


二.Camera Depth Texture


上面说到,我们要怎么得到摄像机渲染的这个场景的图片中哪个部分离我们更远,哪个部分离我们更近?答案就是Camera Depth Texture这个东东。从字面上理解这个就是相机深度纹理。在Unity中,相机可以产生深度,深度+法线或者运动方向纹理,这是一个简化版本的G-Buffer纹理,我们可以用这个纹理进行一些后处理操作。这张纹理图记录了屏幕空间所有物体距离相机的距离。深度纹理中每个像素所记录的深度值是从0 到1 非线性分布的。精度通常是 24 位或16 位,这主要取决于所使用的深度缓冲区。当读取深度纹理时,我们可以得到一个0-1范围内的高精度值。如果你需要获取到达相机的距离或者其他线性关系的值,那么你需要手动计算它。

关于这张图是怎么样产生的,在Unity5之前是通过一个叫做Shader ReplaceMent的操作完成的。这个操作简单来说就是临时把场景中所有的shader换成我们想要的shader,然后渲染到张图上,我们通过Shader ReplaceMent操作,将场景中的对象shader换成按照深度写入一张纹理图。我们可以在5.X版本之前Unity自带的Shader中找到这个生成深度图的shader:Camera-DepthTexture.shader,这里我摘出一小段Tags中RenderType为Opaque的subshader:
  1. SubShader  
  2. {  
  3.     Tags { "RenderType"="Opaque" }  
  4.     Pass   
  5.     {  
  6.         CGPROGRAM  
  7.         #pragma vertex vert  
  8.         #pragma fragment frag  
  9.         #include "UnityCG.cginc"  
  10.         struct v2f  
  11.         {  
  12.             float4 pos : POSITION;  
  13.             #ifdef UNITY_MIGHT_NOT_HAVE_DEPTH_TEXTURE  
  14.             float2 depth : TEXCOORD0;  
  15.             #endif  
  16.         };  
  17.   
  18.         v2f vert( appdata_base v )  
  19.         {  
  20.             v2f o;  
  21.             o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  22.             UNITY_TRANSFER_DEPTH(o.depth);  
  23.             return o;  
  24.         }  
  25.   
  26.         fixed4 frag(v2f i) : COLOR {  
  27.             UNITY_OUTPUT_DEPTH(i.depth);  
  28.         }  
  29.   
  30.         ENDCG  
  31.     }  
  32. }  
我们看到,当物体的渲染Tag为Opaque也就是不透明的时候,会写入深度纹理。而这个文件中其他的几个subshader也分别对针对不同类型的type,比如RenderType为TransparentCutout的subshader,就增加了一句下面的判断,去掉了所有应该透明的地方:
  1. clip( texcol.a*_Color.a - _Cutoff );  
而且这个shader中没有出现RnderType为Transparent类型的,因为透明的物体不会写入我们的深度贴图,也就是说我们开启了alpha blend类型的对象是不会写入深度的。

上面的代码中有几个宏定义,我们可以从UnityCG.cginc文件中找到这几个宏定义的实现:
  1. // Depth render texture helpers  
  2. #if defined(UNITY_MIGHT_NOT_HAVE_DEPTH_TEXTURE)  
  3.     #define UNITY_TRANSFER_DEPTH(oo) oo = o.pos.zw  
  4.     #define UNITY_OUTPUT_DEPTH(i) return i.x/i.y  
  5. #else  
  6.     #define UNITY_TRANSFER_DEPTH(oo)   
  7.     #define UNITY_OUTPUT_DEPTH(i) return 0  
  8. #endif  
结合上面shader的使用,我们看出:UNITY_TRANSFER_DEPTH宏将传入vertex shader中的position的最后两位返回,也就是z坐标和w坐标,在unity里面也就是从屏幕向里看的那个方向就是z轴的方向。而UNITY_OUTPUT_DEPTH通过将z/w将真正的深度返回。UNITY_MIGHT_NOT_HAVE_DEPTH_TEXTURE是如果没有深度图的意思,也就是说,仅当没有获得深度图的时候,才会通过这个计算来计算深度,否则就无操作或者返回0。那么,这种情况下,深度信息从哪里来呢?我们看一下Unity的文档就知道了:

  • UNITY_TRANSFER_DEPTH(o): computes eye space depth of the vertex and outputs it in o (which must be a float2). Use it in a vertex program when rendering into a depth texture. On platforms with native depth textures this macro does nothing at all, because Z buffer value is rendered implicitly.
  • UNITY_OUTPUT_DEPTH(i): returns eye space depth from i (which must be a float2). Use it in a fragment program when rendering into a depth texture. On platforms with native depth textures this macro always returns zero, because Z buffer value is rendered implicitly.
也就是说,如果硬件支持硬件深度的话,也就是直接从z buffer取深度,那么这个宏就没有必要了,因为这样的话,z buffer的深度是隐式渲染的。
关于深度纹理,深度法线纹理,运动方向纹理 Unity官方文档有很好的介绍,我们就不多说了,下面我们看一下怎么在Unity中开启深度的渲染。通过Camera.DepthTextureMode这个变量我们就可以控制是否开启深度的渲染,默认这个值是None,我们可以将其设为None,Depth,DepthNormals三种类型。只要开启了Depth模式,我们就可以在shader中通过_CameraDepthTexture来获得屏幕深度的纹理了。 Unity官方文档中也有详细介绍。下面我们通过一个后处理来实现一个最简单的输出屏幕深度的效果:

C#脚本
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. [ExecuteInEditMode]  
  5. public class DepthTextureTest : PostEffectBase  
  6. {  
  7.     void OnEnable()  
  8.     {  
  9.         GetComponent<Camera>().depthTextureMode |= DepthTextureMode.Depth;  
  10.     }  
  11.   
  12.     void OnDisable()  
  13.     {  
  14.         GetComponent<Camera>().depthTextureMode &= ~DepthTextureMode.Depth;  
  15.     }  
  16.   
  17.     void OnRenderImage(RenderTexture source, RenderTexture destination)  
  18.     {  
  19.         if (_Material)  
  20.         {  
  21.             Graphics.Blit(source, destination, _Material);  
  22.         }  
  23.     }  
  24. }  
shader部分:
  1. Shader "Custom/DepthTest" {  
  2.   
  3.     CGINCLUDE  
  4.     #include "UnityCG.cginc"  
  5.   
  6.     //仍然要声明一下_CameraDepthTexture这个变量,虽然Unity这个变量是unity内部赋值  
  7.     sampler2D _CameraDepthTexture;  
  8.     sampler2D _MainTex;  
  9.     float4    _MainTex_TexelSize;  
  10.   
  11.     struct v2f  
  12.     {  
  13.         float4 pos : SV_POSITION;  
  14.         float2 uv  : TEXCOORD0;  
  15.     };  
  16.   
  17.     v2f vert(appdata_img v)  
  18.     {  
  19.         v2f o;  
  20.         o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  21.         o.uv.xy = v.texcoord.xy;  
  22.   
  23.         return o;  
  24.     }  
  25.   
  26.     fixed4 frag(v2f i) : SV_Target  
  27.     {  
  28.         //直接根据UV坐标取该点的深度值  
  29.         float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, 1 - i.uv);  
  30.         //将深度值变为线性01空间  
  31.         depth = Linear01Depth(depth);  
  32.         return float4(depth, depth, depth, 1);  
  33.     }  
  34.   
  35.     ENDCG  
  36.   
  37.     SubShader  
  38.     {  
  39.         Pass  
  40.         {  
  41.   
  42.             ZTest Off  
  43.             Cull Off  
  44.             ZWrite Off  
  45.             Fog{ Mode Off }  
  46.   
  47.             CGPROGRAM  
  48.             #pragma vertex vert  
  49.             #pragma fragment frag  
  50.             ENDCG  
  51.         }  
  52.   
  53.     }  
  54. }  

 找一个场景,将该脚本挂在摄像机并赋予材质。(注:PostEffectBase类为后处理基类,在 之前的文章中有详细实现,此处不予贴出),找到一个场景,我们测试一下:

原始场景效果:

开启输出深度后处理效果:

恩,场景图变成了一张黑白图像,越远的地方越亮,越近的地方越暗,也就是我们shader中所写的,直接按照深度值来输出了一幅图片。不过注意,这张图中,我把摄像机的远裁剪面调整到了50这一比较小的距离,这样,图中的远近信息显示得更加明显,而如果摄像机的远裁剪面距离很大,那么这张图的输出就会整体偏黑,因为离我们较近的物体距离占远裁剪面的距离太小了,几乎为0,所以就是黑的,如下图所示,当远裁剪面改为1000时深度图,仅有窗户的位置能看到白色:



关于CameraDepthTexture,在Unity4中CameraDepthTexture仍然是通过上面我们说的shader替换技术实现的,所以,一旦我们开启深度渲染,会导致DrawCall翻倍!而在Unity5中,这个CameraDepthTexture与Shadow Caster使用的是一套DepthTexture,通过带有Shadow Caster的对象才会被渲染到深度缓存中。关于Unity5和Unity4中深度缓存的渲染, 这篇文章介绍得很详细,可以进行参考。

三.景深效果实现


终于到了这篇文章的主题了,我们通过shader实现一个景深的效果。思路上面已经说过了,通过两张图片,一张清晰的,一张经过高斯模糊的,然后根据图片中每个像素的深度值在两张图片之间差值,就可以达到景深的效果了。下面附上景深效果代码:

shader部分:
  1. Shader "Custom/DepthOfField" {  
  2.   
  3.     Properties{  
  4.         _MainTex("Base (RGB)", 2D) = "white" {}  
  5.         _BlurTex("Blur", 2D) = "white"{}  
  6.     }  
  7.   
  8.     CGINCLUDE  
  9.     #include "UnityCG.cginc"  
  10.   
  11.     struct v2f_blur  
  12.     {  
  13.         float4 pos : SV_POSITION;  
  14.         float2 uv  : TEXCOORD0;  
  15.         float4 uv01 : TEXCOORD1;  
  16.         float4 uv23 : TEXCOORD2;  
  17.         float4 uv45 : TEXCOORD3;  
  18.     };  
  19.   
  20.     struct v2f_dof  
  21.     {  
  22.         float4 pos : SV_POSITION;  
  23.         float2 uv  : TEXCOORD0;  
  24.         float2 uv1 : TEXCOORD1;  
  25.     };  
  26.   
  27.     sampler2D _MainTex;  
  28.     float4 _MainTex_TexelSize;  
  29.     sampler2D _BlurTex;  
  30.     sampler2D_float _CameraDepthTexture;  
  31.     float4 _offsets;  
  32.     float _focalDistance;  
  33.     float _nearBlurScale;  
  34.     float _farBlurScale;  
  35.   
  36.     //高斯模糊 vert shader(上一篇文章有详细注释)  
  37.     v2f_blur vert_blur(appdata_img v)  
  38.     {  
  39.         v2f_blur o;  
  40.         _offsets *= _MainTex_TexelSize.xyxy;  
  41.         o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  42.         o.uv = v.texcoord.xy;  
  43.   
  44.         o.uv01 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1);  
  45.         o.uv23 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 2.0;  
  46.         o.uv45 = v.texcoord.xyxy + _offsets.xyxy * float4(1, 1, -1, -1) * 3.0;  
  47.   
  48.         return o;  
  49.     }  
  50.   
  51.     //高斯模糊 pixel shader(上一篇文章有详细注释)  
  52.     fixed4 frag_blur(v2f_blur i) : SV_Target  
  53.     {  
  54.         fixed4 color = fixed4(0,0,0,0);  
  55.         color += 0.40 * tex2D(_MainTex, i.uv);  
  56.         color += 0.15 * tex2D(_MainTex, i.uv01.xy);  
  57.         color += 0.15 * tex2D(_MainTex, i.uv01.zw);  
  58.         color += 0.10 * tex2D(_MainTex, i.uv23.xy);  
  59.         color += 0.10 * tex2D(_MainTex, i.uv23.zw);  
  60.         color += 0.05 * tex2D(_MainTex, i.uv45.xy);  
  61.         color += 0.05 * tex2D(_MainTex, i.uv45.zw);  
  62.         return color;  
  63.     }  
  64.   
  65.     //景深效果 vertex shader  
  66.     v2f_dof vert_dof(appdata_img v)  
  67.     {  
  68.         v2f_dof o;  
  69.         //mvp矩阵变换  
  70.         o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  71.         //uv坐标传递  
  72.         o.uv.xy = v.texcoord.xy;  
  73.         o.uv1.xy = o.uv.xy;  
  74.         //dx中纹理从左上角为初始坐标,需要反向  
  75.         #if UNITY_UV_STARTS_AT_TOP  
  76.         if (_MainTex_TexelSize.y < 0)  
  77.             o.uv.y = 1 - o.uv.y;  
  78.         #endif    
  79.         return o;  
  80.     }  
  81.   
  82.     fixed4 frag_dof(v2f_dof i) : SV_Target  
  83.     {  
  84.         //取原始清晰图片进行uv采样  
  85.         fixed4 ori = tex2D(_MainTex, i.uv1);  
  86.         //取模糊普片进行uv采样  
  87.         fixed4 blur = tex2D(_BlurTex, i.uv);  
  88.         //取当位置对应的深度值  
  89.         float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, i.uv);  
  90.         //将深度值转化到01线性空间  
  91.         depth = Linear01Depth(depth);  
  92.           
  93.         //如果depth小于焦点的物体,那么使用原始清晰图像,否则使用模糊的图像与清晰图像的差值,通过差值避免模糊和清晰之间明显的边界,结果为远景模糊效果  
  94.         fixed4 final = (depth <= _focalDistance) ? ori : lerp(ori, blur, clamp((depth - _focalDistance) * _farBlurScale, 0, 1));  
  95.         //上面的结果,再进行一次计算,如果depth大于焦点的物体,使用上面的结果和模糊图像差值,得到近景模糊效果  
  96.         final = (depth > _focalDistance) ? final : lerp(ori, blur, clamp((_focalDistance - depth) * _nearBlurScale, 0, 1));  
  97.         //焦点位置是清晰的图像,两边分别用当前像素深度距离焦点的距离进行差值,这样就达到原理焦点位置模糊的效果  
  98.   
  99.         //上面的?在编译时会被编译成if语句,GPU并不擅长分支计算,而且如果有分支,两个分支都要跑。这里给了一个更优化一些的计算方式,不过语法比较晦涩  
  100.         //float focalTest = clamp(sign(depth - _focalDistance),0,1);  
  101.         //fixed4 final = (1 - focalTest) * ori + focalTest * lerp(ori, blur, clamp((depth - _focalDistance) * _farBlurScale, 0, 1));  
  102.         //final = (focalTest)* final + (1 - focalTest) * lerp(ori, blur, clamp((_focalDistance - depth) * _nearBlurScale, 0, 1));  
  103.         return final;  
  104.     }  
  105.   
  106.     ENDCG  
  107.   
  108.     SubShader  
  109.     {  
  110.         //pass 0: 高斯模糊  
  111.         Pass  
  112.         {  
  113.             ZTest Off  
  114.             Cull Off  
  115.             ZWrite Off  
  116.             Fog{ Mode Off }  
  117.   
  118.             CGPROGRAM  
  119.             #pragma vertex vert_blur  
  120.             #pragma fragment frag_blur  
  121.             ENDCG  
  122.         }  
  123.   
  124.         //pass 1: 景深效果  
  125.         Pass  
  126.         {  
  127.   
  128.             ZTest Off  
  129.             Cull Off  
  130.             ZWrite Off  
  131.             Fog{ Mode Off }  
  132.             ColorMask RGBA  
  133.   
  134.             CGPROGRAM  
  135.             #pragma vertex vert_dof  
  136.             #pragma fragment frag_dof  
  137.             ENDCG  
  138.         }  
  139.   
  140.     }  
  141. }  

C#部分:
  1. using UnityEngine;  
  2. using System.Collections;  
  3.   
  4. [ExecuteInEditMode]  
  5. public class DepthOfFiled : PostEffectBase {  
  6.   
  7.     [Range(0.0f, 100.0f)]  
  8.     public float focalDistance = 10.0f;  
  9.     [Range(0.0f, 100.0f)]  
  10.     public float nearBlurScale = 0.0f;  
  11.     [Range(0.0f, 1000.0f)]  
  12.     public float farBlurScale = 50.0f;  
  13.     //分辨率  
  14.     public int downSample = 1;  
  15.     //采样率  
  16.     public int samplerScale = 1;  
  17.   
  18.     private Camera _mainCam = null;  
  19.     public Camera MainCam  
  20.     {  
  21.         get  
  22.         {  
  23.             if (_mainCam == null)  
  24.                 _mainCam = GetComponent<Camera>();  
  25.             return _mainCam;  
  26.         }  
  27.     }  
  28.   
  29.     void OnEnable()  
  30.     {  
  31.         //maincam的depthTextureMode是通过位运算开启与关闭的  
  32.         MainCam.depthTextureMode |= DepthTextureMode.Depth;  
  33.     }  
  34.   
  35.     void OnDisable()  
  36.     {  
  37.         MainCam.depthTextureMode &= ~DepthTextureMode.Depth;  
  38.     }  
  39.   
  40.     void OnRenderImage(RenderTexture source, RenderTexture destination)  
  41.     {  
  42.         if (_Material)  
  43.         {  
  44.             //首先将我们设置的焦点限制在远近裁剪面之间  
  45.             Mathf.Clamp(focalDistance, MainCam.nearClipPlane, MainCam.farClipPlane);  
  46.   
  47.             //申请两块RT,并且分辨率按照downSameple降低  
  48.             RenderTexture temp1 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format);  
  49.             RenderTexture temp2 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format);  
  50.   
  51.             //直接将场景图拷贝到低分辨率的RT上达到降分辨率的效果  
  52.             Graphics.Blit(source, temp1);  
  53.   
  54.             //高斯模糊,两次模糊,横向纵向,使用pass0进行高斯模糊  
  55.             _Material.SetVector("_offsets", new Vector4(0, samplerScale, 0, 0));  
  56.             Graphics.Blit(temp1, temp2, _Material, 0);  
  57.             _Material.SetVector("_offsets", new Vector4(samplerScale, 0, 0, 0));  
  58.             Graphics.Blit(temp2, temp1, _Material, 0);  
  59.   
  60.             //景深操作,景深需要两的模糊效果图我们通过_BlurTex变量传入shader  
  61.             _Material.SetTexture("_BlurTex", temp1);  
  62.             //设置shader的参数,主要是焦点和远近模糊的权重,权重可以控制插值时使用模糊图片的权重  
  63.             _Material.SetFloat("_focalDistance", FocalDistance01(focalDistance));  
  64.             _Material.SetFloat("_nearBlurScale", nearBlurScale);  
  65.             _Material.SetFloat("_farBlurScale", farBlurScale);  
  66.   
  67.             //使用pass1进行景深效果计算,清晰场景图直接从source输入到shader的_MainTex中  
  68.             Graphics.Blit(source, destination, _Material, 1);  
  69.   
  70.             //释放申请的RT  
  71.             RenderTexture.ReleaseTemporary(temp1);  
  72.             RenderTexture.ReleaseTemporary(temp2);  
  73.         }  
  74.     }  
  75.   
  76.     //计算设置的焦点被转换到01空间中的距离,以便shader中通过这个01空间的焦点距离与depth比较  
  77.     private float FocalDistance01(float distance)  
  78.     {  
  79.         return MainCam.WorldToViewportPoint((distance - MainCam.nearClipPlane) * MainCam.transform.forward + MainCam.transform.position).z / (MainCam.farClipPlane - MainCam.nearClipPlane);  
  80.     }  
  81.   
  82.   
  83. }  

由于上面的原理&代码的注释已经比较清楚,这里不多介绍。景深效果是一个复合效果,其中的模糊效果前面的文章也有介绍,这篇文章的重点也就是通过DepthTexture来混合清晰和模糊的图像,来达到我们想要的“重点”清晰,“陪衬”模糊的效果。

大部分的景深效果是前景清晰,远景模糊,这也是景深的标准用法,不过有时候也有需要近景模糊,远景清晰的效果,或者前后都模糊,中间焦点位置清晰,在实现上我们通过像素点深度到达焦点的距离作为参数,在清晰和模糊图像之间插值,先计算远景的,结果与模糊图片再进行插值,得到最终的效果。

四.效果展示


在MainCamera上挂上DepthOfField脚本,将DepthOfFileld.shader赋给shader槽,即可看见景深的效果。

首先我们看一下清晰的场景图:

开启远景模糊的景深效果:

远近同时模糊的效果,只有焦点距离的对象清晰:


原文地址:http://blog.youkuaiyun.com/puppet_master/article/details/52819874


unityShader裁剪空间 裁剪空间是 GPU 用来决定哪些内容需要显示在屏幕上的一个标准坐标系。它是一个立方体空间,范围是从。 阅读详情

相关推荐

Unity3D:提升场景画面品质&平衡性能优化

Unity之提升场景画面品质及性能优化

saitoDeng的博客 7735

unity shader-UV平移,旋转,缩放

平移效果: 旋转: 缩放: 扭曲效果: shader代码:Shader "Custom/MoveUV" { Properties { _MainTex ("Texture", 2D) = "white" {} _Speed("Rotate Speed",Range(0,4))=1 } SubShader {

yiwei151的博客 1万+

Unity半透明物体景深失效?教你用双材质球方案完美解决(附完整Shader代码)

本文深入剖析了Unity中半透明物体导致景深效果失效的根本原因,即半透明物体默认不写入摄像机深度图。针对此问题,文章详细介绍了稳定高效的“双材质球”解决方案,通过为物体附加一个仅写入深度信息的不可见材质,完美修复景深效果,并提供了完整的Shader代码与实现脚本。

weixin_29010003的博客 381

Unity中Shader的片段取舍clip(value)(一般用于消融效果)

Unity中Shader的片段取舍(一般用于消融效果)

楠溪泽岸的博客 2107

Unity屏幕后处理:OnRenderImage与RendererFeature方案深度解析

屏幕后处理是实时渲染中提升画面表现力的关键技术,其核心原理是在场景渲染完成后,对最终图像进行像素级处理,如同为画面添加滤镜。从技术实现看,它依赖于着色器算法对渲染纹理进行操作,常见效果包括景深、泛光和色彩校正。在Unity引擎中,实现路径的选择直接影响项目架构与性能。传统内置管线通过OnRenderImage回调实现,简单直接但难以与现代可编程渲染管线集成;而URP/HDRP采用的RendererFeature方案,则以模块化、可配置的设计,通过ScriptableRenderPass精确控制执行时机与资源

weixin_30613433的博客 380

Unity Shader-后处理:简单均值模糊

今天来学习一下后处理中比较常用的一种效果,屏幕模糊效果。屏幕模糊效果是一些高级后处理效果的基础,比如景深,运动模糊等等效果都需要用屏幕模糊效果来实现,所以我们首先看一下屏幕模糊效果,然后通过屏幕模糊,进一步学习景深效果与运动模糊效果的实现。 一.简介 二.原理介绍 三.代码实现 四.效果展示

puppet_master的专栏 1万+

Unity Shader 屏幕后处理:OnRenderImage 与 RendererFeature实现景深、Bloom、色彩校正

必须在 Universal Renderer Data 里关闭"中间纹理"选项,或直接迁移到 RendererFeature。移动端强烈建议后者,因为前者会强制 GPU 做一次额外的 Resolve。构建的轻量渲染管线,其核心设计思路是:一切渲染步骤都可以在 CPU 侧用 C# 显式编排。合成时将模糊结果上采样回原分辨率,视觉损失微乎其微。URP 内置的 Bloom Volume 组件就是这个思路,也可以完全自定义。是 Built-in 管线遗留的回调。之前,以参与 TAA/抖动之前的 HDR 图像。

mxwin的博客 454

UnityShader后处理景深效果

UnityShader 后处理景深效果 主要原理是高斯核卷积,并根据深度图采样结果来判断模糊度。 高斯核能反映距离对模糊采样率造成的影响。本例使用的高斯核是5x5尺寸。可以使用双pass的方法把这个高斯核简化成两个一维的高斯核。 在模糊卷积中,把高斯核拆分成两个一维高斯核,在两个pass中分别进行xy方向的卷积。假设先进行了x方向的卷积, 那么y方向用以卷积的参数实际上是x方向上卷积过的。也就是说它也受到了对角线(或者说斜方向)上的影响。 在边缘检测卷积上,xy方向上都使用的是方阵卷积核,并且需要求得的结

ALiang_2685787271的博客 891

Unity三大渲染管线景深实现全解析:从Built-in到HDRP

景深是计算机图形学中模拟真实相机光学特性的核心后处理技术,其原理基于深度缓冲计算弥散圆半径,在图像空间进行采样与模糊混合。这项技术能显著增强画面的空间层次感和视觉引导性,在游戏开发、影视动画和虚拟现实等领域广泛应用。通过理解不同渲染管线下的实现差异,开发者可以更好地平衡效果质量与性能开销。本文聚焦Unity的Built-in、URP和HDRP三大管线,深入探讨景深效果的具体实现方案、参数调优技巧以及性能优化策略,帮助开发者掌握这一重要的视觉叙事工具。

weixin_29006187的博客 313

基于IDEA与Mill构建Windows下的Chisel开发环境——香山处理器源码解析实战

本文详细指导如何在Windows系统下使用IDEA集成开发环境和Mill构建工具搭建Chisel开发环境,并以香山处理器源码为实战案例进行解析。内容涵盖环境准备、源码获取、工程构建、IDEA配置优化及代码阅读技巧,帮助开发者高效学习硬件设计语言。

a1b2c3d的博客 716

第5.1节 构网控制:电压源特性与电压调节

摘要: 构网型变流器的核心物理本质是作为可控交流电压源,通过戴维南等效模型(受控电势源+低输出阻抗)自主建立并调节电压,增强电网电压刚度。其电压调节通过无功-电压闭环控制实现,内环为自动电压调节器(AVR),外环为无功-电压下垂特性,模拟同步发电机功能。关键技术包括自适应增益、虚拟阻抗补偿及动态限流策略,以应对弱电网稳定性、故障过流等问题。该设计满足《规范》对电压调节范围、动态无功支撑的要求,是高比例新能源电力系统电压稳定的关键解决方案。

技术工作者 1107

Unity Shader 中 ShadowCaster的作用和疑问

摘要:文章详细解析了Unity URP渲染管线中的ShadowCaster和DepthOnly两个关键Pass的作用与区别。ShadowCaster用于生成阴影贴图,处理物体投影效果,通过偏移计算避免自阴影问题;DepthOnly则用于生成场景深度图(_CameraDepthTexture),供SSAO、景深等后处理使用。两者调用时机和用途不同:ShadowCaster由光源视角调用生成阴影贴图,DepthOnly由摄像机视角调用生成深度图。文章还指出缺少DepthOnly会导致物体在深度相关后处理中失效,

mxwin的博客 444

Python入门基础教程(非常详细)

Python是一门开源免费、通用型的脚本编程语言,它上手简单,功能强大,坚持「极简主义」。Python类库(模块)极其丰富,这使得Python几乎无所不能,不管是传统的Web开发、PC软件开发、Linux运维,还是当下火热的机器学习、大数据分析、网络爬虫,Python都能胜任。这套Python基础教程不是教科书,不会玩弄概念,而是力求口语化和通俗化,让读者尽快入门。如果有小朋友出于兴趣学习Python,请引导他阅读本教程的前半部分,这是基础,可以降低学习成本;...

Yuki1127918的博客 34万+

Unity实现Arc System Works动漫风格Shader:从原理到实战

卡通渲染(Toon Shading)是一种将3D模型渲染成2D手绘动漫风格的技术,其核心原理是通过修改光照模型和渲染管线,将连续的光影过渡转化为分明的色块。该技术通过使用渐变纹理(Ramp Texture)进行阈值化采样来实现硬边阴影,并结合风格化高光与边缘光(Rim Light)增强画面表现力。在游戏开发,特别是独立游戏和日式动漫风格项目中,卡通渲染能大幅提升艺术表现力与制作效率。本文聚焦于复现Arc System Works(代表作《罪恶装备》)的标志性视觉风格,深入探讨了其着色器管线中动态描边、色调分

weixin_33794672的博客 341

手把手教你用OpenCalib完成激光雷达与相机联合标定:从数据准备到结果可视化

本文详细介绍了使用OpenCalib工具链中的lidar2camera模块完成激光雷达与相机联合标定的全流程,包括数据准备、标定命令执行、结果验证与可视化。通过实战指南,帮助读者掌握工业级标定技术,提升自动驾驶和机器人领域的传感器融合精度。

weixin_30872499的博客 398

5G时代必知:LDPC与Polar码实战解析(附MATLAB仿真代码)

本文深入解析5G时代核心信道编码技术LDPC码与Polar码的原理差异及性能表现,通过MATLAB仿真代码展示其在实际通信系统中的应用。LDPC码适用于大数据块高速传输,而Polar码在小数据块低时延场景表现优异,帮助开发者优化5G系统设计。

sugar的博客 642

Unity 3D场景动态背景模糊实现方案

在3D渲染中,背景模糊并非简单的图像后处理,而是模拟真实镜头光学特性的空间分层效果。其核心在于区分前景与背景的空间层级,并依据深度信息动态控制模糊强度,从而实现电影级景深感。关键技术涉及摄像机视锥体裁剪、深度缓冲分层、自定义高斯核采样及RenderTexture隔离渲染。相比通用UI模糊插件,该方案避免了边缘噪点、深度抖动与性能浪费,特别适用于建筑可视化、AR导览、虚拟演播厅等需突出主体的实时3D应用。本文聚焦Unity引擎下可工程落地的动态背景模糊链路,涵盖URP管线适配、移动端优化与多平台分辨率保真。

weixin_30606461的博客 680

解决:Solving environment: failed CondaValueError: Malformed version string ‘~‘: invalid character(s).

解决:Solving environment: failed CondaValueError: Malformed version string '~': invalid character(s).

晚风微凉的博客 1万+

技术美术TA之屏幕后处理

1.需要在Camera上挂 Monobehaviour脚本呢,通过 OnRenderImage 的回调 调用 Graphics.Blit 进行绘制。本文是视频课程《Unity技术美术TA:Shader篇》,算是对自己学习的总结,也希望分享下所学知识~~对源图像进行 Graphs.Blit 存储成目标图像,最后写入到帧缓存。2.参数需要在 C# 面板控制,不在Material才创建。当内容绘制完毕,会存到帧缓冲区,称为源图像。通过很短的设置时间大幅改善产品的视觉效果。

东北砍王的栖息地 248

安卓15_ROM修改定制化_____修改rom的前提条件 去除各种验证 安卓设备通用

通过博文了解💝💝💝 1-------💝💝💝了解安卓设备的启动流程与核心验证机制 2-------💝💝💝了解安卓设备修改rom中的各种验证机制以及对应的去除方法 3-------💝💝💝了解avb验证与dm验证的本质区别与对应的操作方式 4-------💝💝💝修改rom前的循序步骤 避免验证机制导致的不开机

小马哥的专栏 506

Python全栈入门到实战【JavaScript篇 15】async/await与Fetch API,打通前后端数据通道

Fetch API是浏览器内置的现代HTTP请求接口,用于向服务器发送请求并获取响应。它是(XHR)的替代品。学习Fetch的目标非常明确——用JS从后端API获取数据,并渲染到前端页面。这标志着前后端数据通道的打通,是实现全栈开发的核心技能。try {// 等待Promiseconst parallel = await Promise.all([ // 并行等待]);

那些看似不起波澜的日复一日,会在某天让你看到坚持的意义 1978

Unity Shader-Command Buffer的使用(景深与描边效果重置版)

Command Buffer是Unity5新增的一个灰常灰常强大的功能。先祭出官方介绍和文档。我们在渲染的时候,给OpenGL或者DX的就是一系列的指令,比如glDrawElement,glClear等等,这些东西目前是引擎去调用的,而Unity也为我们封装了更高一级的API,也就是CommandBuffer,可以让我们更加方便灵活地实现一些效果。CommandBuffer最主要的功能是可以预定义一些列的渲染指令,然后将这些指令在我们想要的时机进行执行。本篇文章简单介绍一下CommandBuffer的使用,

puppet_master的专栏 4万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Unity Shader PostProcessing - 7 - DepthOfField(DOF)景深

基本概念 在百度百科里有解析:景深。 引用其简短描述的一段话: 景深(DOF),是指在摄影机镜头或其他成像器前沿能够取得清晰图像的成像所测定的被摄物体前后距离范围。光圈、镜头、及焦平面到拍摄物的距离是影响景深的重要因素。 在聚焦完成后,焦点前后的范围内所呈现的清晰图像的距离,这一前一后的范围,便叫做景深。 在镜头前方(焦点的前、后)有一段一定长度的空间,当被摄物体位于这段空间内时,其在底片上的成...

Jave.Lin 的学习笔记 3833

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

上一篇: Unity Shader-后处理:高斯模糊
下一篇: Unity Shader-后处理:Bloom全屏泛光
cbbbc
博客等级 码龄15年 609粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值