using UnityEngine;
using System.Collections.Generic;
//コンポーネントを自動的に追加
[RequireComponent(typeof(MeshFilter))]
public class PolyMesh : MonoBehaviour
{
///
///
///
public List keyPoints = new List();
///
///
///
public List curvePoints = new List();
///
///
///
public List isCurve = new List();
///
///
///
public MeshCollider meshCollider;
///
///
///
[Range(0.01f, 1)] public float curveDetail = 0.1f;
///
///
///
public float colliderDepth = 1;
///
///
///
public bool buildColliderEdges = true;
///
///
///
public bool buildColliderFront;
///
///
///
public Vector2 uvPosition;
///
///
///
public float uvScale = 1;
///
///
///
public float uvRotation;
public List GetEdgePoints()
{
//Build the point list and calculate curves
var points = new List();
for (int i = 0; i < keyPoints.Count; i++)
{
if (isCurve[i])
{
//Get the curve control point
var a = keyPoints[i];
var c = keyPoints[(i + 1) % keyPoints.Count];
var b = Bezier.Control(a, c, curvePoints[i]);
//Build the curve
var count = Mathf.Ceil(1 / curveDetail);
for (int j = 0; j < count; j++)
{
var t = (float)j / count;
points.Add(Bezier.Curve(a, b, c, t));
}
}
else
points.Add(keyPoints[i]);
}
return points;
}
public void BuildMesh()
{
var points = GetEdgePoints();
var vertices = points.ToArray();
//Build the index array
var indices = new List();
while (indices.Count < points.Count)
indices.Add(indices.Count);
//Build the triangle array
var triangles = Triangulate.Points(points);
//Build the uv array
var scale = uvScale != 0 ? (1 / uvScale) : 0;
var matrix = Matrix4x4.TRS(-uvPosition, Quaternion.Euler(0, 0, uvRotation), new Vector3(scale, scale, 1));
var uv = new Vector2[points.Count];
for (int i = 0; i < uv.Length; i++)
{
var p = matrix.MultiplyPoint(points[i]);
uv[i] = new Vector2(p.x, p.y);
}
//Find the mesh (create it if it doesn't exist)
var meshFilter = GetComponent();
var mesh = meshFilter.sharedMesh;
if (mesh == null)
{
mesh = new Mesh();
mesh.name = "PolySprite_Mesh";
meshFilter.mesh = mesh;
}
//Update the mesh
mesh.Clear();
mesh.vertices = vertices;
mesh.uv = uv;
mesh.triangles = triangles;
mesh.RecalculateNormals();
mesh.Optimize();
//Update collider after the mesh is updated
UpdateCollider(points, triangles);
}
void UpdateCollider(List points, int[] tris)
{
//Update the mesh collider if there is one
if (meshCollider != null)
{
var vertices = new List();
var triangles = new List();
if (buildColliderEdges)
{
//Build vertices array
var offset = new Vector3(0, 0, colliderDepth / 2);
for (int i = 0; i < points.Count; i++)
{
vertices.Add(points[i] + offset);
vertices.Add(points[i] - offset);
}
//Build triangles array
for (int a = 0; a < vertices.Count; a += 2)
{
var b = (a + 1) % vertices.Count;
var c = (a + 2) % vertices.Count;
var d = (a + 3) % vertices.Count;
triangles.Add(a);
triangles.Add(c);
triangles.Add(b);
triangles.Add(c);
triangles.Add(d);
triangles.Add(b);
}
}
if (buildColliderFront)
{
for (int i = 0; i < tris.Length; i++)
tris[i] += vertices.Count;
vertices.AddRange(points);
triangles.AddRange(tris);
}
//Find the mesh (create it if it doesn't exist)
var mesh = meshCollider.sharedMesh;
if (mesh == null)
{
mesh = new Mesh();
mesh.name = "PolySprite_Collider";
}
//Update the mesh
mesh.Clear();
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.RecalculateNormals();
mesh.Optimize();
meshCollider.sharedMesh = null;
meshCollider.sharedMesh = mesh;
}
}
bool IsRightTurn(List points, int a, int b, int c)
{
var ab = points[b] - points[a];
var bc = points[c] - points[b];
return (ab.x * bc.y - ab.y * bc.x) < 0;
}
bool IntersectsExistingLines(List points, Vector3 a, Vector3 b)
{
for (int i = 0; i < points.Count; i++)
if (LinesIntersect(points, a, b, points[i], points[(i + 1) % points.Count]))
return true;
return false;
}
bool LinesIntersect(List points, Vector3 point1, Vector3 point2, Vector3 point3, Vector3 point4)
{
if (point1 == point3 || point1 == point4 || point2 == point3 || point2 == point4)
return false;
float ua = (point4.x - point3.x) * (point1.y - point3.y) - (point4.y - point3.y) * (point1.x - point3.x);
float ub = (point2.x - point1.x) * (point1.y - point3.y) - (point2.y - point1.y) * (point1.x - point3.x);
float denominator = (point4.y - point3.y) * (point2.x - point1.x) - (point4.x - point3.x) * (point2.y - point1.y);
if (Mathf.Abs(denominator) <= 0.00001f)
{
if (Mathf.Abs(ua) <= 0.00001f && Mathf.Abs(ub) <= 0.00001f)
return true;
}
else
{
ua /= denominator;
ub /= denominator;
if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
return true;
}
return false;
}
}
public static class Bezier
{
public static float Curve(float from, float control, float to, float t)
{
return from * (1 - t) * (1 - t) + control * 2 * (1 - t) * t + to * t * t;
}
public static Vector3 Curve(Vector3 from, Vector3 control, Vector3 to, float t)
{
from.x = Curve(from.x, control.x, to.x, t);
from.y = Curve(from.y, control.y, to.y, t);
from.z = Curve(from.z, control.z, to.z, t);
return from;
}
public static Vector3 Control(Vector3 from, Vector3 to, Vector3 curve)
{
//var center = Vector3.Lerp(from, to, 0.5f);
//return center + (curve - center) * 2;
var axis = Vector3.Normalize(to - from);
var dot = Vector3.Dot(axis, curve - from);
var linePoint = from + axis * dot;
return linePoint + (curve - linePoint) * 2;
}
}
public static class Triangulate
{
public static int[] Points(List points)
{
var indices = new List();
int n = points.Count;
if (n < 3)
return indices.ToArray();
int[] V = new int[n];
if (Area(points) > 0)
{
for (int v = 0; v < n; v++)
V[v] = v;
}
else
{
for (int v = 0; v < n; v++)
V[v] = (n - 1) - v;
}
int nv = n;
int count = 2 * nv;
for (int m = 0, v = nv - 1; nv > 2; )
{
if ((count--) <= 0)
return indices.ToArray();
int u = v;
if (nv <= u)
u = 0;
v = u + 1;
if (nv <= v)
v = 0;
int w = v + 1;
if (nv <= w)
w = 0;
if (Snip(points, u, v, w, nv, V))
{
int a, b, c, s, t;
a = V[u];
b = V[v];
c = V[w];
indices.Add(a);
indices.Add(b);
indices.Add(c);
m++;
for (s = v, t = v + 1; t < nv; s++, t++)
V[s] = V[t];
nv--;
count = 2 * nv;
}
}
indices.Reverse();
return indices.ToArray();
}
static float Area(List points)
{
int n = points.Count;
float A = 0.0f;
for (int p = n - 1, q = 0; q < n; p = q++)
{
Vector3 pval = points[p];
Vector3 qval = points[q];
A += pval.x * qval.y - qval.x * pval.y;
}
return (A * 0.5f);
}
static bool Snip(List points, int u, int v, int w, int n, int[] V)
{
int p;
Vector3 A = points[V[u]];
Vector3 B = points[V[v]];
Vector3 C = points[V[w]];
if (Mathf.Epsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x))))
return false;
for (p = 0; p < n; p++)
{
if ((p == u) || (p == v) || (p == w))
continue;
Vector3 P = points[V[p]];
if (InsideTriangle(A, B, C, P))
return false;
}
return true;
}
static bool InsideTriangle(Vector2 A, Vector2 B, Vector2 C, Vector2 P)
{
float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
float cCROSSap, bCROSScp, aCROSSbp;
ax = C.x - B.x; ay = C.y - B.y;
bx = A.x - C.x; by = A.y - C.y;
cx = B.x - A.x; cy = B.y - A.y;
apx = P.x - A.x; apy = P.y - A.y;
bpx = P.x - B.x; bpy = P.y - B.y;
cpx = P.x - C.x; cpy = P.y - C.y;
aCROSSbp = ax * bpy - ay * bpx;
cCROSSap = cx * apy - cy * apx;
bCROSScp = bx * cpy - by * cpx;
return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f));
}
}