首页 > 其他分享 >【Unity3D】水波特效

【Unity3D】水波特效

时间:2023-03-21 10:04:21浏览次数:53  
标签:Unity3D 质点 特效 值越 float waveMaterial 水波

1 水波特效原理

​ 水波特效属于 Unity3D 后处理特效,其原理是:对渲染后的纹理进行局部挤压和拉升变换,即对局部 uv 坐标进行周期性的偏移运动,实现波纹效果。

1)波形方程

​ 为简化水波模型,我们假设水波以机械波(正弦或余弦)传播,并且 0 时刻的水面波形函数为:

​ 其中,r 是质点距离水波中心的半径长度,w1 是波形角频率(值越大,波纹越密),A 是质点水平振动的振幅,offset 是质点的水平偏移量。

2)振动方程

​ t 时刻,半径为 r 的质点水平偏移量为:

​ 其中,w2 是质点水平振动的角频率(值越大,质点振动越快)。

​ 本文代码资源见:Unity3D水波特效

2 代码实现

​ WaterWaveEffect.cs

using UnityEngine;
 
[RequireComponent(typeof(Camera))]  // 屏幕后处理特效一般都需要绑定在像机上
public class WaterWaveEffect : MonoBehaviour {
    public float A = 0.01f; // 水面质点水平波动振幅
    public float w1 = 60; // 水波截面波形角频率(值越大, 波纹越密)
    public float w2 = 30; // 水面质点水平波动角频率(值越大, 水波质点振动越快)
    public float waveWidth = 0.3f; // 水波宽度(水波在扩散时, 后波会消失)
    public float waveSpeed = 0.3f; // 水波传播的速度
    private float waveTime; // 水波传播时间
    private Vector4 waveCenter; // 水波中心
    private Material waveMaterial; // 水波材质
    private bool enabledWave = false; // 水波开关
 
    private void Awake() {
        waveMaterial = new Material(Shader.Find("Custom/WaterWave"));
        waveMaterial.hideFlags = HideFlags.DontSave;
    }

    private void Update() {
        if (Input.GetMouseButton(0)) {
            waveCenter = new Vector2(Input.mousePosition.x / Screen.width, Input.mousePosition.y / Screen.height); // 屏幕坐标归一化
            enabledWave = true;
            waveTime = 0;
        }
    }

    void OnRenderImage (RenderTexture source, RenderTexture destination) {
        if (enabledWave) {
            SetWaveMaterialParams();
            Graphics.Blit (source, destination, waveMaterial);
            waveTime += Time.deltaTime;
            if (waveTime > 2 / waveSpeed) { // 水波传播到屏幕外面, 结束水波特效
                enabledWave = false;
            }
        } else {
            Graphics.Blit (source, destination);
        }
	}

    private void SetWaveMaterialParams() { // 设置水波材质参数
        waveMaterial.SetFloat("_A", A); // 水面质点水平波动振幅
        waveMaterial.SetFloat("_w1", w1); // 水波截面波形角频率(值越大, 波纹越密)
        waveMaterial.SetFloat("_w2", w2); // 水面质点水平波动角频率(值越大, 水波质点振动越快)
        waveMaterial.SetFloat("_t", waveTime); // 水波传播时间
        waveMaterial.SetVector("_o", waveCenter); // 水波中心
        waveMaterial.SetFloat("_waveDist", waveTime * waveSpeed); // 水波传播距离
        waveMaterial.SetFloat("_waveWidth", waveWidth); // 水波宽度(水波在传播时, 后波会消失)
    }
}

​ 说明:WaterWaveEffect 脚本组件需要挂在相机下。

​ WaveShader.shader

Shader "Custom/WaterWave" 
{
	Properties 
	{
		_MainTex ("mainTex", 2D) = "white" {}
	}
 
	SubShader 
	{
		Pass
		{
			ZTest Always
			Cull Off
			ZWrite Off
			Fog { Mode off }
 
			CGPROGRAM

			#pragma vertex vert_img // UnityCG.cginc中定义了vert_img方法, 对vertex和texcoord进行了处理, 输出v2f_img中的pos和uv
			#pragma fragment frag
			#pragma fragmentoption ARB_precision_hint_fastest

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float _A; // 水面质点水平波动振幅
            float _w1; // 水波截面波形角频率(值越大, 波纹越密)
            float _w2; // 水面质点水平波动角频率(值越大, 水波质点振动越快)
            float _t; // 水波传播时间
            float2 _o; // 水波中心坐标
            float _waveDist; // 水波传播距离
            float _waveWidth; // 水波宽度(水波在传播时, 后波会消失)

            fixed4 frag(v2f_img i) : SV_Target // 水波uv坐标的计算不能在顶点着色器中进行, 因为屏后处理的顶点只有屏幕的4个角顶点
            {
                float2 vec = i.uv - _o.xy;
                vec.x *= _ScreenParams.x / _ScreenParams.y; // 按照屏幕长宽比进行缩放
                float radius = length(vec); // 距离波中心的半径长度
                float leng = abs(radius - _waveDist);
                float offset = 0;
                if (leng < _waveWidth)
                {
                    offset = _A * sin(_w1 * radius - _w2 * _t) * (1 - leng / _waveWidth);
                }
                return tex2D(_MainTex, i.uv + offset * 0.707); // offset是一维的, uv是二维的, 需要除以根号2, 即乘以0.707
            }

			ENDCG
		}
	}

	Fallback off
}

3 运行效果

​ 点击屏幕任意位置,出现水波如下,注意观察地面和天空交界的直线,可以明显看到正弦波形。

img

4 推荐阅读

​ 声明:本文转自【Unity3D】水波特效

标签:Unity3D,质点,特效,值越,float,waveMaterial,水波
From: https://www.cnblogs.com/zhyan8/p/17237939.html

相关文章

  • 【Unity3D】选中物体描边特效
    1前言​描边的难点在于如何检测和识别边缘,当前实现描边特效的方法主要有以下几种:​1)基于顶点膨胀的描边方法​在SubShader中开2个Pass渲染通道,第一......
  • 【Unity3D】绘制物体表面三角形网格
    1仅绘制三角形网格​1)创建游戏对象​创建一个空对象,重命名为Grid,并在其下添加需要绘制网格的对象,如下:​场景显示如下:​2)添加脚本组件​Grid......
  • 【Unity3D】绘制物体外框线条盒子
    1需求描述​点选物体、框选物体、绘制外边框中介绍了物体投影到屏幕上的二维外框绘制方法,本文将介绍物体外框线条盒子绘制方法。内框:选中物体后,绘制物体的内框(紧......
  • 【Unity3D】点选物体、框选物体、绘制外边框
    1需求描述​绘制物体外框线条盒子中介绍了绘制物体外框长方体的方法,本文将介绍物体投影到屏幕上的二维外框绘制方法。点选物体:点击物体,可以选中物体,按住Ctrl追......
  • 【Unity3D】使用GL绘制线段
    1前言​线段渲染器LineRenderer、拖尾TrailRenderer、绘制物体表面三角形网格从不同角度介绍了绘制线段的方法,本文再介绍一种新的绘制线段的方法:使用GL绘制线段。......
  • 【Unity3D】VideoPlayer组件
    1简介​AudioSource组件中介绍了音频的播放,本文将介绍基于VideoPlayer组件实现视频播放。​VideoPlayer属性面板如下:Source:视频源类型,有2种类型:VideoC......
  • 【Unity3D】固定管线着色器二
    1前言​固定管线着色器一中介绍了Shader中外部属性、光照、贴图等基础用法,本文将进一步讲解固定管线着色器,介绍正面与反面剔除、Alpha测试、深度测试、混合、渲......
  • 【Unity3D】固定管线着色器一
    1前言​着色器(Shader)是渲染管线中最重要的一环,Unity3D底层基于OpenGL实现,读者可以通过渲染管线了解Unity3D渲染流程。​OpenGL1.x为固定管线,2.x之后......
  • 【Unity3D】协同程序
    1简介​1)协程概念​协同程序(Coroutine)简称协程,是伴随主线程一起运行的程序片段,是一个能够暂停执行的函数,用于解决程序并行问题。协程是C#中的概念,由于Unity3......
  • 【Unity3D】顶点和片元着色器
    1前言​上文介绍了渲染管线、固定管线着色器和表面着色器,如下:渲染管线固定管线着色器一固定管线着色器二表面着色器​固定管线着色器通过命令方式实现光......