ShaderLab實現Vignette過場動畫效果
實現Vignette過場動畫效果
postprocessing中有漸暈效果(Vignette),鏡頭可以由邊緣往中間慢慢變黑;
但是我打包WebGL的時候提示我postprocessing,GPU不支持…
so,用shaderlab實現了簡單的效果,如果需要邊緣模糊,就根據距離做透明度插值;
以下是效果展示:
PostEffectsBase
提供公共方法,所有的postprocess後期效果都繼承該類;
Start方法中檢查設備是否支持後期效果;
CheckShaderAndCreateMaterial方法檢測是否支持shader,支持則創建並返回該shader的對應材質;
[ExecuteInEditMode]
[RequireComponent (typeof(Camera))]
public class PostEffectsBase : MonoBehaviour {
// Called when start
protected void CheckResources() {
bool isSupported = CheckSupport();
if (isSupported == false) {
NotSupported();
}
}
// Called in CheckResources to check support on this platform
protected bool CheckSupport() {
if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false) {
Debug.LogWarning("This platform does not support image effects or render textures.");
return false;
}
return true;
}
// Called when the platform doesn't support this effect
protected void NotSupported() {
enabled = false;
}
protected virtual void Start() {
CheckResources();
}
// Called when need to create the material used by this effect
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;
}
}
}
MyVignette
根據屏幕大小,在shader的着色階段,判斷片元離屏幕中心距離和預設的半徑比較,超過的全部設置成黑色(或其他);
預設半徑最大值為屏幕對角線的一半;
Unity屏幕(0,0)點左下角;
溫馨提示:如果要同時覆蓋UI,canvas的模式不能是overlay,必須改成Camera,同時UI相機要為該腳本掛載的相機;
OnRenderImage(RenderTexture source, RenderTexture destination)
該方法為MonoBehaviour生命周期,會將屏幕渲染結果source返回,函數結束會將destination顯示在屏幕上;
Graphics.Blit(source, destination, material,pass)
將source經過材質material處理後,返回destination;
pass默認為-1,計算所有pass;否則只調用索引值;
public class MyVignette : PostEffectsBase
{
public Shader vignetteShader;
private Material vignetteMaterial;
[Range(0, 1)] public float radio = 1;
public Color circleColor = Color.black;
public Vector2 screenSize;
protected override void Start()
{
base.Start();
screenSize = FindObjectOfType<CanvasScaler>().referenceResolution;
material.SetColor("_Color", circleColor);
//計算屏幕對角線一半的長度
float temp = Mathf.Sqrt(screenSize.x * screenSize.x + screenSize.y * screenSize.y)/2;
material.SetFloat("_ScreenSize", temp);
material.SetVector("_CenterPos", screenSize/2);
}
public Material material
{
get {
vignetteMaterial = CheckShaderAndCreateMaterial(vignetteShader, vignetteMaterial);
return vignetteMaterial;
}
}
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (material != null)
{
material.SetFloat("_Radio", radio);
Graphics.Blit(source, destination, material);
}
else
Graphics.Blit(source, destination);
}
}
VignetteShader
_MainTex 接收屏幕紋理
_Radio 接收半徑變動
在MyVignette類中給Shader屬性賦值,所以其實Properties中可以不用寫(不用在材質中看這些值),直接pass中聲明;
Shader "VignetteShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Radio("Radio",Range(0,1.0)) = 1.0
_ScreenSize("ScreenSize",Float) = 735
_CenterPos("CenterPos",vector) = (640,360,1)
_Color("CircleColor",Color) = (0,0,0,1)
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
fixed _Radio;
fixed _ScreenSize;
float4 _CenterPos;
float4 _Color;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
//減少開方操作
float temp = (i.vertex.x - _CenterPos.x)* (i.vertex.x - _CenterPos.x)+(i.vertex.y-_CenterPos.y)*(i.vertex.y-_CenterPos.y);
_ScreenSize = _ScreenSize*_Radio;
if(temp>_ScreenSize*_ScreenSize)
col = _Color;
return col;
}
ENDCG
}
}
}
使用
主相機上掛在MyVigentte腳本,給MyVigentte參數賦值,將VignetteShader拖到MyVigentte中shader變量;
通過CanvasScaler獲取屏幕寬高,Canvas的RenderMode設置成Screen Space-Camera;
代碼修改MyVignette中Radio的值,就可以實現圓鏡頭效果;