前言本节介绍了几种常见的屏幕后处理BSC屏幕后处理中的BSC是最基础、最常用的色彩调整后处理组合全称为Brightness亮度、Saturation饱和度、Contrast对比度。Brightness亮度直接对画面所有像素的RGB分量进行统一的加法偏移整体提亮或压暗画面调整画面整体的明暗基调。Saturation饱和度控制色彩的鲜艳程度将像素颜色向灰度值饱和度为0或高饱和色彩饱和度大于1插值饱和度为0时画面完全变为黑白。Contrast对比度调整画面明暗反差将像素颜色以0.5灰度值为中心进行缩放提升对比度会让亮部更亮、暗部更暗降低对比度则画面整体发灰偏平。代码实现Shader MyCustom/BSC { Properties { _MainTex (Texture, 2D) white {} _Brightness (Brightness, Float) 1 _Saturation (Saturation, Float) 1 _Contrast (Contrast, Float) 1 } SubShader { Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _Brightness; float _Saturation; float _Contrast; // appdata_img 只包含顶点坐标和uv v2f vert (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv v.texcoord; return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 texColor tex2D(_MainTex, i.uv); // 明度 float3 finalColor texColor.rgb * _Brightness; // 饱和度 float3 greyColor 0.2125 * texColor.r 0.7154 * texColor.g 0.0721 * texColor.b; finalColor lerp(greyColor, finalColor, _Saturation); // 对比度 float3 midGreyColor float3(0.5, 0.5, 0.5); finalColor lerp(midGreyColor, finalColor, _Contrast); return float4(finalColor, 1); } ENDCG } } }边缘检测屏幕后处理边缘检测是一种直接在已渲染完成的画面上提取物体轮廓的特效技术广泛用于描边、卡通渲染、轮廓高亮等场景。它通过对屏幕纹理的像素邻域进行卷积采样计算像素间的灰度差梯度当梯度超过设定阈值时判定该像素属于边缘替换为指定的边缘颜色。最常用的算子是Sobel算子通过3×3的卷积核分别计算X、Y方向的梯度合成最终的边缘强度。代码实现Shader MyCustom/EdgeDetection { Properties { _MainTex (Texture, 2D) white {} _EdgeOnly (_EdgeOnly, Float) 1 _EdgeColor (_EdgeColor, Color) (1, 1, 1, 1) _EdgeBGC (_EdgeBGC, Color) (0, 0, 0, 1) } SubShader { Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc struct v2f { float4 vertex : SV_POSITION; float2 uv[9] : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _MainTex_TexelSize; float _EdgeOnly; float4 _EdgeColor; float4 _EdgeBGC; // appdata_img 只包含顶点坐标和uv v2f vert (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); // 邻点 o.uv[0] v.texcoord _MainTex_TexelSize.xy * float2(-1, -1); o.uv[1] v.texcoord _MainTex_TexelSize.xy * float2(0, -1); o.uv[2] v.texcoord _MainTex_TexelSize.xy * float2(1, -1); o.uv[3] v.texcoord _MainTex_TexelSize.xy * float2(-1, 0); o.uv[4] v.texcoord _MainTex_TexelSize.xy * float2(0, 0); o.uv[5] v.texcoord _MainTex_TexelSize.xy * float2(1, 0); o.uv[6] v.texcoord _MainTex_TexelSize.xy * float2(-1, 1); o.uv[7] v.texcoord _MainTex_TexelSize.xy * float2(0, 1); o.uv[8] v.texcoord _MainTex_TexelSize.xy * float2(1, 1); return o; } float greyColor(float4 texColor) { return 0.2125 * texColor.r 0.7154 * texColor.g 0.0721 * texColor.b; } // 使用算子计算边缘强度 float sobel(v2f i) { const float gx[9] {-1, -2, -1, 0, 0, 0, 1, 2, 1}; const float gy[9] {-1, 0, 1, -2, 0, 2, -1, 0, 1}; float texColor; float edgeX; float edgeY; for (int index 0; index 9; index) { texColor greyColor(tex2D(_MainTex, i.uv[index])); edgeX texColor * gx[index]; edgeY texColor * gy[index]; } float edge 1 - abs(edgeX) - abs(edgeY); return edge; } fixed4 frag (v2f i) : SV_Target { float edge sobel(i); float4 finalColor 1; // 边缘颜色 float3 edgeColor lerp(_EdgeColor, tex2D(_MainTex, i.uv[4]), edge); float3 bgc lerp(_EdgeColor, _EdgeBGC, edge); // 边缘和原图像混合 finalColor.rgb lerp(edgeColor, bgc, _EdgeOnly); return finalColor; } ENDCG } } }高斯模糊高斯模糊Gaussian Blur是屏幕后处理中最核心的图像平滑算法常用于模拟景深、运动模糊、 bloom 发光效果的基础预处理以及降低画面噪点。权重分配中心像素权重最高距离越远的邻域像素权重越低呈钟形曲线分布。加权平均对每个像素及其邻域像素进行加权求和实现平滑过渡。可分离性关键优化二维高斯核可以分解为水平方向和垂直方向两个一维核。这使得计算复杂度从 O(N2)O(N2) 降低到 O(2N)O(2N)极大提升了性能。为了利用可分离性通常分两个 Pass 实现Pass 1水平模糊读取源纹理沿 X 轴方向采样邻域像素应用一维高斯权重输出到中间纹理。Pass 2垂直模糊读取中间纹理沿 Y 轴方向采样邻域像素应用相同的一维高斯权重输出到最终屏幕。代码实现Shader MyCustom/GaussianBlur { Properties { _MainTex (Texture, 2D) white {} _BlurSize (_BlurSize, Float) 1 } SubShader { CGINCLUDE #include UnityCG.cginc struct v2f { float4 vertex : SV_POSITION; float2 uv[5] : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _MainTex_TexelSize; float _BlurSize; // appdata_img 只包含顶点坐标和uv // 采集正负1和正负2的五个点5点高斯模糊Gaussian Blur v2f vertHorizontal (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv[0] v.texcoord _MainTex_TexelSize.xy * float2(0, 0); o.uv[1] v.texcoord _MainTex_TexelSize.xy * float2(1, 0) * _BlurSize; o.uv[2] v.texcoord _MainTex_TexelSize.xy * float2(2, 0) * _BlurSize; o.uv[3] v.texcoord _MainTex_TexelSize.xy * float2(-1, 0) * _BlurSize; o.uv[4] v.texcoord _MainTex_TexelSize.xy * float2(-2, 0) * _BlurSize; return o; } v2f vertVertical (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv[0] v.texcoord _MainTex_TexelSize.xy * float2(0, 0); o.uv[1] v.texcoord _MainTex_TexelSize.xy * float2(0, 1) * _BlurSize; o.uv[2] v.texcoord _MainTex_TexelSize.xy * float2(0, 2) * _BlurSize; o.uv[3] v.texcoord _MainTex_TexelSize.xy * float2(0, -1) * _BlurSize; o.uv[4] v.texcoord _MainTex_TexelSize.xy * float2(0, -2) * _BlurSize; return o; } fixed4 frag (v2f i) : SV_Target { // 加强平均 float weight[3] {0.4026, 0.2442, 0.0545}; float3 sumColor tex2D(_MainTex, i.uv[0]).rgb * weight[0]; for(int index 1; index 3; index) { sumColor tex2D(_MainTex, i.uv[index]).rgb * weight[index]; sumColor tex2D(_MainTex, i.uv[index 2]).rgb * weight[index]; } //sumColor 0; //for(int index 0; index 5; index) //{ // sumColor tex2D(_MainTex, i.uv[index]).rgb * 0.2; //} float4 finalColor 1; finalColor.rgb sumColor; return finalColor; } ENDCG ZTest Always ZWrite Off Cull Off // 横向纵向分为两个Pass进行计算 Pass { NAME GaussianBlurVertical CGPROGRAM #pragma vertex vertVertical #pragma fragment frag ENDCG } Pass { NAME GaussianBlurHorizontal CGPROGRAM #pragma vertex vertHorizontal #pragma fragment frag ENDCG } } }BloomBloom泛光/辉光是模拟真实相机镜头光晕的经典屏幕后处理特效能让画面中高亮区域向外扩散出柔和的发光效果大幅提升画面氛围感和真实感。Bloom的核心逻辑是“提取高亮→高斯模糊→叠加回原画面”三步流程高亮提取从原画面中筛选出亮度超过设定阈值的像素过滤掉暗部区域只保留画面中本该发光的部分如太阳、灯光、金属高光。高斯模糊对提取出的高亮图执行多次降分辨率高斯模糊让高亮区域向外扩散出柔和的光晕这一步可以直接复用你之前写好的高斯模糊Shader。叠加混合将模糊后的光晕图通过加法混合的方式叠加回原始画面最终得到泛光效果。代码实现Shader MyCustom/Bloom { Properties { _MainTex (Texture, 2D) white {} _BrightnessTex (_BrightnessTex, 2D) white {} _BlurSize (_BlurSize, Float) 1 _GreyThreshold (_GreyThreshold, Float) 1 } SubShader { CGINCLUDE #include UnityCG.cginc sampler2D _MainTex; float4 _MainTex_ST; sampler2D _BrightnessTex; float4 _MainTex_TexelSize; float _BlurSize; float _GreyThreshold; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert(appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv v.texcoord; return o; } float greyColor(float4 texColor) { return 0.2125 * texColor.r 0.7154 * texColor.g 0.0721 * texColor.b; } // 高亮提取, 从灰度图过滤 fixed4 fragBrightness (v2f i) : SV_Target { float4 texColor tex2D(_MainTex, i.uv); float brightness saturate(greyColor(texColor) - _GreyThreshold); return texColor * brightness; } // 叠加原图和光晕图 // Bloom通常在HDR色彩空间下计算配合ACES色调映射能避免泛光过曝发白得到更自然的发光色彩。_BrightnessTex是处理过的图片 fixed4 fragBloom (v2f i) : SV_Target { float4 texColor tex2D(_MainTex, i.uv); float4 brightnessColor tex2D(_BrightnessTex, i.uv); return texColor brightnessColor; } ENDCG ZTest Always ZWrite Off Cull Off // 高亮提取 Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragBrightness ENDCG } // 高斯模糊 UsePass MyCustom/GaussianBlur/GaussianBlurVertical UsePass MyCustom/GaussianBlur/GaussianBlurHorizontal // 混合 Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragBloom ENDCG } } }简易运动模糊使用透明度混合Alpha Blending或残影叠加的简化写法完成静态运动模糊实现将当前渲染的画面合到上一帧保留在屏幕缓冲区Back Buffer的画面上没有利用速度向量Velocity Vector或历史帧重投影无法产生基于物体运动方向的真实拖影。代码实现Shader MyCustom/MotionBlur { Properties { _MainTex (Texture, 2D) white {} _MotionBlurAmount (_MotionBlurAmount, Float) 1 } SubShader { CGINCLUDE #include UnityCG.cginc struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _MotionBlurAmount; // appdata_img 只包含顶点坐标和uv v2f vert (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv v.texcoord; return o; } fixed4 fragBlurAmount (v2f i) : SV_Target { // sample the texture fixed4 texColor tex2D(_MainTex, i.uv); texColor.a _MotionBlurAmount; return texColor; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 texColor tex2D(_MainTex, i.uv); return texColor; } ENDCG ZTest Always Cull Off ZWrite Off // 简单实现透明度叠加 Pass { Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB CGPROGRAM #pragma vertex vert #pragma fragment fragBlurAmount ENDCG } Pass { Blend One Zero ColorMask A // 不让最终生成的纹理受到A通道的影响 CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG } } }
TA不一样(十四)
发布时间:2026/7/13 4:40:33
前言本节介绍了几种常见的屏幕后处理BSC屏幕后处理中的BSC是最基础、最常用的色彩调整后处理组合全称为Brightness亮度、Saturation饱和度、Contrast对比度。Brightness亮度直接对画面所有像素的RGB分量进行统一的加法偏移整体提亮或压暗画面调整画面整体的明暗基调。Saturation饱和度控制色彩的鲜艳程度将像素颜色向灰度值饱和度为0或高饱和色彩饱和度大于1插值饱和度为0时画面完全变为黑白。Contrast对比度调整画面明暗反差将像素颜色以0.5灰度值为中心进行缩放提升对比度会让亮部更亮、暗部更暗降低对比度则画面整体发灰偏平。代码实现Shader MyCustom/BSC { Properties { _MainTex (Texture, 2D) white {} _Brightness (Brightness, Float) 1 _Saturation (Saturation, Float) 1 _Contrast (Contrast, Float) 1 } SubShader { Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _Brightness; float _Saturation; float _Contrast; // appdata_img 只包含顶点坐标和uv v2f vert (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv v.texcoord; return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 texColor tex2D(_MainTex, i.uv); // 明度 float3 finalColor texColor.rgb * _Brightness; // 饱和度 float3 greyColor 0.2125 * texColor.r 0.7154 * texColor.g 0.0721 * texColor.b; finalColor lerp(greyColor, finalColor, _Saturation); // 对比度 float3 midGreyColor float3(0.5, 0.5, 0.5); finalColor lerp(midGreyColor, finalColor, _Contrast); return float4(finalColor, 1); } ENDCG } } }边缘检测屏幕后处理边缘检测是一种直接在已渲染完成的画面上提取物体轮廓的特效技术广泛用于描边、卡通渲染、轮廓高亮等场景。它通过对屏幕纹理的像素邻域进行卷积采样计算像素间的灰度差梯度当梯度超过设定阈值时判定该像素属于边缘替换为指定的边缘颜色。最常用的算子是Sobel算子通过3×3的卷积核分别计算X、Y方向的梯度合成最终的边缘强度。代码实现Shader MyCustom/EdgeDetection { Properties { _MainTex (Texture, 2D) white {} _EdgeOnly (_EdgeOnly, Float) 1 _EdgeColor (_EdgeColor, Color) (1, 1, 1, 1) _EdgeBGC (_EdgeBGC, Color) (0, 0, 0, 1) } SubShader { Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc struct v2f { float4 vertex : SV_POSITION; float2 uv[9] : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _MainTex_TexelSize; float _EdgeOnly; float4 _EdgeColor; float4 _EdgeBGC; // appdata_img 只包含顶点坐标和uv v2f vert (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); // 邻点 o.uv[0] v.texcoord _MainTex_TexelSize.xy * float2(-1, -1); o.uv[1] v.texcoord _MainTex_TexelSize.xy * float2(0, -1); o.uv[2] v.texcoord _MainTex_TexelSize.xy * float2(1, -1); o.uv[3] v.texcoord _MainTex_TexelSize.xy * float2(-1, 0); o.uv[4] v.texcoord _MainTex_TexelSize.xy * float2(0, 0); o.uv[5] v.texcoord _MainTex_TexelSize.xy * float2(1, 0); o.uv[6] v.texcoord _MainTex_TexelSize.xy * float2(-1, 1); o.uv[7] v.texcoord _MainTex_TexelSize.xy * float2(0, 1); o.uv[8] v.texcoord _MainTex_TexelSize.xy * float2(1, 1); return o; } float greyColor(float4 texColor) { return 0.2125 * texColor.r 0.7154 * texColor.g 0.0721 * texColor.b; } // 使用算子计算边缘强度 float sobel(v2f i) { const float gx[9] {-1, -2, -1, 0, 0, 0, 1, 2, 1}; const float gy[9] {-1, 0, 1, -2, 0, 2, -1, 0, 1}; float texColor; float edgeX; float edgeY; for (int index 0; index 9; index) { texColor greyColor(tex2D(_MainTex, i.uv[index])); edgeX texColor * gx[index]; edgeY texColor * gy[index]; } float edge 1 - abs(edgeX) - abs(edgeY); return edge; } fixed4 frag (v2f i) : SV_Target { float edge sobel(i); float4 finalColor 1; // 边缘颜色 float3 edgeColor lerp(_EdgeColor, tex2D(_MainTex, i.uv[4]), edge); float3 bgc lerp(_EdgeColor, _EdgeBGC, edge); // 边缘和原图像混合 finalColor.rgb lerp(edgeColor, bgc, _EdgeOnly); return finalColor; } ENDCG } } }高斯模糊高斯模糊Gaussian Blur是屏幕后处理中最核心的图像平滑算法常用于模拟景深、运动模糊、 bloom 发光效果的基础预处理以及降低画面噪点。权重分配中心像素权重最高距离越远的邻域像素权重越低呈钟形曲线分布。加权平均对每个像素及其邻域像素进行加权求和实现平滑过渡。可分离性关键优化二维高斯核可以分解为水平方向和垂直方向两个一维核。这使得计算复杂度从 O(N2)O(N2) 降低到 O(2N)O(2N)极大提升了性能。为了利用可分离性通常分两个 Pass 实现Pass 1水平模糊读取源纹理沿 X 轴方向采样邻域像素应用一维高斯权重输出到中间纹理。Pass 2垂直模糊读取中间纹理沿 Y 轴方向采样邻域像素应用相同的一维高斯权重输出到最终屏幕。代码实现Shader MyCustom/GaussianBlur { Properties { _MainTex (Texture, 2D) white {} _BlurSize (_BlurSize, Float) 1 } SubShader { CGINCLUDE #include UnityCG.cginc struct v2f { float4 vertex : SV_POSITION; float2 uv[5] : TEXCOORD0; }; sampler2D _MainTex; float4 _MainTex_ST; float4 _MainTex_TexelSize; float _BlurSize; // appdata_img 只包含顶点坐标和uv // 采集正负1和正负2的五个点5点高斯模糊Gaussian Blur v2f vertHorizontal (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv[0] v.texcoord _MainTex_TexelSize.xy * float2(0, 0); o.uv[1] v.texcoord _MainTex_TexelSize.xy * float2(1, 0) * _BlurSize; o.uv[2] v.texcoord _MainTex_TexelSize.xy * float2(2, 0) * _BlurSize; o.uv[3] v.texcoord _MainTex_TexelSize.xy * float2(-1, 0) * _BlurSize; o.uv[4] v.texcoord _MainTex_TexelSize.xy * float2(-2, 0) * _BlurSize; return o; } v2f vertVertical (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv[0] v.texcoord _MainTex_TexelSize.xy * float2(0, 0); o.uv[1] v.texcoord _MainTex_TexelSize.xy * float2(0, 1) * _BlurSize; o.uv[2] v.texcoord _MainTex_TexelSize.xy * float2(0, 2) * _BlurSize; o.uv[3] v.texcoord _MainTex_TexelSize.xy * float2(0, -1) * _BlurSize; o.uv[4] v.texcoord _MainTex_TexelSize.xy * float2(0, -2) * _BlurSize; return o; } fixed4 frag (v2f i) : SV_Target { // 加强平均 float weight[3] {0.4026, 0.2442, 0.0545}; float3 sumColor tex2D(_MainTex, i.uv[0]).rgb * weight[0]; for(int index 1; index 3; index) { sumColor tex2D(_MainTex, i.uv[index]).rgb * weight[index]; sumColor tex2D(_MainTex, i.uv[index 2]).rgb * weight[index]; } //sumColor 0; //for(int index 0; index 5; index) //{ // sumColor tex2D(_MainTex, i.uv[index]).rgb * 0.2; //} float4 finalColor 1; finalColor.rgb sumColor; return finalColor; } ENDCG ZTest Always ZWrite Off Cull Off // 横向纵向分为两个Pass进行计算 Pass { NAME GaussianBlurVertical CGPROGRAM #pragma vertex vertVertical #pragma fragment frag ENDCG } Pass { NAME GaussianBlurHorizontal CGPROGRAM #pragma vertex vertHorizontal #pragma fragment frag ENDCG } } }BloomBloom泛光/辉光是模拟真实相机镜头光晕的经典屏幕后处理特效能让画面中高亮区域向外扩散出柔和的发光效果大幅提升画面氛围感和真实感。Bloom的核心逻辑是“提取高亮→高斯模糊→叠加回原画面”三步流程高亮提取从原画面中筛选出亮度超过设定阈值的像素过滤掉暗部区域只保留画面中本该发光的部分如太阳、灯光、金属高光。高斯模糊对提取出的高亮图执行多次降分辨率高斯模糊让高亮区域向外扩散出柔和的光晕这一步可以直接复用你之前写好的高斯模糊Shader。叠加混合将模糊后的光晕图通过加法混合的方式叠加回原始画面最终得到泛光效果。代码实现Shader MyCustom/Bloom { Properties { _MainTex (Texture, 2D) white {} _BrightnessTex (_BrightnessTex, 2D) white {} _BlurSize (_BlurSize, Float) 1 _GreyThreshold (_GreyThreshold, Float) 1 } SubShader { CGINCLUDE #include UnityCG.cginc sampler2D _MainTex; float4 _MainTex_ST; sampler2D _BrightnessTex; float4 _MainTex_TexelSize; float _BlurSize; float _GreyThreshold; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; }; v2f vert(appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv v.texcoord; return o; } float greyColor(float4 texColor) { return 0.2125 * texColor.r 0.7154 * texColor.g 0.0721 * texColor.b; } // 高亮提取, 从灰度图过滤 fixed4 fragBrightness (v2f i) : SV_Target { float4 texColor tex2D(_MainTex, i.uv); float brightness saturate(greyColor(texColor) - _GreyThreshold); return texColor * brightness; } // 叠加原图和光晕图 // Bloom通常在HDR色彩空间下计算配合ACES色调映射能避免泛光过曝发白得到更自然的发光色彩。_BrightnessTex是处理过的图片 fixed4 fragBloom (v2f i) : SV_Target { float4 texColor tex2D(_MainTex, i.uv); float4 brightnessColor tex2D(_BrightnessTex, i.uv); return texColor brightnessColor; } ENDCG ZTest Always ZWrite Off Cull Off // 高亮提取 Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragBrightness ENDCG } // 高斯模糊 UsePass MyCustom/GaussianBlur/GaussianBlurVertical UsePass MyCustom/GaussianBlur/GaussianBlurHorizontal // 混合 Pass { CGPROGRAM #pragma vertex vert #pragma fragment fragBloom ENDCG } } }简易运动模糊使用透明度混合Alpha Blending或残影叠加的简化写法完成静态运动模糊实现将当前渲染的画面合到上一帧保留在屏幕缓冲区Back Buffer的画面上没有利用速度向量Velocity Vector或历史帧重投影无法产生基于物体运动方向的真实拖影。代码实现Shader MyCustom/MotionBlur { Properties { _MainTex (Texture, 2D) white {} _MotionBlurAmount (_MotionBlurAmount, Float) 1 } SubShader { CGINCLUDE #include UnityCG.cginc struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _MotionBlurAmount; // appdata_img 只包含顶点坐标和uv v2f vert (appdata_img v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv v.texcoord; return o; } fixed4 fragBlurAmount (v2f i) : SV_Target { // sample the texture fixed4 texColor tex2D(_MainTex, i.uv); texColor.a _MotionBlurAmount; return texColor; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 texColor tex2D(_MainTex, i.uv); return texColor; } ENDCG ZTest Always Cull Off ZWrite Off // 简单实现透明度叠加 Pass { Blend SrcAlpha OneMinusSrcAlpha ColorMask RGB CGPROGRAM #pragma vertex vert #pragma fragment fragBlurAmount ENDCG } Pass { Blend One Zero ColorMask A // 不让最终生成的纹理受到A通道的影响 CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG } } }