Unity Shader - 后处理:屏幕水波纹

转载自:https://blog.csdn.net/puppet_master/article/details/52975666

Shader代码:

Shader "Custom/WaterWave"
{
	Properties
	{
		_MainTex("Base (RGB)", 2D) = "white" {}
	}

		CGINCLUDE
#include "UnityCG.cginc"
	uniform sampler2D _MainTex;
	float4 _MainTex_TexelSize;
	uniform float _distanceFactor;	//距离系数
	uniform float _timeFactor;		//时间系数
	uniform float _totalFactor;		//sin函数结果系数

	uniform float _waveWidth;		//波纹宽度
	uniform float _curWaveDis;		//扩散速度
	uniform float4 _startPos;		//开始位置

	fixed4 frag(v2f_img i) : SV_Target
	{
		//DX下纹理坐标反向问题
		//UNITY_UV_STARTS_AT_TOP总是用1或0定义,Direct3D平台为1,OpenGL平台为0
		//在Direct3D中,坐标顶点为零,向下增加
		//OpenGL坐标底部为零,向上增加
#if UNITY_UV_STARTS_AT_TOP
		if (_MainTex_TexelSize.y < 0)
		_startPos.y = 1 - _startPos.y;
#endif
	//计算uv到中间点的向量(向外扩,反过来就是向里缩)
	float2 dv = _startPos.xy - i.uv;
	//按照屏幕长宽比进行缩放
	dv = dv * float2(_ScreenParams.x / _ScreenParams.y, 1);
	//计算像素点距中点的距离
	float dis = sqrt(dv.x * dv.x + dv.y * dv.y);
	//用sin函数计算出波形的偏移值factor
	//dis在这里都是小于1的,所以我们需要乘以一个比较大的数,比如60,这样就有多个波峰波谷
	//sin函数是(-1,1)的值域,我们希望偏移值很小,所以这里我们缩小100倍,据说乘法比较快,so...
	float sinFactor = sin(dis * _distanceFactor + _Time.y * _timeFactor) * _totalFactor * 0.01;
	//距离当前波纹运动点的距离,如果小于waveWidth才予以保留,否则已经出了波纹范围,factor通过clamp设置为0
	float discardFactor = clamp(_waveWidth - abs(_curWaveDis - dis), 0, 1) / _waveWidth;
	//归一化
	float2 dv1 = normalize(dv);
	//计算每个像素uv的偏移值
	float2 offset = dv1  * sinFactor * discardFactor;
	//像素采样时偏移offset
	float2 uv = offset + i.uv;
	return tex2D(_MainTex, uv);
	}
		ENDCG

		SubShader
	{
		Pass
		{
			ZTest Always
			Cull Off
			ZWrite Off
			Fog{ Mode off }

			CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest 
			ENDCG
		}
	}
	Fallback off
}

C#代码(挂载在Camera上):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//非运行时也出发效果
[ExecuteInEditMode]
public class WaterWave : MonoBehaviour {

    //Inspector面板上直接拖入
    public Shader shader = null;
    private Material _material = null;

    //距离系数
    public float distanceFactor = 60.0f;
    //时间系数
    public float timeFactor = -30.0f;
    //sin函数结果系数
    public float totalFactor = 1.0f;

    //波纹宽度
    public float waveWidth = 0.3f;
    //波纹扩散的速度
    public float waveSpeed = 0.3f;

    private float waveStartTime;
    private Vector4 startPos = new Vector4(0.5f, 0.5f, 0, 0);

    //根据Shader生成材质
    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;
    }

    void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        //计算波纹移动的距离,根据enable到目前的时间*速度求解
        float curWaveDistance = (Time.time - waveStartTime) * waveSpeed;
        //设置一系列参数
        _Material.SetFloat("_distanceFactor", distanceFactor);
        _Material.SetFloat("_timeFactor", timeFactor);
        _Material.SetFloat("_totalFactor", totalFactor);
        _Material.SetFloat("_waveWidth", waveWidth);
        _Material.SetFloat("_curWaveDis", curWaveDistance);
        _Material.SetVector("_startPos", startPos);
        Graphics.Blit(source, destination, _Material);
    }

    void Update()
    {
        if (Input.GetMouseButton(0))
        {
            Vector2 mousePos = Input.mousePosition;
            //将mousePos转化为(0,1)区间
            startPos = new Vector4(mousePos.x / Screen.width, mousePos.y / Screen.height, 0, 0);
            waveStartTime = Time.time;
        }
    }
}

效果图:

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值