话不多说,先上效果图:
没做动图,大致效果也就是从一个完整的画面逐渐呈圆形缩放至指定大小,最后再放大为一个完整画面的效果。
大概的思路就是,在shader中设置一个固定的uv坐标为圆心,设置一个可变的半径_Radius。然后在C#中动态为_Radius赋值。
然后在shader内通过判断当前传入的uv坐标和圆心坐标的关系,距离大于半径_Radius,则设置目标颜色为纯黑(第一次写shader,不晓得这么说对不对。。。):
至于上图的_ScreenParams.x /和_ScreenParams.y,暂时没搞清楚什么意思,但是不这么写。圆就会被拉伸为椭圆
= =。
最后呢,unity会调用自带的API:OnRenderImage(RenderTexture source, RenderTexture destination),将源贴图向目标贴图进行融合,这个过程是unity自己去调用的。我们不需要手动调用。
具体的使用方法就是,讲下面的脚本挂载到主相机就ok。
刚开始写博客,难免吧啦吧啦说一堆废话,多担待,多担待。。
C#脚本:
using UnityEngine;
using System.Collections;
public class SceneFadeInOut : MonoBehaviour
{
public static SceneFadeInOut Instance;
public Material ma;
public float ChangeSpeed = 1.0f;
public float waitTime = 0.8f;
private float count;
private void Awake()
{
Instance = this;
}
// Use this for initialization
void Start()
{
if (ma == null)
{
ma = new Material(Shader.Find("MyShader/BlackScreen"));
}
}
//测试效果的代码,可以忽略
private void Update()
{
//if (Input.GetKeyDown(KeyCode.Space))
//{
// StartCoroutine(ChangeEffect());
//}
}
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
Graphics.Blit(source, destination, ma);
}
IEnumerator ChangeEffect()
{
while (ma.GetFloat("_Radius") >= 0)
{
count = ma.GetFloat("_Radius") - ChangeSpeed * Time.deltaTime;
//count = count <= 0 ? 0 : count;
ma.SetFloat("_Radius", count);
yield return 0;
}
yield return new WaitForSeconds(waitTime);
while (ma.GetFloat("_Radius") <= 1.5)
{
count = ma.GetFloat("_Radius") + ChangeSpeed * Time.deltaTime;
//count = count >= 1 ? 1 : count;
ma.SetFloat("_Radius", count);
yield return 0;
}
yield return 0;
}
}
Shader:
Shader "MyShader/BlackScreen" {
Properties
{
_Color("Main Color", Color) = (1,1,1,1)
_ChangeFloat("改变颜色",Range(0,1)) = 1.0
_MainTex("Base (RGB)", 2D) = "white" {}
_Radius("Radius",float)=1.5
_Center_X("Center_X", float) =0.95
_Center_Y("Center_Y", float) = 0.5
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _Color;
sampler2D _MainTex;
float1 _ChangeFloat;
float _Radius;
float _Center_X;
float _Center_Y;
float4 frag(v2f_img i) : COLOR
{
float x = i.uv.x*(_ScreenParams.x / _ScreenParams.y);
float y = i.uv.y;
float dis = sqrt((x - _Center_X)*(x - _Center_X) + (y - _Center_Y)*(y - _Center_Y));
if (dis>_Radius)
{
float4 col = (0, 0, 0, 0);
return col;
}
return tex2D(_MainTex, i.uv);
}
ENDCG
}
}
Fallback off
}
代码是有参考他人的,一时半会找不到链接了,尴尬。
总之感谢他们。。。
最后,动态设置上述的圆心坐标,可以实现追光灯的效果,具体实现,待我去研究一下。。
--------------------------------------------------分割线-----------------------------------------------------
其实frag函数内没必要用if判断的,而且改成下面的实现方法,会有边缘平滑渐变的一个效果,看起来更舒服些:
float dis = sqrt((x - _Center_X)*(x - _Center_X) + (y - _Center_Y)*(y - _Center_Y));
float t = _Radius - dis;
float rt = 0.5f + _tanh(t * _Sharp) * 0.5f;
float col = float4(rt, rt, rt, rt);
return tex2D(_MainTex, i.uv) * col;
--------------------------------------------------分割线-----------------------------------------------------
修改后的shader:
Shader "MyShader/BlackScreen" {
Properties
{
_Color("Main Color", Color) = (1,1,1,1)
_ChangeFloat("改变颜色",Range(0,1)) = 1.0
_MainTex("Base (RGB)", 2D) = "white" {}
_Radius("Radius",float)=1.5
_Center_X("Center_X", float) =0.5
_Center_Y("Center_Y", float) =0.5
_Sharp("Sharp", float) = 10.0
}
SubShader
{
Pass
{
ZTest Always Cull Off ZWrite Off
Fog{ Mode off }
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "UnityCG.cginc"
fixed4 _Color;
sampler2D _MainTex;
float1 _ChangeFloat;
float _Radius;
float _Center_X;
float _Center_Y;
float _Sharp;
float _tanh(float x)
{
return 2.0f / (1.0f + exp(-2.0f * x)) - 1.0f;
}
float4 frag(v2f_img i) : COLOR
{
_Center_X=_Center_X*(_ScreenParams.x / _ScreenParams.y);
float x = i.uv.x*(_ScreenParams.x / _ScreenParams.y);
float y = i.uv.y;
float dis = sqrt((x - _Center_X)*(x - _Center_X) + (y - _Center_Y)*(y - _Center_Y));
float t = _Radius - dis;
float rt = 0.5f + _tanh(t * _Sharp) * 0.5f;
float col = float4(rt, rt, rt, rt);
return tex2D(_MainTex, i.uv) * col;
}
ENDCG
}
}
Fallback off
}