【Unity Shader入门精要学习】高级(一)
2019-11-04 本文已影响0人
小王子称号发放NPC
屏幕后处理效果
屏幕后处理效果(screen post-processing effects),是游戏中实现屏幕特效的常见方法。屏幕后处理,顾名思义,通常指的是在渲染完整个场景得到屏幕图像后,在对这个图像进行一系列操作,实现各种屏幕特效,如景深(Depth of Field),运动模糊(Motion Blur)。
void OnRenderImage(RenderTexture src, RenderTexture dest)
因此,想要实现屏幕后处理的基础在于得到渲染后的屏幕图像,Unity提供了方便的接口——OnRenderImage(只在摄像机脚本中生效),在OnRenderImage函数中,经常使用Graphics.Blit函数来完成对渲染纹理的处理:
public static void Blit(Texture source, RenderTexture dest);
public static void Blit(Texture source, RenderTexture dest, Material mat, int pass = -1);
public static void Blit(Texture source, Material mat, int pass = -1);
public static void Blit(Texture source, RenderTexture dest, Vector2 scale, Vector2 offset);
public static void Blit(Texture source, RenderTexture dest, int sourceDepthSlice, int destDepthSlice);
public static void Blit(Texture source, Material mat, int pass, int destDepthSlice);
public static void Blit(Texture source, RenderTexture dest, Vector2 scale, Vector2 offset, int sourceDepthSlice, int destDepthSlice);
在默认情况下,OnRenderImage函数会在所有不透明和透明的Pass执行完毕后被调用,以便对场景中所有游戏对象都产生影响。但有时,我们希望在不透明的Pass(即渲染队列小于等于2500的Pass,内置的Background、Geometry和AlphaTest渲染队列均在此范围内)执行完毕后立即调用OnRenderImage,从而不对透明物体产生任何影响。此时可以在OnRenderImage函数前添加ImageEffectOpaque属性来实现这样的目的:
[ImageEffectOpaque]
private void OnRenderImage(RenderTexture src, RenderTexture dest)
调整屏幕的亮度,饱和度,对比度
调整前调整后
摄像机脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class PostEffectsBase : MonoBehaviour
{
protected Material CheckShaderAndCreateMaterial(Shader shader, Material material)
{
if (shader == null || !shader.isSupported)
{
return null;
}
if (shader.isSupported && material && material.shader == shader)
{
return material;
}
material = new Material(shader);
material.hideFlags = HideFlags.DontSave;
if (material)
{
return material;
}
else
{
return null;
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BrightnessSaturationContrast : PostEffectsBase
{
public Shader briSatConShader;
protected 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;
[ImageEffectOpaque]
private void OnRenderImage(RenderTexture src, RenderTexture dest)
{
// Debug.Log("BrightnessSaturationContrast OnRenderImage");
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
Shader "Unlit/BrightnessSaturationConstrat"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Brightness("Brightness",float)=1
_Saturation("Saturation",float)=1
_Contrast("Contrast",float)=1
}
SubShader
{
//下面三项是屏幕后处理标配
ZTest Always
Cull Off
ZWrite Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 pos: SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Brightness;
float _Saturation;
float _Contrast;
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 finalCol = renderTex.rgb * _Brightness;
fixed luminance = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
fixed3 luminanceColor = fixed3(luminance, luminance, luminance);
finalCol = lerp(luminanceColor,finalCol,_Saturation);
fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
finalCol = lerp(avgColor, finalCol, _Contrast);
return fixed4(finalCol, renderTex.a);
}
ENDCG
}
}
}