自动生成路径mesh

先看看效果图:

自动生成路径mesh

大多数形状都支持,但仍存在不少会生成奇怪形状的情形,到后面也没继续扩展维护了,只当看看好玩

自动生成路径mesh

在编辑器模式便能看到预览效果(Enable,Disable此脚本 Editor便会更新)

不算上起始点,总共有三个控制点,目前上传版本不支持高度y上的平滑插值

W:宽度, R:第一个节点的控制圆半径,R2:第二个控制圆的半径,Div:拐点圆弧平均切割数

代码如下(写的比较乱),一个简易的自动mesh生成工具

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


// 大于90度非直角转弯
[ExecuteInEditMode]
public class G90D_2 : MonoBehaviour
{


[SerializeField]
Material material;


Vector3 c1 = new Vector3(0f, 0f, 0f);
public Vector3 c2 = new Vector3(0f, 0f, 20f); // 控制点2
public Vector3 c3 = new Vector3(20f, 0f, 30f); // 控制点3
public Vector3 c4 = new Vector3(40f, 0f, 25f); // 控制点4
public float w = 1f; // 画的线宽 = 2w
public float r = 1.5f; // 内径圆半径
public float r2 = 1.5f;
public int div = 4; // 拐角弧切成多少份(2三角面)
public string path = "Assets/mymesh.asset"; // 保存路径,相对于项目


// Use this for initialization
void OnEnable()
{
GenerateHeightmap();
}


void GenerateHeightmap()
{
// Create the game object containing the renderer
gameObject.AddComponent<MeshFilter>();
gameObject.AddComponent<MeshRenderer>();
if (material)
GetComponent<Renderer>().material = material;
else
GetComponent<Renderer>().material.color = Color.white;


// Retrieve a mesh instance
Mesh mesh = GetComponent<MeshFilter>().mesh;


List<Vector3> points = new List<Vector3>();
int[] indecies = new int[4];
Color[] colors = new Color[4];
List<Vector2> uvs = new List<Vector2>();


Debug.Log("CosQ: " + Mathf.Cos(60f * Mathf.Deg2Rad));
// 目前只做了 c2 右拐, c2 左拐用 z轴对称回去
bool invert = false;
if (c3.x < 0)
{
invert = true;
c3.x *= -1;
c4.x *= -1;
}


points.Add(new Vector3(c1.x - w, c1.y, c1.z));
points.Add(new Vector3(c1.x + w, c1.y, c1.z));


Vector3 c2l = (c1 - c2).normalized;
Vector3 c2r = (c3 - c2).normalized;
float Q = 90 * Mathf.Deg2Rad - Mathf.Acos(Vector3.Dot(c2l, c2r)) / 2;
//float Q2 = Mathf.Atan((c3.z - c2.z) / (c3.x - c2.x));
Debug.Log("Q1: " + Q / Mathf.Deg2Rad);


Vector3 c22 = c2;
Vector3 c33 = c3;
float D = 2 * Q;
if (c3.x > c2.x) // else情况先用这种模式求, 对结果 Z 取反
{
c22 = new Vector3(c2.x + w + r, c2.y, c2.z - (w + r) * Mathf.Tan(Q));
points.Add(new Vector3(c22.x - 2 * w - r, c22.y, c22.z));
points.Add(new Vector3(c22.x - r, c22.y, c22.z));


for (int i = 1; i <= div; ++i)
{
float d = D * i / div;
points.Add(new Vector3(c22.x - (r + 2 * w) * Mathf.Cos(d), c22.y, c22.z + (r + 2 * w) * Mathf.Sin(d)));
points.Add(new Vector3(c22.x - r * Mathf.Cos(d), c22.y, c22.z + r * Mathf.Sin(d)));
}


// 求c3拐点
r = r2;
Vector3 c3l = (c2 - c3).normalized;
Vector3 c3r = (c4 - c3).normalized;
Q = 90 * Mathf.Deg2Rad - Mathf.Acos(Vector3.Dot(c3l, c3r)) / 2;
D = 2 * Q;
float Q2 = Mathf.Acos(Vector3.Dot(c3r, Vector3.forward));
//Debug.Log("Q1: " + Q / Mathf.Deg2Rad + "Q2: " + Q2 / Mathf.Deg2Rad);


float c2c = (w + r) / Mathf.Cos(Q);//(w+r)/Mathf.Cos(Q2)/(1-Mathf.Tan(Q-Q2)*Mathf.Tan(Q2));


//Debug.Log("Q2::: " + Q2 / Mathf.Deg2Rad + "x: " + x + " x+: " + x * Mathf.Tan(Q - Q2) / Mathf.Tan(Q2) +" z+: " + x / Mathf.Tan(Q2));
//Debug.Log("c33.x: " + c33.x + " c33.z : " + c33.z);
// case 1 c4.x < c3.x c33.z < c3.z 
// case 2 c4.x < c3.x c33.z > c3.z 
// case 3 c4.x > c3.x c33.z > c3.z 
// c4在c3左边需要减掉Q2


if (c4.x <= c3.x && c4.z >= c3.z)
{
float Q3 = Mathf.Acos(Vector3.Dot((c3 - c2).normalized, Vector3.forward));
if (Q2 < Q3) // c33.z > c3.z c3的拐点c33 在c3的上面
{
c33 = new Vector3(c3.x - c2c * Mathf.Cos(Q - Q2), c3.y, c3.z + c2c * Mathf.Sin(Q - Q2));
for (int i = div; i >= 0; --i)
{
float d = D * i / div;
if (d > Q2)
{
d -= Q2;
points.Add(new Vector3(c33.x + r * Mathf.Cos(d), c33.y, c33.z - r * Mathf.Sin(d)));
points.Add(new Vector3(c33.x + (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z - (r + 2 * w) * Mathf.Sin(d)));
}
else
{
d = Q2 - d;
points.Add(new Vector3(c33.x + r * Mathf.Cos(d), c33.y, c33.z + r * Mathf.Sin(d)));
points.Add(new Vector3(c33.x + (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z + (r + 2 * w) * Mathf.Sin(d)));
}
}


}
else
{
c33 = new Vector3(c3.x - c2c * Mathf.Cos(Q - Q3), c3.y, c3.z - c2c * Mathf.Sin(Q - Q3));
for (int i = div; i >= 0; --i)
{
float d = D * i / div;
if (d > D - Q3)
{
d -= (D - Q3);
points.Add(new Vector3(c33.x + r * Mathf.Cos(d), c33.y, c33.z - r * Mathf.Sin(d)));
points.Add(new Vector3(c33.x + (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z - (r + 2 * w) * Mathf.Sin(d)));
}
else
{
d = (D - Q3) - d;
points.Add(new Vector3(c33.x + r * Mathf.Cos(d), c33.y, c33.z + r * Mathf.Sin(d)));
points.Add(new Vector3(c33.x + (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z + (r + 2 * w) * Mathf.Sin(d)));
}
}
}


points.Add(new Vector3(c4.x - w * Mathf.Cos(Q2), c4.y, c4.z - w * Mathf.Sin(Q2)));
points.Add(new Vector3(c4.x + w * Mathf.Cos(Q2), c4.y, c4.z + w * Mathf.Sin(Q2)));
}
else //!(c4.x <= c3.x && c4.z >= c3.z)
{
if (c4.z >= c3.z && Vector3.Dot((c3 - c2).normalized, Vector3.right) >= Vector3.Dot((c4 - c3).normalized, Vector3.right))
// // c4在c3上面
{
c33 = new Vector3(c3.x - c2c * Mathf.Cos(Q + Q2), c3.y, c3.z + c2c * Mathf.Sin(Q + Q2));
for (int i = div; i >= 0; --i)
{
float d = D * i / div;
d += Q2;
points.Add(new Vector3(c33.x + r * Mathf.Cos(d), c33.y, c33.z - r * Mathf.Sin(d)));
points.Add(new Vector3(c33.x + (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z - (r + 2 * w) * Mathf.Sin(d)));
}
// c4
points.Add(new Vector3(c4.x - w * Mathf.Cos(Q2), c4.y, c4.z + w * Mathf.Sin(Q2)));
points.Add(new Vector3(c4.x + w * Mathf.Cos(Q2), c4.y, c4.z - w * Mathf.Sin(Q2)));
}
else if (c3.z < c2.z && c4.x >= c3.x && Vector3.Dot((c3 - c2).normalized, Vector3.right) < Vector3.Dot((c4 - c3).normalized, Vector3.right))
//
{
Q2 = Mathf.Acos(Vector3.Dot(c3r, Vector3.right));
if (c4.z <= c3.z) // c4 down
{
c33 = new Vector3(c3.x + c2c * Mathf.Sin(Q + Q2), c3.y, c3.z + c2c * Mathf.Cos(Q + Q2));
for (int i = div; i >= 0; --i)
{
float d = D * i / div;
d = Mathf.PI / 2 - d - Q2;


points.Add(new Vector3(c33.x - r * Mathf.Cos(d), c33.y, c33.z - r * Mathf.Sin(d)));
points.Add(new Vector3(c33.x - (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z - (r + 2 * w) * Mathf.Sin(d)));


}
// c4
points.Add(new Vector3(c4.x + w * Mathf.Sin(Q2), c4.y, c4.z + w * Mathf.Cos(Q2)));
points.Add(new Vector3(c4.x - w * Mathf.Sin(Q2), c4.y, c4.z - w * Mathf.Cos(Q2)));

}
else
{
c33 = new Vector3(c3.x + c2c * Mathf.Sin(Q - Q2), c3.y, c3.z + c2c * Mathf.Cos(Q - Q2));
for (int i = div; i >= 0; --i)
{
float d = D * i / div;
if (d > Q2)
{
d = Mathf.PI / 2 - (d - Q2);
points.Add(new Vector3(c33.x - r * Mathf.Cos(d), c33.y, c33.z - r * Mathf.Sin(d)));
points.Add(new Vector3(c33.x - (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z - (r + 2 * w) * Mathf.Sin(d)));
}
else
{
d = Mathf.PI / 2 - (Q2 - d);
points.Add(new Vector3(c33.x + r * Mathf.Cos(d), c33.y, c33.z - r * Mathf.Sin(d)));
points.Add(new Vector3(c33.x + (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z - (r + 2 * w) * Mathf.Sin(d)));
}
}
// c4
points.Add(new Vector3(c4.x - w * Mathf.Sin(Q2), c4.y, c4.z + w * Mathf.Cos(Q2)));
points.Add(new Vector3(c4.x + w * Mathf.Sin(Q2), c4.y, c4.z - w * Mathf.Cos(Q2)));
}


}
else
{ //没考虑 c3.z < c2.z
Q2 = Mathf.Acos(Vector3.Dot(c3r, Vector3.back));
if ((c4.x < c3.x && c4.z < c3.z) || Q2 < Mathf.PI / 2 - Q) // c33 在c3的第三象限 
{
if (c4.x >= c3.x) // 如果c4.x < c3.x d的计算发生改变
{
c33 = new Vector3(c3.x - c2c * Mathf.Cos(Q + Q2), c3.y, c3.z - c2c * Mathf.Sin(Q + Q2));
for (int i = div; i >= 0; --i)
{
float d = D * i / div;
d += Q2;
if (d > Mathf.PI / 2)
{
d = Mathf.PI - d;
points.Add(new Vector3(c33.x - (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z + (r + 2 * w) * Mathf.Sin(d)));
points.Add(new Vector3(c33.x - r * Mathf.Cos(d), c33.y, c33.z + r * Mathf.Sin(d)));
}
else
{
points.Add(new Vector3(c33.x + (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z + (r + 2 * w) * Mathf.Sin(d)));
points.Add(new Vector3(c33.x + r * Mathf.Cos(d), c33.y, c33.z + r * Mathf.Sin(d)));
}
}
// c4
points.Add(new Vector3(c4.x + w * Mathf.Cos(Q2), c4.y, c4.z + w * Mathf.Sin(Q2)));
points.Add(new Vector3(c4.x - w * Mathf.Cos(Q2), c4.y, c4.z - w * Mathf.Sin(Q2)));
}
else
{
c33 = new Vector3(c3.x - c2c * Mathf.Cos(Q - Q2), c3.y, c3.z - c2c * Mathf.Sin(Q - Q2));
for (int i = div; i >= 0; --i)
{
float d = D * i / div;
d -= Q2;
if (d > Mathf.PI / 2)
{
d = Mathf.PI - d;
points.Add(new Vector3(c33.x - (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z + (r + 2 * w) * Mathf.Sin(d)));
points.Add(new Vector3(c33.x - r * Mathf.Cos(d), c33.y, c33.z + r * Mathf.Sin(d)));


}
else
{
points.Add(new Vector3(c33.x + (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z + (r + 2 * w) * Mathf.Sin(d)));
points.Add(new Vector3(c33.x + r * Mathf.Cos(d), c33.y, c33.z + r * Mathf.Sin(d)));


}
}
// c4
points.Add(new Vector3(c4.x + w * Mathf.Cos(Q2), c4.y, c4.z - w * Mathf.Sin(Q2)));
points.Add(new Vector3(c4.x - w * Mathf.Cos(Q2), c4.y, c4.z + w * Mathf.Sin(Q2)));
}
}
else// c33 在c3的第四象限
{
Q2 = Mathf.Acos(Vector3.Dot((c2 - c3).normalized, Vector3.back));
c33 = new Vector3(c3.x + c2c * Mathf.Cos(Q + Q2), c3.y, c3.z - c2c * Mathf.Sin(Q + Q2));
for (int i = 0; i <= div; ++i)
{
float d = D * i / div;
d = d + Q2;
if (d < Mathf.PI / 2)
{
points.Add(new Vector3(c33.x - (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z + (r + 2 * w) * Mathf.Sin(d)));
points.Add(new Vector3(c33.x - r * Mathf.Cos(d), c33.y, c33.z + r * Mathf.Sin(d)));
}
else
{
d = Mathf.PI - d;
points.Add(new Vector3(c33.x + (r + 2 * w) * Mathf.Cos(d), c33.y, c33.z + (r + 2 * w) * Mathf.Sin(d)));
points.Add(new Vector3(c33.x + r * Mathf.Cos(d), c33.y, c33.z + r * Mathf.Sin(d)));
}
}
// c4
Q2 = Mathf.Acos(Vector3.Dot((c4 - c3).normalized, Vector3.forward));
points.Add(new Vector3(c4.x - w * Mathf.Cos(Q2), c4.y, c4.z + w * Mathf.Sin(Q2)));
points.Add(new Vector3(c4.x + w * Mathf.Cos(Q2), c4.y, c4.z - w * Mathf.Sin(Q2)));
}
}
}
//points.Add(new Vector3(c33.x + r, c33.y, c33.z));
//points.Add(new Vector3(c33.x + 2 * w + r, c33.y, c33.z));
}


List<Vector3> points2 = new List<Vector3>();
if(invert)
{
c3.x *= -1;
c4.x *= -1;
int k = 0;
Vector3 tmp = Vector3.zero;
for(int i=0; i<points.Count/2; ++i)
{
k = 2 * i;
tmp = points[k+1];
tmp.x = -tmp.x;
points2.Add(tmp);
tmp = points[k];
tmp.x = -tmp.x;
points2.Add(tmp);
//points[k] = points[k + 1];
//points[k + 1] = tmp;
}
points = points2;
}


float Q4 = Mathf.Acos(Vector3.Dot((c3 - c4).normalized, Vector3.right));






for (int i = 0; i < points.Count; ++i)
{
Debug.Log(string.Format("Point {0}: ({1}, {2}, {3})", i, points[i].x, points[i].y, points[i].z));
//indecies[i] = i;
//colors[i] = new Color(Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f), Random.Range(0.0f, 1.0f), 1.0f);
}


//uvs.Add(new Vector2(0, 1));
//uvs.Add(new Vector2(0, 0));
//uvs.Add(new Vector2(1, 1));
//uvs.Add(new Vector2(1, 0));




mesh.vertices = points.ToArray();
//mesh.uv = uvs.ToArray();
//mesh.colors = colors;
//mesh.SetIndices(indecies, MeshTopology.Points, 0);


List<int> triangles = new List<int>();
int index = 0;
for (int x = 0; x < (points.Count - 3); ++x)
{
triangles.Add(x);
triangles.Add(x+2);
triangles.Add(x+1);


triangles.Add(x+2);
triangles.Add(x+3);
triangles.Add(x+1);
}


//var triangles = new int[(points.Count - 3) * 6];
//var index = 0;
//for (int x = 0; x < (points.Count - 3); ++x)
//{
// triangles[index++] = x;
// triangles[index++] = 2 + x;
// triangles[index++] = x + 1;


// triangles[index++] = x + 2;
// triangles[index++] = x + 3;
// triangles[index++] = x + 1;
//}


// And assign them to the mesh
mesh.triangles = triangles.ToArray();


//mesh.RecalculateNormals();


// 保存mesh
//var mf = GetComponent<MeshFilter>();
//if (mf)
//{
// //path = FileUtil.GetProjectRelativePath(path);
// AssetDatabase.CreateAsset(mesh, path);
// AssetDatabase.SaveAssets();
//}




}




Vector3 BezierPathCalculation(Vector3 p0, Vector3 p1, Vector3 p2, float t)
{
float tt = t * t;
float u = 1.0f - t;
float uu = u * u;


Vector3 B = new Vector3();
B = uu * p0;
B += 2.0f * u * t * p1;
B += tt * p2;


return B;
}
Vector3 BezierPathCalculation(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
{
float tt = t * t;
float ttt = t * tt;
float u = 1.0f - t;
float uu = u * u;
float uuu = u * uu;


Vector3 B = new Vector3();
B = uuu * p0;
B += 3.0f * uu * t * p1;
B += 3.0f * u * tt * p2;
B += ttt * p3;


return B;
}
}