shader-屏幕后处理

Unity Shader-后处理屏幕水波效果 一.简介 最近在打黑魂,被虐得死去活来,每次都是想砸电脑的节奏,然而还是忍不住想玩,唉。在被虐了千百遍之后,我发现写代码比玩游戏爽....下面步入正题,黑魂的传送技能之前会播放一个帅帅的屏幕特效-屏幕水波,从屏幕中间向四周扩散开来,很有赶脚。下面附上一张截图: 阅读详情

屏幕后处理

在渲染完整个场景得到屏幕图像后,再对这个图像进行处理,实现各种特效。在渲染后的屏幕图像,即抓屏,OnRenderImage函数接口可以对该图像进行操作返回最终的图像,利用Graphics.Blit()函数处理图片。默认情况下,OnRenderImage在透明和不透明的pass执行完后被调用。大致的流程:向摄像机添加脚本--》实现OnRenderImage函数--》调用Graphics.Blit()使用特定的shader处理图像--》将最终的图像返回屏幕。注意:使用之前需要检查条件是否满足这样的操作,平台是否支持该操作。

    饱和度、亮度、对比度

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]//在编辑模式下能够执行该程序
[RequireComponent(typeof(Camera))]
public class RenderDemo : MonoBehaviour
{
    //是否支持屏幕特效
    private bool isEnabled;
    private void Check()
    {
        //SystemInfo 基本能够获取运行平台的所有属性信息。
        if (SystemInfo.supportsImageEffects==false|| SystemInfo.supportsRenderTextures==false)
        {
            isEnabled = false;
            Debug.LogWarning("不支持屏幕特效或纹理渲染");
        }
        else
        {
            isEnabled = true;
        }
    }

    private void Start()
    {
        Check();
    }

    protected Material CheckShaderAndCreateMaterial(Shader shader,Material material)
    {
        if (null ==shader)
        {
            return null;
        }

        if (shader.isSupported && material && material.shader==shader)
        {
            return material;
        }

        if (!shader.isSupported)
        {
            return null;
        }
        else
        {
            material=new Material(shader);
            //hideFlags用于控制对象的破坏,保存和在检查器中的可见性。
            //不保存到场景中,加载新场景是不会被销毁。
            material.hideFlags = HideFlags.DontSave;
            if (material)
            {
                return material;
            }
            else
            {
               return null;
            }
        }
    }
    public Shader briSatConShader;
    private Material briSatConMaterial;
    public Material material {  
        get {
            briSatConMaterial = CheckShaderAndCreateMaterial(briSatConShader, briSatConMaterial);
            return briSatConMaterial;
        }  
    }

    [Range(0.0f, 3.0f)]
    public float brightness = 1.0f;

    [Range(0.0f, 3.0f)]
    public float saturation = 1.0f;

    [Range(0.0f, 3.0f)]
    public float contrast = 1.0f;
    void OnRenderImage(RenderTexture src, RenderTexture dest) {
        if (material != null) {
            material.SetFloat("_Brightness", brightness);
            material.SetFloat("_Saturation", saturation);
            material.SetFloat("_Contrast", contrast);
            
            Graphics.Blit(src, dest, material);
        } else {
            Graphics.Blit(src, dest);
        }
    }
}
Shader "Unlit/First"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Birghtness("Birghtness",Float)=1.0
        _Saturation("Saturation",Float)=1.0
        _Contrast("Contrast",Float)=1.0
    }
    SubShader
    {
        Pass
        {
            ZTest Always Cull Off ZWrite Off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            fixed _Birghtness;
            fixed _Saturation;
            fixed _Contrast;
            
            
            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;

            };
            v2f vert (appdata_img v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.texcoord;
                return o;
            }
            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 renderTex = tex2D(_MainTex, i.uv);
                //亮度 
                fixed3 finalColor=renderTex.rgb * _Birghtness;
                //饱和度
                //通过固定的系数算的luminance 亮度
                fixed luminance=0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
                fixed3 luminanceColor=fixed3(luminance,luminance,luminance);
                finalColor= lerp(luminanceColor,finalColor,_Saturation);
                
                //对比度 像创建对比度为0的颜色值 也就是各个分量为0.5
                fixed3 avgColor=fixed3(0.5,0.5,0.5);
                finalColor=lerp(avgColor,finalColor,_Contrast);
                return fixed4(finalColor,renderTex.a);
            }
            ENDCG
        }
    }
    FallBack Off
}

边缘检测

原理利用一些边缘检测算子对图像进行卷积操作。

如果相邻像素间存在差异明显的颜色、亮度、纹理等属性,就可认为之间存在边界----差值可用梯度(gradient)描述.

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Two : RenderDemo
{
    public Shader edgeDetectShader;
    private Material edgeDetectMaterial = null;
    public Material material {  
        get {
            edgeDetectMaterial = CheckShaderAndCreateMaterial(edgeDetectShader, edgeDetectMaterial);
            return edgeDetectMaterial;
        }  
    }

    [Range(0.0f, 1.0f)]
    public float edgesOnly = 0.0f;

    public Color edgeColor = Color.black;
	
    public Color backgroundColor = Color.white;

    void OnRenderImage (RenderTexture src, RenderTexture dest) {
        if (material != null) {
            material.SetFloat("_EdgeOnly", edgesOnly);
            material.SetColor("_EdgeColor", edgeColor);
            material.SetColor("_BackgroundColor", backgroundColor);

            Graphics.Blit(src, dest, material);
        } else {
            Graphics.Blit(src, dest);
        }
    }
}
Shader "Unlit/Two"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _EdgeColor("_EdgeColor",Color)=(0,0,0,0)
        _BackGroundColor("_BackGroundColor",Color)=(1,1,1,1)
        _EdgeOnly("_EdgeOnly",Float)=0
    }
    SubShader
    {
        Pass
        {
            ZTest Always Cull Off ZWrite Off
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            fixed4 _EdgeColor;  
            fixed4 _BackGroundColor;
            //边缘线强度
            fixed _EdgeOnly;
            sampler2D _MainTex;
            fixed4 _MainTex_TexelSize;//得到纹素值  ,卷积需要对相邻区域内的纹理进行采样,需要利用纹素值来计算各个相邻区域的纹理坐标
        
            struct v2f
            {
                float4 vertex : POSITION;
                half2 uv[9] : TEXCOORD0;
            };

            v2f vert (appdata_img v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                half2 uv=v.texcoord;
                //维数为9的数组,sobel算子采样时需要9个纹域纹理坐标
                o.uv[0]=uv+_MainTex_TexelSize.xy * half2(-1,-1);
                o.uv[1]=uv+_MainTex_TexelSize.xy * half2(0,-1);
                o.uv[2]=uv+_MainTex_TexelSize.xy * half2(1,-1);
                o.uv[3]=uv+_MainTex_TexelSize.xy * half2(-1,0);
                o.uv[4]=uv+_MainTex_TexelSize.xy * half2(0,0);//中心位置的纹理。
                o.uv[5]=uv+_MainTex_TexelSize.xy * half2(1,0);
                o.uv[6]=uv+_MainTex_TexelSize.xy * half2(-1,1);
                o.uv[7]=uv+_MainTex_TexelSize.xy * half2(0,1);
                o.uv[8]=uv+_MainTex_TexelSize.xy * half2(1,1);
                
                return o;
            }
            fixed luminance(fixed4 color) {
				return  0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b; 
			}
			//sobel算子的定义--计算的edge越小,该位置就越可能是边缘点。
			half Sobel(v2f i) {
				const half Gx[9] = {-1,  0,  1,
										-2,  0,  2,
										-1,  0,  1};
				const half Gy[9] = {-1, -2, -1,
										0,  0,  0,
										1,  2,  1};		
				half texColor;
				half edgeX = 0;
				half edgeY = 0;
				for (int it = 0; it < 9; it++) {
					texColor = luminance(tex2D(_MainTex, i.uv[it]));
					edgeX += texColor * Gx[it];
					edgeY += texColor * Gy[it];
				}
				
				half edge = 1 - abs(edgeX) - abs(edgeY);
				
				return edge;
			}
			
            fixed4 frag (v2f i) : SV_Target
            {
                //将计算采样纹理坐标转移到片元着色器,可以减少运算,提高性能。
                //利用Sobel得到梯度值
                fixed edge=Sobel(i);
                
                fixed4 withEdgeColoe=lerp(_EdgeColor,tex2D(_MainTex,i.uv[4]),edge);
                fixed4 onlyEgdeColor=lerp(_EdgeColor,_BackGroundColor,edge);
                fixed4 finalColor=lerp(withEdgeColoe,onlyEgdeColor,_EdgeOnly);
                return finalColor;
            }
            ENDCG
        }
    }
    FallBack Off
}

高斯模糊

卷积的另一个应用---高斯模糊。模糊实现:均值模糊(卷积后得到的像素值是其相邻内各个像素值的平均值);中值模糊(选择邻域内对所有像素排序后的中值替换原颜色);

一个pass使用竖直方向的一维高斯核对图像进行滤波,第二个pass再使用水平方向的一维高斯核对图像进行滤波。

Shader "Unlit/3"
{
   Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_BlurSize ("Blur Size", Float) = 1.0
	}
	SubShader {
	    
	    // 使用 CGINCLUDE ENDCG 组织代码 不需要包含pass 使用时只需要 指定其中的顶点或片着色器即可调用
		CGINCLUDE
		#include "UnityCG.cginc"
		
		sampler2D _MainTex;  
		half4 _MainTex_TexelSize;
		//控制采样距离
		float _BlurSize;
		  
		struct v2f {
			float4 pos : SV_POSITION;
			half2 uv[5]: TEXCOORD0;
		};
		  
		v2f vertBlurVertical(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			
			half2 uv = v.texcoord;
			
			o.uv[0] = uv;
			o.uv[1] = uv + float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
			o.uv[2] = uv - float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
			o.uv[3] = uv + float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
			o.uv[4] = uv - float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
					 
			return o;
		}
		
		v2f vertBlurHorizontal(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			
			half2 uv = v.texcoord;
			
			o.uv[0] = uv;
			o.uv[1] = uv + float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
			o.uv[2] = uv - float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
			o.uv[3] = uv + float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
			o.uv[4] = uv - float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
					 
			return o;
		}
		
		fixed4 fragBlur(v2f i) : SV_Target {
		    //采样纹理坐标转移到片元中,减少运算,可提高性能,顶点到片元的插值时线性的,不会影响计算结果
			float weight[3] = {0.4026, 0.2442, 0.0545};
			
			fixed3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];
			
			for (int it = 1; it < 3; it++) {
				sum += tex2D(_MainTex, i.uv[it*2-1]).rgb * weight[it];
				sum += tex2D(_MainTex, i.uv[it*2]).rgb * weight[it];
			}
			
			return fixed4(sum, 1.0);
		}
		    
		ENDCG
		
		ZTest Always Cull Off ZWrite Off
		
		Pass {
		    //定义该pass的name 以便于再其他shader中进行调用
			NAME "GAUSSIAN_BLUR_VERTICAL"
			
			CGPROGRAM
		    //指明CGINCLUDE 中的调用方法 
			#pragma vertex vertBlurVertical  
			#pragma fragment fragBlur
			  
			ENDCG  
		}
		
		Pass {  
		
			NAME "GAUSSIAN_BLUR_HORIZONTAL"
			
			CGPROGRAM  
			
			#pragma vertex vertBlurHorizontal  
			#pragma fragment fragBlur
			
			ENDCG
		}
	} 
	FallBack "Diffuse"
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Thredd : RenderDemo
{
    public Shader briSatConShader;
    private Material briSatConMaterial;
    public Material material {  
        get {
            briSatConMaterial = CheckShaderAndCreateMaterial(briSatConShader, briSatConMaterial);
            return briSatConMaterial;
        }  
    }

    //高斯模糊迭代次数 
    [Range(0, 4)] 
    public float iteration = 3;
    //模糊范围 过大会造成虚影
    [Range(0.2f, 3)] 
    public float blurSpread = 0.6f;
    
    //缩放系数 过大需要处理的像素越少,会造成图像像素化
    [Range(1,8)]
    public int downSample=2;
 
    /*private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (material!=null)
        {
            int rtw = src.width;
            int rth = src.height;
            //临时的texture
            RenderTexture buffer = RenderTexture.GetTemporary(rtw, rth, 0);
            //先执行 第一个pass 结果存在临时buffer
            Graphics.Blit(src,buffer,material,0);
            //再执行第二个pass  
            Graphics.Blit(buffer,dest,material,1);
            //释放临时的buffer
            RenderTexture.ReleaseTemporary(buffer);
        }
        else
        {
            Graphics.Blit(src,dest);
        }
        
    }*/
    /*private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (material!=null)
        {
            //对图像进行降采样减少需要处理的像素个数提高性能,
            //除以缩放系数
            int rtw = src.width/downSample;
            int rth = src.height/downSample;
            //临时的texture
            RenderTexture buffer = RenderTexture.GetTemporary(rtw, rth, 0);
            //双线性过滤-将纹理样本平均
            buffer.filterMode = FilterMode.Bilinear;
            //先执行 第一个pass 结果存在临时buffer
            Graphics.Blit(src,buffer,material,0);
            //再执行第二个pass  
            Graphics.Blit(buffer,dest,material,1);
            //释放临时的buffer
            RenderTexture.ReleaseTemporary(buffer);
        }
        else
        {
            Graphics.Blit(src,dest);
        }
        
    }*/
    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (material!=null)
        {
            //对图像进行降采样减少需要处理的像素个数提高性能,
            //除以缩放系数
            int rtw = src.width/downSample;
            int rth = src.height/downSample;
            //临时的texture
            RenderTexture buffer = RenderTexture.GetTemporary(rtw, rth, 0);
            //双线性过滤-将纹理样本平均
            buffer.filterMode = FilterMode.Bilinear;
            Graphics.Blit(src,buffer);
            //迭代模糊次数
            for (int i=0;i<iteration;i++)
            {
                material.SetFloat("_BlueSize",1.0f+ i * blurSpread);
                
                RenderTexture buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
                Graphics.Blit(buffer,buffer0,material,0);
                RenderTexture.ReleaseTemporary(buffer);
                buffer = buffer0;
                
                buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
                Graphics.Blit(buffer,buffer0,material,1);
                RenderTexture.ReleaseTemporary(buffer);
                buffer = buffer0;
            }
            Graphics.Blit(buffer,dest);
            //释放临时的buffer
            RenderTexture.ReleaseTemporary(buffer);
        }
        else
        {
            Graphics.Blit(src,dest);
        }
    }
}

Bloom

让屏幕画面中较亮的区域向外扩散,造成朦胧的效果。原理:设定一个阈值提取图像中较亮区域,把它们存储到一张渲染图中,在进行高斯模糊,模拟光线扩散的效果,最后和原图混合得到最终效果。三个pass : 第一个pass提取较亮的区域,第二和第三个pass进行高斯模糊,第四个pass将高斯模糊后的结果与原图混合。

public class Bloom : RenderDemo{

	public Shader bloomShader;
	private Material bloomMaterial = null;
	public Material material {  
		get {
			bloomMaterial = CheckShaderAndCreateMaterial(bloomShader, bloomMaterial);
			return bloomMaterial;
		}  
	}

	[Range(0, 4)]
	public int iterations = 3;
	
	[Range(0.2f, 3.0f)]
	public float blurSpread = 0.6f;

	[Range(1, 8)]
	public int downSample = 2;
	//提取较亮区域的阈值,开启HDR后,会得到更加精确颜色值,此时像素亮度可能会大于1
	[Range(0.0f, 4.0f)]
	public float luminanceThreshold = 0.6f;

	void OnRenderImage (RenderTexture src, RenderTexture dest) {
		if (material != null) {
			material.SetFloat("_LuminanceThreshold", luminanceThreshold);

			int rtW = src.width/downSample;
			int rtH = src.height/downSample;
			
			RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
			buffer0.filterMode = FilterMode.Bilinear;
			
			Graphics.Blit(src, buffer0, material, 0);
			
			for (int i = 0; i < iterations; i++) {
				material.SetFloat("_BlurSize", 1.0f + i * blurSpread);
				
				RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
				
				Graphics.Blit(buffer0, buffer1, material, 1);
				
				RenderTexture.ReleaseTemporary(buffer0);
				buffer0 = buffer1;
				buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
				
				Graphics.Blit(buffer0, buffer1, material, 2);
				
				RenderTexture.ReleaseTemporary(buffer0);
				buffer0 = buffer1;
			}

			material.SetTexture ("_Bloom", buffer0);  
			Graphics.Blit (src, dest, material, 3);  

			RenderTexture.ReleaseTemporary(buffer0);
		} else {
			Graphics.Blit(src, dest);
		}
	}
}
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unlit/4" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_Bloom ("Bloom (RGB)", 2D) = "black" {}
		_LuminanceThreshold ("Luminance Threshold", Float) = 0.5
		_BlurSize ("Blur Size", Float) = 1.0
	}
	SubShader {
		CGINCLUDE
		
		#include "UnityCG.cginc"
		
		sampler2D _MainTex;
		half4 _MainTex_TexelSize;
		sampler2D _Bloom;
		float _LuminanceThreshold;
		float _BlurSize;
		
		struct v2f {
			float4 pos : SV_POSITION; 
			half2 uv : TEXCOORD0;
		};	
		
		v2f vertExtractBright(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			o.uv = v.texcoord;
			return o;
		}
		//计算得到亮度
		fixed luminance(fixed4 color) {
			return  0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b; 
		}
		//亮度区域
		fixed4 fragExtractBright(v2f i) : SV_Target {
			fixed4 c = tex2D(_MainTex, i.uv);
			//亮度减去阈值==较亮的区域 最终的范围要在0~1之间
			fixed val = clamp(luminance(c) - _LuminanceThreshold, 0.0, 1.0);
			return c * val;
		}
		
		//混合较亮区域
		struct v2fBloom {
			float4 pos : SV_POSITION; 
			half4 uv : TEXCOORD0;
		};
		v2fBloom vertBloom(appdata_img v) {
			v2fBloom o;
			
			o.pos = UnityObjectToClipPos (v.vertex);
			o.uv.xy = v.texcoord;		
			o.uv.zw = v.texcoord;
			
			#if UNITY_UV_STARTS_AT_TOP			
			if (_MainTex_TexelSize.y < 0.0)
				o.uv.w = 1.0 - o.uv.w;
			#endif
				        	
			return o; 
		}
		fixed4 fragBloom(v2fBloom i) : SV_Target {
		    //相加混合原图和bloom图
			return tex2D(_MainTex, i.uv.xy) + tex2D(_Bloom, i.uv.zw);
		} 
		
		ENDCG
		
		ZTest Always Cull Off ZWrite Off
		
		Pass {  
			CGPROGRAM  
			#pragma vertex vertExtractBright  
			#pragma fragment fragExtractBright  
			
			ENDCG  
		}
		
		UsePass "Unlit/3/GAUSSIAN_BLUR_VERTICAL"
		
		UsePass "Unlit/3/GAUSSIAN_BLUR_HORIZONTAL"
		
		Pass {  
			CGPROGRAM  
			#pragma vertex vertBloom  
			#pragma fragment fragBloom  
			
			ENDCG  
		}
	}
	FallBack Off
}

 

运动模糊

相机曝光时,拍摄场景发生变化,就会产生模糊的效果。运动模糊的实现方法:利用一块累计缓存(accumulation buffer)来混合多张连续的图像。当物体快速移动产生多张图像后,取其平均值作为最后的运动模糊图像-----性能消耗大,需要一帧里渲染多次场景。第二种:速度缓存(velocity buffer),这个缓存存储了各个像素当前的运动速度,再利用该值决定模糊的方向和大小。

public class MotionBlur : RenderDemo{

	public Shader motionBlurShader;
	private Material motionBlurMaterial = null;

	public Material material {  
		get {
			motionBlurMaterial = CheckShaderAndCreateMaterial(motionBlurShader, motionBlurMaterial);
			return motionBlurMaterial;
		}  
	}

	[Range(0.0f, 0.9f)]
	//运动模糊参数 越大越模糊
	public float blurAmount = 0.5f;
	
	private RenderTexture accumulationTexture;

	void OnDisable() {
		DestroyImmediate(accumulationTexture);
	}

	void OnRenderImage (RenderTexture src, RenderTexture dest) {
		if (material != null) {
			//是否满足条件 
			if (accumulationTexture == null || accumulationTexture.width != src.width || accumulationTexture.height != src.height) {
				DestroyImmediate(accumulationTexture);
				accumulationTexture = new RenderTexture(src.width, src.height, 0);
				//不会显示在Hierarchy中,也不会保存到场景中,也不会由Resources.UnloadUnusedAssets卸载。
				accumulationTexture.hideFlags = HideFlags.HideAndDontSave;
				//替换渲染图
				Graphics.Blit(src, accumulationTexture);
			}
			//我们正在设计中累积帧的运动而没有清除/丢弃,因此请消除来自Unity的任何性能警告
			//纹理恢复操作,发生在渲染到纹理而纹理有没有提前清空或销毁,
			//不清空纹理,后续进行叠加
			accumulationTexture.MarkRestoreExpected();

			material.SetFloat("_BlurAmount", 1.0f - blurAmount);
            //叠加纹理
			Graphics.Blit (src, accumulationTexture, material);
			Graphics.Blit (accumulationTexture, dest);
		} else {
			Graphics.Blit(src, dest);
		}
	}
}
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unlit/6" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_BlurAmount ("Blur Amount", Float) = 1.0
	}
	SubShader {
		CGINCLUDE
		
		#include "UnityCG.cginc"
		
		sampler2D _MainTex;
		fixed _BlurAmount;
		
		struct v2f {
			float4 pos : SV_POSITION;
			half2 uv : TEXCOORD0;
		};
		
		v2f vert(appdata_img v) {
			v2f o;
			o.pos = UnityObjectToClipPos(v.vertex);
			o.uv = v.texcoord;
			return o;
		}
		//更新RGB通道
		fixed4 fragRGB (v2f i) : SV_Target {
			return fixed4(tex2D(_MainTex, i.uv).rgb, _BlurAmount);
		}
		//跟新Alpha通道 混合图像,不写入渲染纹理中
		half4 fragA (v2f i) : SV_Target {
			return tex2D(_MainTex, i.uv);
		}
		ENDCG
		
		ZTest Always Cull Off ZWrite Off
		Pass {
		    //开启混合
			Blend SrcAlpha OneMinusSrcAlpha
            //只输出RGB
			ColorMask RGB
			CGPROGRAM
			
			#pragma vertex vert  
			#pragma fragment fragRGB  
			
			ENDCG
		}
		
		Pass {   
			Blend One Zero
			//只输出Alpha
			ColorMask A
			CGPROGRAM  
			
			#pragma vertex vert  
			#pragma fragment fragA
			  
			ENDCG
		}
	}
 	FallBack Off
}

https://blog.csdn.net/poem_qianmo/article/details/42060963

 

 

Shader后处理屏幕映射 一、计算屏幕空间坐标 一个模型的MVP变换,即从模型空间(M)转换到观察空间(V)再转换到裁剪空间(P),然后将投影完成的标准立方体通过屏幕映射(视口变换)转换成屏幕坐标进行显示。 下图即标准立方体到屏幕空间的映射过程。 Clip Space → Screen Space的基本方法 v2f vert (appdata v) { o.screen_pos = o.pos; //_ProjectionParams.x用于校正不同平台下的uv坐标... 阅读详情

相关推荐

Unity Shader入门精要学习笔记 - 第12章 屏幕后处理效果

Unity Shader入门精要学习笔记 - 第12章 屏幕后处理效果本系列为UnityShader入门精要读书笔记总结, 原作者博客链接:http://blog.csdn.net/candycat1992/article/ 书籍链接:http://product.dangdang.com/23972910.html第12章 屏幕后处理效果屏幕后处理效果(screen post-process

那远远的云端 3930

Shader】常用后处理Shader总结_1

这篇总结一下常用的后处理Shader,套上主Camera就能让游戏画面效果上升一个Level那种,整容效果等同于美图秀秀的滤镜(并没有!)。 后处理的具体实现原理: 1、先把场景里东西给渲染了 2、把渲染好的屏幕图像“截个屏”(我是主要用OnRenderImage) 3、把刚刚的“截屏”进行处理,再放到屏幕后处理C#脚本基类 首先写一个万用的后处理C#脚本基类PostEffectsBase。来...

糕二不二的博客 2076

Unity Shader 屏幕后处理反相

Shader代码如下: Properties { _MainTex ("Base (RGB)", 2D) = "white" {}//渲染纹理 } SubShader { Pass { ZTest Always Cull Off ZWrite Off CGPROGRAM #include "UnityCG.cginc" #prag...

qq_44800780的博客 1022

Shader入门-------屏幕后处理

Shader入门-------屏幕后处理 前记:需求需要,快速学习--------------------mx 屏幕后处理:通常指在渲染完整个场景得到屏幕图像之后再对这个图像进行一系列操作,实现各种屏幕特效。 Unity中提供一个接口OnRenderImage函数。声明如下:OnRenderImage(RenderTexture src ,RenderTexture dest) Unity会把当前渲染得到的图像存储在第一个参数对应的源渲染纹理中,通过函数中一系列操作后,再把目标渲染纹理,即第二个参数对应的渲

m0_56399931的博客 624

Unity中后处理 脚本 和 Shader

我们在上篇文章中提到,在Unity中实现后处理效果,需要同时结合 脚本 和 Shader,我们在这篇文章中编写所需要使用的C#脚本。

楠溪泽岸的博客 1486

Chapter12 屏幕后处理效果——Shader入门精要学习笔记

概念:在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列操作,实现各种屏幕特效。

weixin_70073176的博客 1101

unity shader屏幕后处理

unity shader屏幕后处理

weixin_46525412的博客 512

利用脚本和Shader制作屏幕后处理效果

Unity会把当前渲染完成后的图像存储在src源渲染纹理中,通过函数中的一系列操作后(该函数内操作是我们自定义的),再把目标渲染纹理存储在dest渲染纹理中,dest最终会被显示到屏幕

2401_83878847的博客 832

(九)unity Shader之——————屏幕后处理效果(原理以及实现一个简单的屏幕后处理效果)

一、建立一个基本的屏幕后处理脚本系统 屏幕后处理,通常指的是在渲染完整个场景得到屏幕图像后,再对这个图像进行一系列的操作,实现各种屏幕特效。可以为游戏画面添加更多的艺术效果,例如景深、运动模糊等。 因此想要实现屏幕后处理的基础在于得到渲染后的屏幕图像,即抓取屏幕,而unity为我们提供了这样一个方便的接口——OnRenderImage函数。它的函数声明如下: MonoBehaviour.On...

cgy56191948的博客 3329

Unity Shader 屏幕后处理灰度

原理: 移除场景中除了黑白灰以外所有的颜色,让整个图像灰度化(Grayscale)。很简单的实现方式是,取所有的颜色分量,将它们平均化,但是但人眼会对绿色更加敏感一些,而对蓝色不那么敏感,所以为了获取物理上更精确的效果,我们需要使用加权的(Weighted)通道: 脚本如下: public Shader shader;//相应的shader private Material ma...

qq_44800780的博客 624

shader入门基础-屏幕后处理效果

在摄像机中添加一个用于屏幕后处理的脚本,在这个脚本中,我们会实现 OnRenderImage 函数来获取当前屏幕的渲染纹理。高斯模糊需要调用两个 Pass,第一个 pass 使用竖直方向一维高斯核进行滤波就,第二个 pass 使用水平方向一维高斯核进行滤波。高斯核的维度越高,模糊的程度越大。不清楚屏幕亮度,饱和度,对比度的定义,这里参考了 csdn 博客,大家可以直接参考 @feilong_csdn。高斯是一个正方形大小的滤波核,其中每个元素的计算都是基于下面的高斯方程。亮度,对比度,饱和度的实现。

lx19900918的专栏 353

Unity3D 屏幕后处理模糊效果Shader

分享一个简易的屏幕后处理,模糊效果的shader实现: Shader "Custom/BlurEffect" { Properties { _MainTex("Main Tex", 2D) = "white"{} _BlurSize("BlurSize", Range(0, 1)) = 1.0 } SubShader { CGINCLUDE #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_ST;

文先生的博客 3577

Unity Shader屏幕后处理 Bloom效果

原理: 首先根据一个阈值提取出图像中较亮的区域,把他们存储在一张渲染纹理中,再利用高斯模糊对这张渲染纹理进行模糊处理,模拟光线扩散效果,最后将其和原图像进行混合,得到最终的结果 脚本实现: 我们要使用4个Pass通道 第一个Pass通道提取较亮的区域,存储起来 第二个Pass通道进行垂直模糊 第三个Pass通道进行水平模糊 第四个Pass通道进行混合 public class Bloom : Po...

qq_44800780的博客 559

Unity Shader屏幕后处理高斯模糊

原理 利用卷积计算,使用的卷积核叫高斯核 使用一个N x N的高斯核对图像进行卷积滤波,就需要N x N x W x H次纹理采样,当N的大小不断增加时,采样次数会变得非常巨大,不过我们可以把这个二维高斯函数拆分成两个一维函数. 得到的结果是一样的。 实现 我们会先后调用两个Pass,第一个Pass使用竖直方向的一维高斯核进行滤波,第二个Pass使用水平方向的一维高斯核,得到最终的目标图像. 首先...

qq_44800780的博客 502

Unity Shader 屏幕后处理调整亮度、饱和度、对比度

在进行屏幕后处理之前,需要检查一系列条件是否满足,比如是否支持渲染纹理和屏幕特效,是否支持当前使用的Unity shader等.所以需要创建一个基类,用来检查: 屏幕后处理基类 using UnityEngine; [ExecuteInEditMode]//ExecuteInEditMode属性的作用是在EditMode下也可以执行脚本 [RequireComponent (typeof(Cam...

qq_44800780的博客 896

Unity Shader屏幕后处理 边缘检测

原理 利用边缘检测算子对图像进行卷积操作 如何知道哪里才算是边缘呢? 如果相邻像素之间存在差别明显的颜色、亮度、纹理等属性,我们就会认为它们之间应该有一条边界。这种相邻像素之间的插值可以用梯度来表示,边缘处的梯度绝对值会比较大. 三种常见的边缘检测算子 它们都包含了两个方向的卷积核,分别用于检测水平方向和竖直方向上的边缘信息,在进行边缘检测时,我们需要对每个像素分别进行一次卷积计算,得到两个方向...

qq_44800780的博客 487

Unity Shader 学习13:屏幕后处理 - 使用高斯模糊的Bloom辉光效果

luminaceThreshold:模糊阈值,它能决定提取亮部的区域范围 iterations:迭代次数,可以对图片进行多次的模糊 blurSpread:每次迭代模糊后,都要对模糊范围 (BlurSize) 进行扩大,其控制每次扩大的速度 blurSize:就是上述的blurSize,其与blurSpread的关系为 1.0f + 迭代次数i * blurSpeed ,加一是为了保证值最小能为1 downSample:对原图进行降采样,也就是降低图片的像素,这样既能优化性能,又能获得更平滑的模糊效果

weixin_63623077的博客 1452

【unity shader 案例】屏幕后处理

unity shader 屏幕全屏变灰

weixin_40967344的博客 273
上一篇: C#--CLR
下一篇: unity--常用物理公式
WCNB
博客等级 码龄9年 15粉丝 87原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值