虽然通过参数调试,可以得到不错的水面行走效果,但是CPU计算量也太大了了点。唉~
这里的实现原理,是通过一张Texture2D图,将UV波动的信息当成颜色记录在Texture2D图上,然后通过shader的tex2D函数获得颜色(也就是获得了UV),将这部分和原始UV叠加就能获得人物行走水面的效果。因为Texture2D贴图越大就越耗,计算量也是指数上升,自欺欺人的放入线程计算,不过看着过高的cpu占用,只能舍弃了,唉~,不过将Texture2D贴图限制的小一点,说不定就能吧。还有一个方案就是放在computer shader中计算,下面放上代码,注解很详细了。
脚本
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class WaterWave:MonoBehaviour {
// Use this for initialization
int waveWidth = 512;
int waveHeigth = 512;
public int waveWidthMax = 512;
public int waveHeigthMax = 512;
int planeW = 5;
int planeH = 5;
UnityEngine.Color[] colorBuff;
[Range(0, 1)]
public float power = 0.2f;
[Range(0, 0.2f)]
public float weak = 0.02f;
float[,] waveA;
float[,] waveB;
Texture2D tex_uv;
void Start() {
waveA = new float[waveWidth, waveWidth];
waveB = new float[waveHeigth, waveHeigth];
tex_uv = new Texture2D(waveWidth, waveHeigth);
GetComponent<Renderer>().material.SetTexture("_waveTex", tex_uv);
colorBuff = new UnityEngine.Color[waveWidth * waveHeigth];
isTure = true;
Thread tf = new Thread(new ThreadStart(computeWave));
tf.Start();
UpdateManges.add_playerEventList_(waveUpdate);
//computeWave();
}
// Update is called once per frame
bool ISPLAY = false;
int thisTime = 0;
public Vector3 vt3;//人物脚部落地的世界坐标
void waveUpdate() {
thisTime = (int)(Time.deltaTime * 1000);
tex_uv.SetPixels(colorBuff);
Debug.Log(colorBuff[0][0]);
tex_uv.Apply();
/*if (Input.GetMouseButtonDown(0)) {
ISPLAY = true;
} else if (Input.GetMouseButtonUp(0)) {
ISPLAY = false;
}
if (ISPLAY) {
Vector3 vt = Input.mousePosition;
Ray r = Camera.main.ScreenPointToRay(vt);
RaycastHit hitt = new RaycastHit();
if (Physics.Raycast(r, out hitt)) {
Vector3 localPos = hitt.collider.transform.InverseTransformPoint(hitt.point);
localPos.x = planeW - (localPos.x + planeW) / 2;
localPos.z = planeH - (localPos.z + planeH) / 2;
putpop(localPos.x / planeH * waveWidth, localPos.z / planeH * waveHeigth, power);
}
}*/
if (vt3 != Vector3.zero) {
Vector3 localPos = transform.InverseTransformPoint(vt3);
localPos.x = planeW - (localPos.x + planeW) / 2;
localPos.z = planeH - (localPos.z + planeH) / 2;
putpop(localPos.x / planeH * waveWidth, localPos.z / planeH * waveHeigth, power);
}
}
void putpop(float x, float y, float power) {
int radius = 3;
int _x = (int)x < radius + 1 ? radius + 1 : (int)x >= waveWidth - radius - 1 ? waveWidth - radius - 1 : (int)x;
int _y = (int)y < radius + 1 ? radius + 1 : (int)y >= waveHeigth - radius - 1 ? waveHeigth - radius - 1 : (int)y;
float dist;
for (int i = -radius; i <= radius; i++) {
for (int j = -radius; j <= radius; j++) {
dist = Mathf.Sqrt(i * i + j * j);
if (dist < radius) {
waveA[_x + i, _y + j] = power*Mathf.Cos(dist * Mathf.PI / radius);//一个范围的都添加力量
}
}
}
}
void computeWave() {
while (isTure) {
for (int w = 1; w < waveWidthMax - 1; w++) {
for (int h = 1; h < waveHeigthMax - 1; h++) {
waveB[w, h] = (waveA[w - 1, h] +//左
waveA[w - 1, h + 1] +//左上
waveA[w, h + 1] +//上
waveA[w + 1, h + 1] +//右上
waveA[w + 1, h] +//右
waveA[w + 1, h - 1] +//右下
waveA[w, h - 1] +//下
waveA[w - 1, h - 1]) / 4 - //左下
waveB[w, h];
float value = waveB[w, h];
if (value > 1)
waveB[w, h] = 1;
if (value < -1)
waveB[w, h] = -1;
float offset_u = (waveB[w - 1, h] - waveB[w + 1, h]) / 2;
float offset_v = (waveB[w, h - 1] - waveB[w, h + 1]) / 2;
float r = (offset_u + 1) / 2;//0-1
float g = (offset_v + 1) / 2;//0-1
colorBuff[waveWidth * h + w] = new UnityEngine.Color(r, g, 0);//将UV信息写入颜色,最后通过tex2d来获取UV信息
waveB[w, h] -= waveB[w, h] * weak;//波纹衰减衰减
}
}
/*for (int w = waveWidth - waveWidthMax; w < waveWidth - 1; w++) {
for (int h = waveHeigth - waveHeigthMax; h < waveHeigth - 1; h++) {
colorBuff[waveWidth * h + w - (waveWidth - waveWidthMax)] = new UnityEngine.Color(0, 0, 0);
waveB[w, h] = 0;
}
}*/
float[,] temp = waveA;
waveA = waveB;
waveB = temp;
Thread.Sleep(thisTime);
}
}
bool isTure = false;
private void OnDestroy() {
UpdateManges.sub_playerEventList_(waveUpdate);
isTure = false;
}
}
shader
Shader "Unlit/WaterWave"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_F("平静状态下的水扰动周期",range(0,10)) = 1
_P("平静状态下的水平移范围", range(0, 10)) = 1
wave("波涛起伏深度",range(0,1)) = 0.5
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
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;
sampler2D _waveTex;
float _F;
float _P;
float wave;
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
{
i.uv += 0.01 *sin(i.uv * 2 * 3.14*_F + _Time.y*_P);
// sample the texture
float2 waveuv = tex2D(_waveTex, i.uv).xy; //0-1
waveuv = waveuv * wave;
i.uv += waveuv;
fixed4 col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}