313 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
## BrightnessSaturationAndContrast
 | 
						||
### 给摄像机添加脚本
 | 
						||
添加2个Meta,让其可以在编辑器模式下运行,并且只能绑定Camera组件。
 | 
						||
```
 | 
						||
[ExecuteInEditMode]
 | 
						||
[RequireComponent(typeof(Camera))]
 | 
						||
```
 | 
						||
实现基础类
 | 
						||
```
 | 
						||
using UnityEngine;
 | 
						||
 | 
						||
[ExecuteInEditMode]
 | 
						||
[RequireComponent(typeof(Camera))]
 | 
						||
public class PostEffectsBase : MonoBehaviour
 | 
						||
{
 | 
						||
    protected void CheckResources()
 | 
						||
    {
 | 
						||
        bool isSupported = CheckSupport();
 | 
						||
 | 
						||
        if (isSupported == false)
 | 
						||
        {
 | 
						||
            NotSupported();
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    protected bool CheckSupport()
 | 
						||
    {
 | 
						||
        if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false)
 | 
						||
        {
 | 
						||
            Debug.LogWarning("Not Supported!");
 | 
						||
            return false;
 | 
						||
        }
 | 
						||
        return true;
 | 
						||
    }
 | 
						||
 | 
						||
    protected void NotSupported()
 | 
						||
    {
 | 
						||
        enabled = false;
 | 
						||
    }
 | 
						||
 | 
						||
    protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
 | 
						||
    {
 | 
						||
        if (shader == null)
 | 
						||
            return null;
 | 
						||
        if (shader.isSupported && material && material.shader == shader)
 | 
						||
            return material;
 | 
						||
        if (!shader.isSupported)
 | 
						||
            return null;
 | 
						||
        else
 | 
						||
        {
 | 
						||
            material = new Material(shader);
 | 
						||
            material.hideFlags = HideFlags.DontSave;
 | 
						||
            if (material)
 | 
						||
                return material;
 | 
						||
            else
 | 
						||
                return null;
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    protected void Start()
 | 
						||
    {
 | 
						||
        CheckResources();
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
```
 | 
						||
之后根据需求在子类中添加变量:
 | 
						||
```
 | 
						||
using UnityEngine;
 | 
						||
 | 
						||
public class BrightnessSaturationAndContrast : PostEffectsBase
 | 
						||
{
 | 
						||
    [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;
 | 
						||
 | 
						||
    public Shader briSatConShader;
 | 
						||
    private Material briSatConMaterial;
 | 
						||
 | 
						||
    public Material material
 | 
						||
    {
 | 
						||
        get
 | 
						||
        {
 | 
						||
            briSatConMaterial = CheckShaderAndCreateMaterial(briSatConShader, briSatConMaterial);
 | 
						||
            return briSatConMaterial;
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    private 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);
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 | 
						||
```
 | 
						||
最后在OnRenderImage中调用Graphics.Blit()进行渲染。
 | 
						||
 | 
						||
### 添加后处理Shader
 | 
						||
```
 | 
						||
Shader "PostProcess/BrightnessSaturationAndContrast" {
 | 
						||
	
 | 
						||
	Properties {
 | 
						||
		_MainTex ("Base", 2D) = "white" {}
 | 
						||
        _Brightness("Brightness",Float)=1
 | 
						||
        _Saturation("Saturation",Float)=1
 | 
						||
        _Contrast("Constrast",Float)=1
 | 
						||
    }
 | 
						||
 | 
						||
	SubShader {
 | 
						||
        Pass{
 | 
						||
            ZTest Always Cull Off ZWrite Off
 | 
						||
 | 
						||
            CGPROGRAM
 | 
						||
            #pragma vertex vert
 | 
						||
            #pragma fragment frag
 | 
						||
 | 
						||
            #include "UnityCG.cginc"
 | 
						||
 | 
						||
            sampler2D _MainTex;
 | 
						||
            half _Brightness;
 | 
						||
            half _Saturation;
 | 
						||
            half _Contrast;
 | 
						||
 | 
						||
            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;
 | 
						||
            }
 | 
						||
 | 
						||
            fixed4 frag(v2f i) : SV_Target{
 | 
						||
                fixed4 renderTex=tex2D(_MainTex,i.uv);
 | 
						||
 | 
						||
                fixed3 finalColor=renderTex.rgb * _Brightness;
 | 
						||
                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);
 | 
						||
 | 
						||
                fixed3 avgColor=fixed3(0.5,0.5,0.5);
 | 
						||
                finalColor=lerp(avgColor,finalColor,_Contrast);
 | 
						||
                return fixed4(finalColor,renderTex.a);
 | 
						||
            }
 | 
						||
 | 
						||
            ENDCG
 | 
						||
        }
 | 
						||
    }
 | 
						||
    Fallback Off
 | 
						||
}
 | 
						||
```
 | 
						||
 | 
						||
## 高斯模糊
 | 
						||
 | 
						||
与之前不同,这里利用RenderTexture.GetTemporary函数分配了一块与屏幕图像大小相同的缓冲区。这是因为,高斯模糊需要调用两个Pass,我们需要使用一块中间缓存来存储第一个Pass执行完毕后得到的模糊结果。`RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);`我们首先调用`Graphics.Blit(src, buffer, material, 0),`使用Shader中的第一个pass对src进行处理,并将结果存储在了buffer中。然后在调用`Graphics.Blit(src, buffer, material, 1)`,使用Shader中的第二个Pass对buffer进行处理,返回最终的屏幕图像。最后,我们还需要调用`RenderTexture.ReleaseTemporary`来释放之前分配的缓存。
 | 
						||
 | 
						||
```
 | 
						||
private void OnRenderImage(RenderTexture src, RenderTexture dest)
 | 
						||
{
 | 
						||
    if (material != null)
 | 
						||
    {
 | 
						||
        int rtW = src.width;
 | 
						||
        int rtH = src.height;
 | 
						||
        RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);
 | 
						||
 | 
						||
        Graphics.Blit(src, buffer, material, 0);
 | 
						||
        Graphics.Blit(buffer, dest, material, 1);
 | 
						||
 | 
						||
        RenderTexture.Release(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;
 | 
						||
        RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH, 0);
 | 
						||
        buffer.filterMode=FilterMode.Bilinear;
 | 
						||
 | 
						||
        Graphics.Blit(src, buffer, material, 0);
 | 
						||
        Graphics.Blit(buffer, dest, material, 1);
 | 
						||
 | 
						||
        RenderTexture.Release(buffer);
 | 
						||
    }
 | 
						||
    else
 | 
						||
    {
 | 
						||
        Graphics.Blit(src, dest);
 | 
						||
    }
 | 
						||
}
 | 
						||
```
 | 
						||
### CGINCLUDE
 | 
						||
使用CGINCLUDE与ENDCG关键字将通用部分引用给其他Pass
 | 
						||
```
 | 
						||
Shader "Unity Shaders Book/Chapter 12/Gaussian Blur" {
 | 
						||
	Properties {
 | 
						||
		_MainTex ("Base (RGB)", 2D) = "white" {}
 | 
						||
		_BlurSize ("Blur Size", Float) = 1.0
 | 
						||
	}
 | 
						||
	SubShader {
 | 
						||
		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 = mul(UNITY_MATRIX_MVP, 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 = mul(UNITY_MATRIX_MVP, 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 {
 | 
						||
			NAME "GAUSSIAN_BLUR_VERTICAL"
 | 
						||
			
 | 
						||
			CGPROGRAM
 | 
						||
			  
 | 
						||
			#pragma vertex vertBlurVertical  
 | 
						||
			#pragma fragment fragBlur
 | 
						||
			  
 | 
						||
			ENDCG  
 | 
						||
		}
 | 
						||
		
 | 
						||
		Pass {  
 | 
						||
			NAME "GAUSSIAN_BLUR_HORIZONTAL"
 | 
						||
			
 | 
						||
			CGPROGRAM  
 | 
						||
			
 | 
						||
			#pragma vertex vertBlurHorizontal  
 | 
						||
			#pragma fragment fragBlur
 | 
						||
			
 | 
						||
			ENDCG
 | 
						||
		}
 | 
						||
	} 
 | 
						||
	FallBack "Diffuse"
 | 
						||
}
 | 
						||
 | 
						||
``` |