贝塞尔曲线的应用

在Unity设计过程中,我们常常会想让游戏中的人群或者相机延一组点进行移动,若想使其平滑运动,这时我们便会用到贝塞尔曲线。

贝塞尔曲线公式如下:

 

一条贝塞尔曲线直接使用公式可使两点连接,代码如下:

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

public class Curve : MonoBehaviour {

	public GameObject[] objs;	//要连接的物体
	List<Vector3> points;		//所有点的位置

	public static Material lineMaterial;
	static void CreateLineMaterial() {
		if (!lineMaterial) {
			lineMaterial = new Material("Shader \"Lines/Colored Blended\" {" + "SubShader { Pass { " + "    Blend SrcAlpha OneMinusSrcAlpha " + "    ZWrite Off Cull Off Fog { Mode Off } " + "    BindChannels {" + "      Bind \"vertex\", vertex Bind \"color\", color }" + "} } }");
			lineMaterial.hideFlags = HideFlags.HideAndDontSave;
			lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
		}
	}

	void OnPostRender() {
		points = Line (objs);
		CreateLineMaterial();
		lineMaterial.SetPass(0);

		GL.Begin(GL.LINES);
		GL.Color(Color.red);
		//画出贝塞尔曲线
		for (int i = 0; i < points.Count - 1; i++) {
			GL.Vertex(points[i]);
			GL.Vertex(points[i + 1]);
		}
		//切线
		GL.Vertex (objs[0].transform.position);
		GL.Vertex (objs[1].transform.position);
		GL.Vertex (objs[2].transform.position);
		GL.Vertex (objs[3].transform.position);
		GL.End();
	}
	//计算贝塞尔曲线
	List<Vector3> Line (GameObject[] objs) {
		List<Vector3> line = new List<Vector3> ();
		for (float i = 0; i < 1; i+=0.02f) {
			Vector3 temp = new Vector3(0,0,0);
			for (int j = 0; j < objs.Length; j++) {
				temp += nCr (objs.Length - 1,j) * Mathf.Pow((1 - i),objs.Length - 1 - j) * Mathf.Pow(i, j) * objs[j].transform.position;
			}
			line.Add (temp);
		}
		return line;
	}
	//组合
	int nCr (int n,int r) {
		return Factorial (n) / (Factorial (r) * Factorial (n - r));
	}
	//阶乘
	int Factorial (int value) {
		if (value == 0) {
			return 1;
		}
		int sum = 1;
		for (int i = 0; i < value; i++) {
			sum *= (i + 1);
		}
		return sum;
	}

}


通过这段代码可使两点间的曲线自由变换,其效果如图:


如此,两点间的贝塞尔曲线就做好了。那么现在需要把多条贝塞尔曲线连接到一起,注意,起始点和终点的切线设为0,其余点的切线设为其相邻点的差。

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

public class Curve2 : MonoBehaviour {

	public GameObject[] objs;			//所要连接物体
	List<Vector3> points;				//所有点的位置
	public float tangentSize = 1f;		//切线大小

	public static Material lineMaterial;
	static void CreateLineMaterial() {
		if (!lineMaterial) {
			lineMaterial = new Material("Shader \"Lines/Colored Blended\" {" + "SubShader { Pass { " + "    Blend SrcAlpha OneMinusSrcAlpha " + "    ZWrite Off Cull Off Fog { Mode Off } " + "    BindChannels {" + "      Bind \"vertex\", vertex Bind \"color\", color }" + "} } }");
			lineMaterial.hideFlags = HideFlags.HideAndDontSave;
			lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave;
		}
	}
	
	void OnPostRender() {
		Vector3[] pos = new Vector3[objs.Length];
		for (int i = 0; i < objs.Length; i++) {
			pos[i] = objs[i].transform.position;
		}
		points = WholeLine (pos);

		CreateLineMaterial();
		lineMaterial.SetPass(0);
		GL.Begin(GL.LINES);
		GL.Color(Color.red);
		for (int i = 0; i < points.Count - 1; i++) {
			GL.Vertex(points[i]);
			GL.Vertex(points[i + 1]);
		}
		GL.End();
	}
	//画出所有曲线
	List<Vector3> WholeLine (Vector3[] value) {
		List<Vector3> line = new List<Vector3> ();
		Vector3[] tempPoint = new Vector3[4];
		for (int i = 0; i < value.Length - 1; i++) {
			tempPoint[0] = value[i];
			if (i == 0) {
				tempPoint[1] = value[i];
			} else {
				tempPoint[1] = value[i] + Vector3.Normalize(value[i + 1] - value[i - 1]) * tangentSize;
			}
			tempPoint[3] = value[i + 1];
			if (i == value.Length - 2) {
				tempPoint[2] = value[i + 1];
			} else {
				tempPoint[2] = value[i + 1] + Vector3.Normalize(value[i] - value[i + 2]) * tangentSize;
			}
			List<Vector3> temp = Line (tempPoint);
			for (int j = 0; j < temp.Count; j++) {
				line.Add(temp[j]);
			}
		}
		return line;
	}
	//画出单条曲线
	List<Vector3> Line (Vector3[] p) {
		List<Vector3> line = new List<Vector3> ();
		for (float i = 0; i < 1; i+=0.02f) {
			Vector3 temp = new Vector3(0,0,0);
			for (int j = 0; j < p.Length; j++) {
				temp += nCr (p.Length - 1,j) * Mathf.Pow((1 - i),p.Length - 1 - j) * Mathf.Pow(i, j) * p[j];
			}
			line.Add (temp);
		}
		return line;
	}
	//组合
	int nCr (int n,int r) {
		return Factorial (n) / (Factorial (r) * Factorial (n - r));
	}
	//阶乘
	int Factorial (int value) {
		if (value == 0) {
			return 1;
		}
		int sum = 1;
		for (int i = 0; i < value; i++) {
			sum *= (i + 1);
		}
		return sum;
	}
	
}



多条贝塞尔曲线效果图:

 

用这样的曲线去模拟人群行走,就会变得平滑许多啦!
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值