Games103的作业4:水波

这个作业做得我头疼,奇奇怪怪的bug一堆,目前暂时没有弄水作用于木块,我猜应该是用浮力对木块作用的力矩来解决

下面记录下代码

using UnityEngine;
using System.Collections;

public class wave_motion : MonoBehaviour 
{
	int size 		= 100;
	float rate 		= 0.005f;
	float gamma		= 0.004f;
	float damping 	= 0.996f;
	float[,] 	old_h;
	float[,]	low_h;
	float[,]	vh;
	float[,]	b;

	bool [,]	cg_mask;
	float[,]	cg_p;
	float[,]	cg_r;
	float[,]	cg_Ap;
	bool 	tag=true;

	Vector3 	cube_v = Vector3.zero;
	Vector3 	cube_w = Vector3.zero;


	// Use this for initialization
	void Start () 
	{
		Mesh mesh = GetComponent<MeshFilter> ().mesh;
		mesh.Clear ();

		Vector3[] X=new Vector3[size*size];

		for (int i=0; i<size; i++)
		for (int j=0; j<size; j++) 
		{
			X[i*size+j].x=i*0.1f-size*0.05f;
			X[i*size+j].y=0;
			X[i*size+j].z=j*0.1f-size*0.05f;
		}

		int[] T = new int[(size - 1) * (size - 1) * 6];
		int index = 0;
		for (int i=0; i<size-1; i++)
		for (int j=0; j<size-1; j++)
		{
			T[index*6+0]=(i+0)*size+(j+0);
			T[index*6+1]=(i+0)*size+(j+1);
			T[index*6+2]=(i+1)*size+(j+1);
			T[index*6+3]=(i+0)*size+(j+0);
			T[index*6+4]=(i+1)*size+(j+1);
			T[index*6+5]=(i+1)*size+(j+0);
			index++;
		}
		mesh.vertices  = X;
		mesh.triangles = T;
		mesh.RecalculateNormals ();

		low_h 	= new float[size,size];
		old_h 	= new float[size,size];
		vh 	  	= new float[size,size];
		b 	  	= new float[size,size];

		cg_mask	= new bool [size,size];
		cg_p 	= new float[size,size];
		cg_r 	= new float[size,size];
		cg_Ap 	= new float[size,size];

		for (int i=0; i<size; i++)
		for (int j=0; j<size; j++) 
		{
			low_h[i,j]=99999;
			old_h[i,j]=0;
			vh[i,j]=0;
		}
	}

	void A_Times(bool[,] mask, float[,] x, float[,] Ax, int li, int ui, int lj, int uj)
	{
		for(int i=li; i<=ui; i++)
		for(int j=lj; j<=uj; j++)
		if(i>=0 && j>=0 && i<size && j<size && mask[i,j])
		{
			Ax[i,j]=0;
			if(i!=0)		Ax[i,j]-=x[i-1,j]-x[i,j];
			if(i!=size-1)	Ax[i,j]-=x[i+1,j]-x[i,j];
			if(j!=0)		Ax[i,j]-=x[i,j-1]-x[i,j];
			if(j!=size-1)	Ax[i,j]-=x[i,j+1]-x[i,j];
		}
	}

	float Dot(bool[,] mask, float[,] x, float[,] y, int li, int ui, int lj, int uj)
	{
		float ret=0;
		for(int i=li; i<=ui; i++)
		for(int j=lj; j<=uj; j++)
		if(i>=0 && j>=0 && i<size && j<size && mask[i,j])
		{
			ret+=x[i,j]*y[i,j];
		}
		return ret;
	}

	void Conjugate_Gradient(bool[,] mask, float[,] b, float[,] x, int li, int ui, int lj, int uj)
	{
		//Solve the Laplacian problem by CG.
		A_Times(mask, x, cg_r, li, ui, lj, uj);

		for(int i=li; i<=ui; i++)
		for(int j=lj; j<=uj; j++)
		if(i>=0 && j>=0 && i<size && j<size && mask[i,j])
		{
			cg_p[i,j]=cg_r[i,j]=b[i,j]-cg_r[i,j];
		}

		float rk_norm=Dot(mask, cg_r, cg_r, li, ui, lj, uj);

		for(int k=0; k<128; k++)
		{
			if(rk_norm<1e-10f)	break;
			A_Times(mask, cg_p, cg_Ap, li, ui, lj, uj);
			float alpha=rk_norm/Dot(mask, cg_p, cg_Ap, li, ui, lj, uj);

			for(int i=li; i<=ui; i++)
			for(int j=lj; j<=uj; j++)
			if(i>=0 && j>=0 && i<size && j<size && mask[i,j])
			{
				x[i,j]   +=alpha*cg_p[i,j];
				cg_r[i,j]-=alpha*cg_Ap[i,j];
			}

			float _rk_norm=Dot(mask, cg_r, cg_r, li, ui, lj, uj);
			float beta=_rk_norm/rk_norm;
			rk_norm=_rk_norm;

			for(int i=li; i<=ui; i++)
			for(int j=lj; j<=uj; j++)
			if(i>=0 && j>=0 && i<size && j<size && mask[i,j])
			{
				cg_p[i,j]=cg_r[i,j]+beta*cg_p[i,j];
			}
		}

	}

	void Shallow_Wave(float[,] old_h, float[,] h, float [,] new_h)
	{
		//Step 1:
		//TODO: Compute new_h based on the shallow wave model.
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++)
			{
				new_h[i, j] = h[i, j] + (h[i, j] - old_h[i, j]) * damping;
				if (i - 1 >= 0)
					new_h[i, j] += (h[i - 1, j] - h[i, j]) * rate;
				if (i + 1 < size)
					new_h[i, j] += (h[i + 1, j] - h[i, j]) * rate;
				if (j - 1 >= 0)
					new_h[i, j] += (h[i, j - 1] - h[i, j]) * rate;
				if (j + 1 < size)
					new_h[i, j] += (h[i, j + 1] - h[i, j]) * rate;
			}

		//Step 2: Block->Water coupling
		GameObject cube = GameObject.Find("Cube");
		//TODO: for block 1, calculate low_h.
		Vector3 cube_p = cube.transform.position;
		Mesh cube_m = cube.GetComponent<MeshFilter>().mesh;
		Bounds bound = cube_m.bounds;

		int li = (int)((cube_p.x) * 10 + 50 - 2);	//世界坐标里长度0.1对应一方格,水面大小为100X100
		int ui = (int)((cube_p.x) * 10 + 50 + 2);
		int lj = (int)((cube_p.z) * 10 + 50 - 2);
		int uj = (int)((cube_p.z) * 10 + 50 + 2);	

		for (int i = li ; i <= ui; i++)      
			for (int j = lj; j <= uj; j++)


				//for (int i = li-3; i <= ui+3; i++)		//我并不怎么理解这么-3 +3的作用,但他的确可以消除残留痕迹,而反之将+3-3这些等价变换到ui,li,uj,lj却不能做到消除残留痕迹的效果
			//for (int j = lj-3; j <= uj+3; j++)
				if (i >= 0 && j >= 0 && i < size && j < size)
				{
				Vector3 p = new Vector3(i * 0.1f - 5f, -11f, j * 0.1f - 5f);
				Vector3 q = new Vector3(i * 0.1f - 5f, -10f, j * 0.1f - 5f);
				
				p = cube.transform.InverseTransformPoint(p);
				q = cube.transform.InverseTransformPoint(q);

				Ray ray = new Ray(p, q - p);
				float dis= 99999;
				bound.IntersectRay(ray,out dis);
				low_h[i, j] = -11f+dis;
			}


		//TODO: then set up b and cg_mask for conjugate gradient.
		for(int i=0;i<size;i++)
			for(int j=0;j<size;j++)
            {
				if(low_h[i,j]>h[i,j])
                {
					b[i, j] = 0;
					cg_mask[i, j] = false;
					vh[i, j] = 0;
                }
				else
                {
					b[i, j] =  (new_h[i, j] - low_h[i, j])/rate;
					cg_mask[i, j] = true;
                }

            }


		//TODO: Solve the Poisson equation to obtain vh (virtual height).
		Conjugate_Gradient(cg_mask, b, vh, li - 1, ui + 1, lj - 1, uj + 1);

		//TODO: for block 2, calculate low_h.
		//TODO: then set up b and cg_mask for conjugate gradient.
		//TODO: Solve the Poisson equation to obtain vh (virtual height).

		//TODO: Diminish vh.
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++)	
			{
				if (cg_mask[i, j])
					vh[i, j] *= gamma;
			}
		//TODO: Update new_h by vh.
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++)
			{
				if ((i - 1) >= 0)
					new_h[i, j] += (vh[i - 1, j] - vh[i, j]) * rate ;
				if ((i + 1) < size)
					new_h[i, j] += (vh[i + 1, j] - vh[i, j]) * rate;
				if ((j - 1) >= 0)
					new_h[i, j ] += (vh[i, j - 1] - vh[i, j]) * rate ;
				if ((j + 1) < size)
					new_h[i, j ] += (vh[i, j + 1] - vh[i, j]) * rate;
			}
		//Step 3
		//TODO: old_h <- h; h <- new_h;
		for (int i=0;i<size;i++)
			for(int j=0;j<size;j++)
            {
				old_h[i, j] = h[i, j];
				h[i, j] = new_h[i, j];
            }
		//Step 4: Water->Block coupling.
		//More TODO here.
	}
	

	// Update is called once per frame
	void Update () 
	{
		Mesh mesh = GetComponent<MeshFilter> ().mesh;
		Vector3[] X    = mesh.vertices;
		float[,] new_h = new float[size, size];
		float[,] h     = new float[size, size];

		//TODO: Load X.y into h.
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++)
				h[i, j] = X[i * size + j].y;

		if (Input.GetKeyDown ("r")) 
		{
			//TODO: Add random water.
			h[15, 15] += 0.1f;
		}
	
		for(int l=0; l<8; l++)
		{
			Shallow_Wave(old_h, h, new_h);
		}

		//TODO: Store h back into X.y and recalculate normal.
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++)
				X[i*size+j].y = h[i, j];
		mesh.vertices = X;
		mesh.RecalculateNormals();
	}
}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值