Unity Shader学习:收缩、螺旋

Unity Shader学习:收缩、螺旋

这个效果老酷了,主要数学知识稍微涉及到点,详细原理可以看puppet_master的原文,大致实现了下,有需要的朋友可以看看。

扭曲效果基本原理:根据数学公式改变uv偏移,再叠加噪声偏移模糊场景。

效果图:
Unity Shader学习:收缩、螺旋_第1张图片
Unity Shader学习:收缩、螺旋_第2张图片
Unity Shader学习:收缩、螺旋_第3张图片
C#部分:

//屏幕后处理基类
using UnityEngine;
using System.Collections;

//非运行时也触发效果
[ExecuteInEditMode]
//屏幕后处理特效一般都需要绑定在摄像机上
[RequireComponent(typeof(Camera))]
//提供一个后处理的基类,主要功能在于直接通过Inspector面板拖入shader,生成shader对应的材质
public class PostEffectBase : MonoBehaviour
{

    //Inspector面板上直接拖入
    public Shader shader = null;
    private Material _material = null;
    public Material _Material
    {
        get
        {
            if (_material == null)
                _material = GenerateMaterial(shader);
            return _material;
        }
    }

    //根据shader创建用于屏幕特效的材质
    protected Material GenerateMaterial(Shader shader)
    {
        if (shader == null)
            return null;
        //需要判断shader是否支持
        if (shader.isSupported == false)
            return null;
        Material material = new Material(shader);
        material.hideFlags = HideFlags.DontSave;
        if (material)
            return material;
        return null;
    }

}
//挂在摄像机
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TimeWrapPostEffect : PostEffectBase {
    //扭曲系数
    public float distortFactor;
    //噪声系数
    public float noiseFactor;
    //噪声图
    public Texture noiseTex;
    //效果时长
    public float effectTime;
    //当前进行了时长
    private float currentTime;
    //扭曲曲线系数
    public float scaleCurveFactor;
    //扭曲曲线
    public AnimationCurve scaleCurve;
    //噪声曲线系数
    public float noiseCurveFactor;
    //噪声曲线
    public AnimationCurve noiseCurve;

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (_Material)
        {
            _Material.SetTexture("_NoiseTex", noiseTex);
            _Material.SetFloat("_DistortFactor", distortFactor);
            _Material.SetFloat("_NoiseFactor", noiseFactor);
            Graphics.Blit(source, destination, _Material);
        }
        else
        {
            Graphics.Blit(source, destination);
        }
    }

    //组件直接右键Play就能运行
    [ContextMenu("Play")]
    public void StartEffect()
    {
        currentTime = 0.0f;
        StartCoroutine(WrapEffect());
    }

    IEnumerator WrapEffect()
    {
        while (currentTime<effectTime)
        {
            currentTime += Time.deltaTime;
            //计算系数=曲线值*曲线系数
            distortFactor = scaleCurve.Evaluate(currentTime / effectTime) * scaleCurveFactor;
            noiseFactor = noiseCurve.Evaluate(currentTime / effectTime) * noiseCurveFactor;
            yield return null;            
        }
        distortFactor = 0.0f;
        noiseFactor = 0.0f;
    }
}

Shader部分:

//屏幕扭曲
Shader "Custom/TimeWrap" {
	Properties {
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
	    _NoiseTex("NoiseTex",2D)="white"{}
	}
		CGINCLUDE
		sampler2D _MainTex;
	    sampler2D _NoiseTex;
		//扭曲系数
	    float _DistortFactor;
		//噪声扰动系数
	    float _NoiseFactor;
        #include "UnityCG.cginc"

    //收缩效果片元函数
	float4 frag_distort(v2f_img i) :SV_Target{
		//获取中心点到像素的向量
		float2 dir = i.uv- float2(0.5,0.5);
		//扭曲偏移值=扭曲系数*向量方向的反比(越近扭曲越大)
		float2 scaleOffest = _DistortFactor * normalize(dir)*(1 - length(dir));
		float4 noise = tex2D(_NoiseTex, i.uv);
		//噪声的扰动偏移(噪声颜色rg通道映射到-1,1区间,再乘以方向,越远噪声越大)
		float2 noiseOffset = (noise.xy - float2(0.5, 0.5)) * 2 *_NoiseFactor*dir;
		//偏移叠加
		float2 offset = scaleOffest + noiseOffset;
		float2 uv = i.uv + offset;
		return tex2D(_MainTex, uv);
	}

	//漩涡效果片元函数
	float4 frag_rotate(v2f_img i) :SV_Target{
		//将uv原点放到屏幕中心
		float2 dir = i.uv - float2(0.5,0.5);
		//获取中心点到像素的向量
		float2 dir1 = i.uv - float2(0.5, 0.5);
		//旋转角度=3.14/180再处以向量长度(越远旋转越小)
		float rot = _DistortFactor * 0.1745 / (length(dir1) + 0.1);
		float sinValue;
		float cosValue;
		//输入角度输出sin和cos值
		sincos(rot, sinValue, cosValue);
		//旋转矩阵
		float2x2 rotMatrix = float2x2(cosValue, -sinValue, sinValue, cosValue);
		//绕uv原点(现在在屏幕中心)旋转(行向量)
		dir = mul(dir, rotMatrix);
		//将uv原点返回uv原点
		dir += float2(0.5, 0.5);
		float4 noise = tex2D(_NoiseTex, i.uv);
		//噪声扰动
		float2 noiseOffset = (noise.xy-float2(0.5,0.5))*2*_NoiseFactor*dir1;
		//已经旋转过的uv和噪声偏移
		float2 uv = dir + noiseOffset;
		return tex2D(_MainTex, uv);
	}
		ENDCG

		SubShader{
		Pass{
		ZTest Off
				Cull Off
				Zwrite Off
				Fog{Mode off}
				CGPROGRAM
                #pragma vertex vert_img
			    //自行选择用哪个片元函数
                #pragma fragment frag_distort
				ENDCG
		}	
	}
	FallBack "Diffuse"
}

你可能感兴趣的:(Unity,Shader)