This commit is contained in:
MuHua-123
2024-11-25 18:32:05 +08:00
parent 72d1f89b54
commit 84243e75a8
353 changed files with 17666 additions and 3206 deletions
@@ -0,0 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 单个算法函数
/// </summary>
/// <typeparam name="Data"></typeparam>
public interface UnitAlgorithm<Data> {
/// <summary> 执行算法 </summary>
public void Compute(Data data);
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 60c99317b7676b6408025f3f6fed9f1a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,165 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary>
/// 贝塞尔算法
/// </summary>
public class UnitAlgorithmBezier : UnitAlgorithm<DataPlate> {
/// <summary> 贝塞尔算法 </summary>
public UnitAlgorithmBezier() { }
public class DataBezier {
//输入
public float smooth;
public Bezier bezier;
public Vector3 aPoint;
public Vector3 bPoint;
public Vector3 aBezier;
public Vector3 bBezier;
//输出
public float length;
public List<Vector3> positions = new List<Vector3>();
public List<DataLine> lines = new List<DataLine>();
}
public void Compute(DataPlate data) {
List<Vector3> points = new List<Vector3>();
for (int i = 0; i < data.sides.Count; i++) {
Compute(data.sides[i]);
points.AddRange(data.sides[i].positions);
}
//去除重复边缘点
points = points.Distinct().ToList();
data.edgePoints = points;
}
public void Compute(DataSide data) {
DataBezier dataBezier = new DataBezier();
dataBezier.bezier = data.bezier;
dataBezier.smooth = data.plate.smooth;
dataBezier.aPoint = data.aPoint.position;
dataBezier.bPoint = data.bPoint.position;
dataBezier.aBezier = data.aBezier;
dataBezier.bBezier = data.bBezier;
Compute(dataBezier);
data.length = dataBezier.length;
data.positions = dataBezier.positions.ToArray();
data.lines = dataBezier.lines.ToArray();
}
/// <summary> 计算曲线细分点 </summary>
private void Compute(DataBezier data) {
//细分点
if (data.bezier == Bezier.) {
data.positions = Compute(data.aPoint, data.bPoint);
}
if (data.bezier == Bezier.) {
data.positions = Compute(data.aPoint, data.aBezier, data.bPoint, data.smooth);
}
if (data.bezier == Bezier.) {
data.positions = Compute(data.aPoint, data.aBezier, data.bBezier, data.bPoint, data.smooth);
}
//线段
data.lines = new List<DataLine>();
float origin = 0;
for (int i = 0; i < data.positions.Count - 1; i++) {
DataLine line = new DataLine();
line.a = data.positions.LoopIndex(i + 0);
line.b = data.positions.LoopIndex(i + 1);
line.origin = origin;
data.lines.Add(line);
data.length += line.Distance;
origin += line.Distance;
}
}
/// <summary> 二阶贝塞尔线段 </summary>
private List<Vector3> Compute(Vector3 aPoint, Vector3 bPoint) {
return new List<Vector3> { aPoint, bPoint };
}
/// <summary> 二阶贝塞尔线段 </summary>
private List<Vector3> Compute(Vector3 a, Vector3 b, Vector3 c, float smooth) {
List<Vector3> points = new List<Vector3>();
//方向,距离
Vector2 direction = (c - a).normalized;
float distance = Vector2.Distance(c, a);
//求余,得商数
int quotient = Quotient(distance, smooth);
//贝塞尔曲线点
for (int i = 0; i < quotient; i++) {
float t = i * (distance / quotient) / distance;
Vector2 position = ComputeBezier(a, b, c, t);
points.Add(position);
}
points.Add(c);
return points;
}
/// <summary> 三阶贝塞尔线段 </summary>
private List<Vector3> Compute(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float smooth) {
List<Vector3> points = new List<Vector3>();
//方向,距离
Vector2 direction = (d - a).normalized;
float distance = Vector2.Distance(d, a);
//求余,得商数
int quotient = Quotient(distance, smooth);
//贝塞尔曲线点
for (int i = 0; i < quotient; i++) {
float t = i * (distance / quotient) / distance;
Vector2 position = ComputeBezier(a, b, c, d, t);
points.Add(position);
}
points.Add(d);
return points;
}
/// <summary> 商数 </summary>
public static int Quotient(float distance, float smooth) {
int a = (int)(distance * 1000);
int b = (int)(smooth * 1000);
return Math.DivRem(a, b, out int remainder);
}
/// <summary>
/// 一阶贝塞尔算法
/// </summary>
/// <param name="a">起点</param>
/// <param name="b">终点</param>
/// <param name="t">进度</param>
/// <returns></returns>
public static Vector3 ComputeBezier(Vector3 a, Vector3 b, float t) {
return a + (b - a) * t;
}
/// <summary>
/// 二阶贝塞尔算法
/// </summary>
/// <param name="a">起点</param>
/// <param name="b">贝塞尔点</param>
/// <param name="c">终点</param>
/// <param name="t">进度</param>
/// <returns>当前进度的曲线点</returns>
public static Vector3 ComputeBezier(Vector3 a, Vector3 b, Vector3 c, float t) {
Vector3 aa = a + (b - a) * t;
Vector3 bb = b + (c - b) * t;
return aa + (bb - aa) * t;
}
/// <summary>
/// 三阶贝塞尔算法
/// </summary>
/// <param name="a">起点</param>
/// <param name="b">起点的贝塞尔点</param>
/// <param name="c">终点的贝塞尔点</param>
/// <param name="d">终点</param>
/// <param name="t">进度</param>
/// <returns>当前进度的曲线点</returns>
public static Vector3 ComputeBezier(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float t) {
Vector3 aa = a + (b - a) * t;
Vector3 bb = b + (c - b) * t;
Vector3 cc = c + (d - c) * t;
Vector3 aaa = aa + (bb - aa) * t;
Vector3 bbb = bb + (cc - bb) * t;
return aaa + (bbb - aaa) * t;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c59160eac8bcdec48a6b5584c7c91192
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 散点边界算法
/// </summary>
public class UnitAlgorithmBorder : UnitAlgorithm<DataPlate> {
/// <summary> 散点边界算法 </summary>
public UnitAlgorithmBorder() { }
public void Compute(DataPlate plate) {
List<Vector3> edgePoints = new List<Vector3>(plate.edgePoints);
plate.border = Border(edgePoints);
}
public static DataBorder Border(List<Vector3> points) {
float minX = 0; float minY = 0;
float maxX = 0; float maxY = 0;
for (int i = 0; i < points.Count; i++) {
if (points[i].x < minX) { minX = points[i].x; }
if (points[i].x > maxX) { maxX = points[i].x; }
if (points[i].y < minY) { minY = points[i].y; }
if (points[i].y > maxY) { maxY = points[i].y; }
}
return new DataBorder(minX, maxX, minY, maxY);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 794f9553060acb04e88211793e35c810
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,133 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary>
/// 多边形耳切法
/// </summary>
public class UnitAlgorithmEarCutting : UnitAlgorithm<DataPlate> {
/// <summary> 多边形耳切法 </summary>
public UnitAlgorithmEarCutting() { }
public class Auriculare {
public int index;
public Vector3 aPoint;//+0
public Vector3 bPoint;//-1
public Vector3 cPoint;//+1
}
public void Compute(DataPlate data) {
List<Vector3> points = new List<Vector3>(data.edgePoints);
//判断散列点排序方向
Vector3[] allArray = points.ToArray();
bool isClockWise = IsClockWise(allArray);
//耳切法生成三角形
List<DataTriangle> triangles = new List<DataTriangle>();
ComputeAuriculare(triangles, points, allArray, isClockWise);
data.triangles = triangles;
}
#region
/// <summary> 循环计算有效的耳点 </summary>
public static void ComputeAuriculare(List<DataTriangle> triangles, List<Vector3> edgePoints, Vector3[] allArray, bool isClockWise) {
List<DataTriangle> temp = ComputeAuriculare(edgePoints, allArray, isClockWise);
if (temp.Count == 0) { return; }
triangles.AddRange(temp);
ComputeAuriculare(triangles, edgePoints, allArray, isClockWise);
}
/// <summary> 计算一个有效的耳点 </summary>
public static List<DataTriangle> ComputeAuriculare(List<Vector3> edgePoints, Vector3[] allArray, bool isClockWise) {
Vector3[] array = edgePoints.ToArray();
List<DataTriangle> polygons = new List<DataTriangle>();
for (int i = 0; i < array.Length; i++) {
Auriculare auriculare = CreateAuriculare(i, array);
// 等于180,大于180,不可能为耳点
if (!GetAngleType(auriculare, isClockWise)) { continue; }
// 包含其他点,不可能为耳点
if (IsInsideTriangle(auriculare, allArray)) { continue; }
// 包含其他耳点,不可能成为耳点
if (!IsInsideAuriculare(auriculare, edgePoints)) { continue; }
edgePoints.Remove(auriculare.aPoint);
polygons.Add(CreateAuriculareToTriangle(auriculare));
}
return polygons;
}
/// <summary> 创建耳点 </summary>
public static Auriculare CreateAuriculare(int index, Vector3[] array) {
Auriculare auriculare = new Auriculare();
auriculare.index = index;
auriculare.bPoint = array.LoopIndex(index - 1);
auriculare.aPoint = array.LoopIndex(index);
auriculare.cPoint = array.LoopIndex(index + 1);
return auriculare;
}
/// <summary> 计算三角形内是否包含其他点 </summary>
public static bool IsInsideTriangle(Auriculare auriculare, Vector3[] array) {
for (int i = 0; i < array.Length; i++) {
if (array[i] == auriculare.aPoint) { continue; }
if (array[i] == auriculare.bPoint) { continue; }
if (array[i] == auriculare.cPoint) { continue; }
if (IsInsideTriangle(auriculare, array[i])) { return true; }
}
return false;
}
/// <summary> 计算三角形内是否包含其他点 </summary>
public static bool IsInsideAuriculare(Auriculare auriculare, List<Vector3> edgePoints) {
if (!edgePoints.Contains(auriculare.aPoint)) { return false; }
if (!edgePoints.Contains(auriculare.bPoint)) { return false; }
if (!edgePoints.Contains(auriculare.cPoint)) { return false; }
return true;
}
/// <summary> 从节点创建三角形 </summary>
public static DataTriangle CreateAuriculareToTriangle(Auriculare auriculare) {
DataTriangle triangle = new DataTriangle();
triangle.a = auriculare.aPoint;
triangle.b = auriculare.bPoint;
triangle.c = auriculare.cPoint;
return triangle;
}
#endregion
#region
/// <summary> 当前的点方向是否为顺时针 </summary>
public static bool IsClockWise(Vector3[] array) {
// 通过计算叉乘来确定方向
float sum = 0f;
double count = array.Length;
Vector3 va, vb;
for (int i = 0; i < array.Length; i++) {
va = array[i];
vb = (i == count - 1) ? array[0] : array[i + 1];
sum += va.x * vb.y - va.y * vb.x;
}
return sum < 0;
}
/// <summary> 判断角的类型 </summary>
public static bool GetAngleType(Auriculare auriculare, bool isClockWise) {
// 角度是否小于180
// oa & ob 之间的夹角,(右手法则)
// 逆时针顺序是相反的
Vector2 a = auriculare.aPoint;
Vector2 b = auriculare.bPoint;
Vector2 c = auriculare.cPoint;
float f = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
bool flag = isClockWise ? f > 0 : f < 0;
if (f == 0) { return false;/*平角*/ }
else if (flag) { return true;/*劣角*/ }
else { return false;/*优角*/ }
}
/// <summary> p点是否在点a,b,c组成的三角形内,或边上 </summary>
public static bool IsInsideTriangle(Auriculare auriculare, Vector2 p) {
// p点是否在abc三角形内
Vector2 a = auriculare.aPoint;
Vector2 b = auriculare.bPoint;
Vector2 c = auriculare.cPoint;
float c1 = (b.x - a.x) * (p.y - b.y) - (b.y - a.y) * (p.x - b.x);
float c2 = (c.x - b.x) * (p.y - c.y) - (c.y - b.y) * (p.x - c.x);
float c3 = (a.x - c.x) * (p.y - a.y) - (a.y - c.y) * (p.x - a.x);
return (c1 > 0f && c2 >= 0f && c3 >= 0f) || (c1 < 0f && c2 <= 0f && c3 <= 0f);
}
#endregion
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4372bf8b5aa864f47bc02eec462942d7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,127 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 贝塞尔曲线计算边缘点
/// </summary>
public class UnitAlgorithmEdgePoint : UnitAlgorithm<DataPolygon> {
/// <summary> 三阶贝塞尔曲线计算边缘点 </summary>
public UnitAlgorithmEdgePoint() { }
public void Compute(DataPolygon data) {
//List<DataPoint> points = new List<DataPoint>(data.points);
//List<Vector3> edgePoints = new List<Vector3>();
//for (int i = 0; i < points.Count; i++) {
// DataPoint aPoint = points.LoopIndex(i);
// DataPoint bPoint = points.LoopIndex(i + 1);
// if (!aPoint.isCurveAfter && !bPoint.isCurveFront) {
// edgePoints.Add(aPoint.position);
// }
// if (!aPoint.isCurveAfter && bPoint.isCurveFront) {
// edgePoints.AddRange(CreateLine(aPoint, bPoint, bPoint.frontBezier, data.edgeSmooth));
// }
// if (aPoint.isCurveAfter && !bPoint.isCurveFront) {
// edgePoints.AddRange(CreateLine(aPoint, bPoint, aPoint.afterBezier, data.edgeSmooth));
// }
// if (aPoint.isCurveAfter && bPoint.isCurveFront) {
// edgePoints.AddRange(CreateLine(aPoint, bPoint, data.edgeSmooth));
// }
//}
//data.edgePoints = edgePoints;
}
#region
/// <summary> 二阶贝塞尔线段 </summary>
public List<Vector3> CreateLine(DataPoint aPoint, DataPoint bPoint, Vector3 b, float smooth) {
List<Vector3> points = new List<Vector3>();
//方向,距离
Vector2 direction = (bPoint.position - aPoint.position).normalized;
float distance = Vector2.Distance(bPoint.position, aPoint.position);
//求余,得商数
int quotient = Quotient(distance, smooth);
//贝塞尔曲线点
Vector3 a = aPoint.position;
Vector3 c = bPoint.position;
for (int i = 0; i < quotient; i++) {
float t = i * (distance / quotient) / distance;
Vector2 position = ComputeBezier(a, b, c, t);
points.Add(position);
}
return points;
}
/// <summary> 三阶贝塞尔线段 </summary>
public List<Vector3> CreateLine(DataPoint aPoint, DataPoint bPoint, float smooth) {
List<Vector3> points = new List<Vector3>();
//方向,距离
Vector2 direction = (bPoint.position - aPoint.position).normalized;
float distance = Vector2.Distance(bPoint.position, aPoint.position);
//求余,得商数
int quotient = Quotient(distance, smooth);
//贝塞尔曲线点
//Vector3 a = aPoint.position;
//Vector3 b = aPoint.afterBezier;
//Vector3 c = bPoint.frontBezier;
//Vector3 d = bPoint.position;
//for (int i = 0; i < quotient; i++) {
// float t = i * (distance / quotient) / distance;
// Vector2 position = ComputeBezier(a, b, c, d, t);
// points.Add(position);
//}
return points;
}
#endregion
#region
/// <summary> 商数 </summary>
public static int Quotient(float distance, float smooth) {
int a = (int)(distance * 1000);
int b = (int)(smooth * 1000);
return Math.DivRem(a, b, out int remainder);
}
/// <summary>
/// 一阶贝塞尔算法
/// </summary>
/// <param name="a">起点</param>
/// <param name="b">终点</param>
/// <param name="t">进度</param>
/// <returns></returns>
public static Vector3 ComputeBezier(Vector3 a, Vector3 b, float t) {
return a + (b - a) * t;
}
/// <summary>
/// 二阶贝塞尔算法
/// </summary>
/// <param name="a">起点</param>
/// <param name="b">贝塞尔点</param>
/// <param name="c">终点</param>
/// <param name="t">进度</param>
/// <returns>当前进度的曲线点</returns>
public static Vector3 ComputeBezier(Vector3 a, Vector3 b, Vector3 c, float t) {
Vector3 aa = a + (b - a) * t;
Vector3 bb = b + (c - b) * t;
return aa + (bb - aa) * t;
}
/// <summary>
/// 三阶贝塞尔算法
/// </summary>
/// <param name="a">起点</param>
/// <param name="b">起点的贝塞尔点</param>
/// <param name="c">终点的贝塞尔点</param>
/// <param name="d">终点</param>
/// <param name="t">进度</param>
/// <returns>当前进度的曲线点</returns>
public static Vector3 ComputeBezier(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float t) {
Vector3 aa = a + (b - a) * t;
Vector3 bb = b + (c - b) * t;
Vector3 cc = c + (d - c) * t;
Vector3 aaa = aa + (bb - aa) * t;
Vector3 bbb = bb + (cc - bb) * t;
return aaa + (bbb - aaa) * t;
}
#endregion
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c1c3f376c874a464db8a962d4a2f4730
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,107 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
/// <summary>
/// 三角形合并网格
/// </summary>
public class UnitAlgorithmMergeTriangle : UnitAlgorithm<DataPlate> {
/// <summary> 三角形合并网格 </summary>
public UnitAlgorithmMergeTriangle() { }
public void Compute(DataPlate data) {
List<DataTriangle> polygons = data.triangles;
//三角形合并
List<Vector3> vertices = vertices = MergeVertices(polygons);
List<int> triangles = JobFindTriangleIndex(polygons, vertices);
//展开uv (顶点去掉z坐标就是未缩放的平面UV)
List<Vector2> uv = new List<Vector2>();
for (int i = 0; i < vertices.Count; i++) { uv.Add(vertices[i]); }
//附加数据
data.designMesh = new Mesh();
data.designMesh.vertices = vertices.ToArray();
data.designMesh.uv = uv.ToArray();
data.designMesh.triangles = triangles.ToArray();
data.designMesh.RecalculateBounds();
data.designMesh.RecalculateNormals();
}
/// <summary> 合并顶点 </summary>
private List<Vector3> MergeVertices(List<DataTriangle> polygons) {
List<Vector3> vertices = new List<Vector3>();
for (int i = 0; i < polygons.Count; i++) {
vertices.Add(polygons[i].a);
vertices.Add(polygons[i].b);
vertices.Add(polygons[i].c);
}
return vertices.Distinct().ToList();
}
#region Jobs
/// <summary> 三角形顶点索引查找作业 </summary>
private List<int> JobFindTriangleIndex(List<DataTriangle> polygons, List<Vector3> vertices) {
NativeArray<DataTriangle> dataArray = new NativeArray<DataTriangle>(polygons.ToArray(), Allocator.TempJob);
NativeArray<Vector3> verticeArray = new NativeArray<Vector3>(vertices.ToArray(), Allocator.TempJob);
NativeArray<Triangle> trianglesArray = new NativeArray<Triangle>(polygons.Count, Allocator.TempJob);
TriangleIndex triangleIndex = new TriangleIndex();
triangleIndex.dataArray = dataArray;
triangleIndex.vertices = verticeArray;
triangleIndex.triangles = trianglesArray;
JobHandle dependency = new JobHandle();
JobHandle handle = triangleIndex.ScheduleParallel(polygons.Count, 2048, dependency);
handle.Complete();
List<int> triangles = new List<int>();
for (int i = 0; i < trianglesArray.Length; i++) {
triangles.Add(trianglesArray[i].a);
triangles.Add(trianglesArray[i].b);
triangles.Add(trianglesArray[i].c);
}
dataArray.Dispose();
verticeArray.Dispose();
trianglesArray.Dispose();
return triangles;
}
/// <summary> 三角形顶点索引查找作业 </summary>
[BurstCompile]
public struct TriangleIndex : IJobFor {
[ReadOnly] public NativeArray<DataTriangle> dataArray;
[ReadOnly] public NativeArray<Vector3> vertices;
public NativeArray<Triangle> triangles;
public void Execute(int index) {
DataTriangle dataTriangle = dataArray[index];
Triangle triangle = new Triangle();
bool a = false, b = false, c = false;
for (int i = 0; i < vertices.Length; i++) {
Vector3 vector = vertices[i];
if (dataTriangle.a == vector) { triangle.a = i; a = true; }
if (dataTriangle.b == vector) { triangle.b = i; b = true; }
if (dataTriangle.c == vector) { triangle.c = i; c = true; }
if (a && b && c) { break; }
}
triangles[index] = triangle;
}
}
/// <summary> 三角形顶点索引 </summary>
public struct Triangle { public int a, b, c; }
#endregion
/// <summary> 是否启用计时器 </summary>
private readonly bool isEnableTimer = true;
/// <summary> 计时器 </summary>
private void Chronoscope(string content, Action action) {
if (!isEnableTimer) { action?.Invoke(); return; }
float time = Time.realtimeSinceStartup;
action?.Invoke();
float consumed = Time.realtimeSinceStartup - time;
Debug.Log($"{content}{consumed * 1000}");
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e4f1e7f586419604093e6609268f27b8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,95 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 合并三角形
/// </summary>
public class UnitAlgorithmMergeTriangles : UnitAlgorithm<DataPolygon> {
public void Compute(DataPolygon data) {
//List<DataTriangle> triangles = new List<DataTriangle>(data.triangles);
//index = 0;
//Merge(triangles);
//data.triangles = triangles;
//ModuleCore.I.VisualPolygon.UpdateVisual(data);
}
private int index;
private int maxIndex;
/// <summary> 取一个三角形出来 匹配剩下的三角形 符合条件则合并 </summary>
private void Merge(List<DataTriangle> triangles) {
if (index > triangles.Count) { return; }
DataTriangle aT = triangles[0];
triangles.Remove(aT);
maxIndex = triangles.Count;
for (int i = 0; i < triangles.Count; i++) {
DataTriangle bT = triangles[i];
//ab同边
if (MergeConditions(bT.a, bT.b, bT, ref aT)) { triangles.Remove(bT); continue; }
//bc同边
if (MergeConditions(bT.b, bT.c, bT, ref aT)) { triangles.Remove(bT); continue; }
//ca同边
if (MergeConditions(bT.c, bT.a, bT, ref aT)) { triangles.Remove(bT); continue; }
}
index = maxIndex == triangles.Count ? index + 1 : 0;
Debug.Log($"{index} , {maxIndex} , {triangles.Count}");
triangles.Add(aT);
Merge(triangles);
}
/// <summary> 匹配三角形 符合条件则合并 无法合并则返回 true </summary>
private bool Merge(List<DataTriangle> triangles, DataTriangle aT) {
for (int i = 0; i < triangles.Count; i++) {
DataTriangle bT = triangles[i];
//ab同边
if (MergeConditions(bT.a, bT.b, bT, ref aT)) { triangles.Remove(bT); }
//bc同边
if (MergeConditions(bT.b, bT.c, bT, ref aT)) { triangles.Remove(bT); }
//ca同边
if (MergeConditions(bT.c, bT.a, bT, ref aT)) { triangles.Remove(bT); }
}
return true;
}
/// <summary> 计算三角形内是否包含其他点 </summary>
private bool IsInsideTriangle(DataTriangle triangle, Vector3 point) {
if (triangle.a == point) { return true; }
if (triangle.b == point) { return true; }
if (triangle.c == point) { return true; }
return false;
}
//检测合并条件是否满足
private bool MergeConditions(Vector3 a, Vector3 b, DataTriangle bT, ref DataTriangle aT) {
if (!IsInsideTriangle(aT, a, b, out Vector3 o)) { return false; }
if (!IsInsideTriangle(bT, a, b, out Vector3 c)) { return false; }
if (IsInsideTriangle(aT, c)) { return true; }
Vector3 oa = (o - a).normalized;
Vector3 ob = (o - b).normalized;
Vector3 oc = (o - c).normalized;
if (oc == oa) { aT.a = o; aT.b = b; aT.c = c; return true; }
if (oc == ob) { aT.a = o; aT.b = a; aT.c = c; return true; }
return false;
}
/// <summary> 计算三角形内是否包含其他点 </summary>
private bool IsInsideTriangle(DataTriangle triangle, Vector3 a, Vector3 b, out Vector3 o) {
if (triangle.a == a && triangle.b == b) { o = triangle.c; return true; }
if (triangle.a == b && triangle.b == a) { o = triangle.c; return true; }
if (triangle.a == a && triangle.c == b) { o = triangle.b; return true; }
if (triangle.a == b && triangle.c == a) { o = triangle.b; return true; }
if (triangle.b == a && triangle.c == b) { o = triangle.a; return true; }
if (triangle.b == b && triangle.c == a) { o = triangle.a; return true; }
o = a; return false;
}
/// <summary> p点是否在点a,b,c组成的三角形内,或边上 </summary>
public static bool IsInsideTriangle(DataTriangle auriculare, Vector2 p) {
// p点是否在abc三角形内
Vector2 a = auriculare.a;
Vector2 b = auriculare.b;
Vector2 c = auriculare.c;
float c1 = (b.x - a.x) * (p.y - b.y) - (b.y - a.y) * (p.x - b.x);
float c2 = (c.x - b.x) * (p.y - c.y) - (c.y - b.y) * (p.x - c.x);
float c3 = (a.x - c.x) * (p.y - a.y) - (a.y - c.y) * (p.x - a.x);
return (c1 > 0f && c2 >= 0f && c3 >= 0f) || (c1 < 0f && c2 <= 0f && c3 <= 0f);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 45d3c753563f5be468680173acf8b1e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,149 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UnitAlgorithmMeshVertex : UnitAlgorithm<DataPolygon> {
public class Line {
public Vector3 aPoint;
public Vector3 bPoint;
}
public class VertexUnit {
public Vector3 position;
}
public VertexUnit[,] unitArray;
public void Compute(DataPolygon data) {
//List<Vector3> edgePoints = new List<Vector3>(data.edgePoints);
////计算边界
//float minX = 0; float minY = 0;
//float maxX = 0; float maxY = 0;
//for (int i = 0; i < edgePoints.Count; i++) {
// if (edgePoints[i].x < minX) { minX = edgePoints[i].x; }
// if (edgePoints[i].x > maxX) { maxX = edgePoints[i].x; }
// if (edgePoints[i].y < minY) { minY = edgePoints[i].y; }
// if (edgePoints[i].y > maxY) { maxY = edgePoints[i].y; }
//}
//float wide = maxX - minX;
//float high = maxY - minY;
////求余,得商数
//int wideQuotient = Quotient(wide, 0.01f) + 1;
//int highQuotient = Quotient(high, 0.01f) + 1;
////平均间隔
//float wideAverage = wide / wideQuotient;
//float highAverage = high / highQuotient;
////计算内部网格点
//List<Vector3> vertices = new List<Vector3>();
//Vector3 origin = new Vector3(minX, minY);
//for (int i = 0; i < highQuotient; i++) {
// for (int j = 0; j < wideQuotient; j++) {
// Vector3 position = origin + new Vector3(j * wideAverage, i * highAverage);
// if (FindPlateInside(edgePoints, position)) { vertices.Add(position); }
// }
//}
////创建边缘线段,区分方向
//List<Line> horizontal = new List<Line>();
//List<Line> vertical = new List<Line>();
//for (int i = 0; i < edgePoints.Count; i++) {
// Line line = new Line();
// line.aPoint = edgePoints.LoopIndex(i + 0);
// line.bPoint = edgePoints.LoopIndex(i + 1);
// Vector3 direction = (line.bPoint - line.aPoint).normalized;
// if (Mathf.Abs(direction.x) >= 0.9) { horizontal.Add(line); }
// else { vertical.Add(line); }
//}
////计算水平线段顶点
//for (int i = 0; i < wideQuotient; i++) {
// Vector3 a = new Vector3(minX + i * wideAverage, minY - 1);
// Vector3 b = new Vector3(minX + i * wideAverage, maxY + 1);
// //Debug.Log($"线段:{a} , {b}");
// for (int j = 0; j < horizontal.Count; j++) {
// Line line = horizontal[j];
// //Debug.Log($"线段:{a} , {b} , {line.aPoint} , {line.bPoint}");
// if (!TryGetIntersectPoint(a, b, line.aPoint, line.bPoint, out Vector3 intersectPos)) { continue; }
// //Debug.Log($"交点:{intersectPos}");
// vertices.Add(intersectPos);
// }
//}
////计算垂直线段顶点
//for (int i = 0; i < highQuotient; i++) {
// Vector3 a = new Vector3(minX - 1, minY + i * highAverage);
// Vector3 b = new Vector3(maxX + 1, minY + i * highAverage);
// //Debug.Log($"线段:{a} , {b}");
// for (int j = 0; j < vertical.Count; j++) {
// Line line = vertical[j];
// //Debug.Log($"线段:{a} , {b} , {line.aPoint} , {line.bPoint}");
// if (!TryGetIntersectPoint(a, b, line.aPoint, line.bPoint, out Vector3 intersectPos)) { continue; }
// //Debug.Log($"交点:{intersectPos}");
// vertices.Add(intersectPos);
// }
//}
//Debug.Log(vertices.Count);
//data.vertices = vertices;
}
/// <summary> 商数 </summary>
public static int Quotient(float distance, float smooth) {
int a = (int)(distance * 1000);
int b = (int)(smooth * 1000);
return Math.DivRem(a, b, out int remainder);
}
/// <summary> 转角法查询位置是否在板片内 </summary>
public static bool FindPlateInside(List<Vector3> points, Vector3 position) {
double angles = 0;
for (int i = 0; i < points.Count; i++) {
Vector3 a = points.LoopIndex(i + 0) - position;
Vector3 b = points.LoopIndex(i + 1) - position;
float angle = Vector2.SignedAngle(a, b);
angles += angle;
}
int normal = (int)(angles * 1000);
return normal > 1000;
}
/// <summary>
/// 计算AB与CD两条线段的交点.
/// </summary>
/// <param name="a">A点</param>
/// <param name="b">B点</param>
/// <param name="c">C点</param>
/// <param name="d">D点</param>
/// <param name="intersectPos">AB与CD的交点</param>
/// <returns>是否相交 true:相交 false:未相交</returns>
private bool TryGetIntersectPoint(Vector3 a, Vector3 b, Vector3 c, Vector3 d, out Vector3 intersectPos) {
intersectPos = Vector3.zero;
Vector3 ab = b - a;
Vector3 ca = a - c;
Vector3 cd = d - c;
Vector3 v1 = Vector3.Cross(ca, cd);
// 不共面
if (Mathf.Abs(Vector3.Dot(v1, ab)) > 1e-6) { return false; }
// 平行
if (Vector3.Cross(ab, cd).sqrMagnitude <= 1e-6) { return false; }
Vector3 ad = d - a;
Vector3 cb = b - c;
// 快速排斥
if (Mathf.Min(a.x, b.x) > Mathf.Max(c.x, d.x) || Mathf.Max(a.x, b.x) < Mathf.Min(c.x, d.x)
|| Mathf.Min(a.y, b.y) > Mathf.Max(c.y, d.y) || Mathf.Max(a.y, b.y) < Mathf.Min(c.y, d.y)
|| Mathf.Min(a.z, b.z) > Mathf.Max(c.z, d.z) || Mathf.Max(a.z, b.z) < Mathf.Min(c.z, d.z)) {
return false;
}
// 跨立试验
if (Vector3.Dot(Vector3.Cross(-ca, ab), Vector3.Cross(ab, ad)) > 0
&& Vector3.Dot(Vector3.Cross(ca, cd), Vector3.Cross(cd, cb)) > 0) {
Vector3 v2 = Vector3.Cross(cd, ab);
float ratio = Vector3.Dot(v1, v2) / v2.sqrMagnitude;
intersectPos = a + ab * ratio;
return true;
}
return false;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9b4b2ff6807f9704cb50f12b41e2a0a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,59 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 菱形绘制三角形算法
/// </summary>
public class UnitAlgorithmRhombus : UnitAlgorithm<DataPlate> {
public void Compute(DataPlate data) {
List<DataTriangle> triangles = new List<DataTriangle>();
data.vertexGrid.Loop((x, y) => {
DataVertex vertex = data.vertexGrid.Get(x, y);
if (!vertex.isValid) { return; }
TryGet(data.vertexGrid, x, y + 1, ref vertex.above);
TryGet(data.vertexGrid, x, y - 1, ref vertex.below);
TryGet(data.vertexGrid, x - 1, y, ref vertex.left);
TryGet(data.vertexGrid, x + 1, y, ref vertex.right);
TryGet(data.vertexGrid, x - 1, y + 1, ref vertex.leftAbove);
TryGet(data.vertexGrid, x - 1, y - 1, ref vertex.leftBelow);
TryGet(data.vertexGrid, x + 1, y + 1, ref vertex.rightAbove);
TryGet(data.vertexGrid, x + 1, y - 1, ref vertex.rightBelow);
//默认绘制左上角
if (vertex.above != null && vertex.left != null) {
triangles.Add(CreateDataTriangle(vertex, vertex.left, vertex.above));
}
//默认绘制右下角
if (vertex.below != null && vertex.right != null) {
triangles.Add(CreateDataTriangle(vertex, vertex.right, vertex.below));
}
//如果右上角点不存在,则尝试绘制右上角
if (vertex.rightAbove == null && vertex.above != null && vertex.right != null) {
triangles.Add(CreateDataTriangle(vertex, vertex.above, vertex.right));
}
//如果左下角点不存在,则尝试绘制左下角
if (vertex.leftBelow == null && vertex.below != null && vertex.left != null) {
triangles.Add(CreateDataTriangle(vertex, vertex.below, vertex.left));
}
});
data.triangles = triangles;
}
/// <summary> 校验性获取网格上的点 </summary>
private void TryGet(GridTool<DataVertex> grid, int x, int y, ref DataVertex vertex) {
vertex = null;
if (!grid.TryGet(x, y, out DataVertex data)) { return; }
if (data.isValid) { vertex = data; }
}
/// <summary> 创建三角形 </summary>
private DataTriangle CreateDataTriangle(DataVertex a, DataVertex b, DataVertex c) {
DataTriangle triangle = new DataTriangle();
triangle.b = a.design;
triangle.c = b.design;
triangle.a = c.design;
return triangle;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e45b841993dc7c04584b87f7794cf2fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,35 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UnitAlgorithmSubdivision : UnitAlgorithm<DataPolygon> {
public void Compute(DataPolygon data) {
//List<DataTriangle> triangles = new List<DataTriangle>(data.triangles);
//List<DataTriangle> subdivision = new List<DataTriangle>();
//for (int i = 0; i < triangles.Count; i++) {
// subdivision.AddRange(Compute(triangles[i]));
//}
//subdivision.AddRange(Subdivision(triangles[121], data.edgeSmooth));
//data.triangles = subdivision;
}
private List<DataTriangle> Compute(DataTriangle triangle) {
float ab = Vector3.Distance(triangle.a, triangle.b);
float bc = Vector3.Distance(triangle.b, triangle.c);
float ca = Vector3.Distance(triangle.c, triangle.a);
if (ab > bc && ab > ca && ab > 0.02f) { return Compute(triangle.c, triangle.a, triangle.b); }
if (bc > ab && bc > ca && bc > 0.02f) { return Compute(triangle.a, triangle.b, triangle.c); }
if (ca > bc && ca > ab && ca > 0.02f) { return Compute(triangle.b, triangle.c, triangle.a); }
return new List<DataTriangle> { triangle };
}
private List<DataTriangle> Compute(Vector3 a, Vector3 b, Vector3 c) {
Vector3 direction = b - c;
Vector3 d = c + direction * 0.5f;
DataTriangle aT = new DataTriangle { a = a, b = d, c = c };
DataTriangle bT = new DataTriangle { a = a, b = b, c = d };
return new List<DataTriangle> { aT, bT, };
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bb4aa74668cf2134eb322b3a40d74c29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,150 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 顶点算法
/// </summary>
public class UnitAlgorithmVertex : UnitAlgorithm<DataPlate> {
public class SideVertex : IComparable<SideVertex> {
public float distance;
public DataVertex vertex;
public int CompareTo(SideVertex other) {
return other.distance >= distance ? 1 : -1;
}
}
public void Compute(DataPlate data) {
float smooth = data.smooth;
DataBorder border = data.border;
List<Vector3> edgePoints = new List<Vector3>(data.edgePoints);
int wide = Mathf.FloorToInt(border.Wide / smooth) + 1;
int high = Mathf.FloorToInt(border.High / smooth) + 1;
//计算内部顶点
data.vertexGrid = new GridTool<DataVertex>(wide, high, (x, y) => {
Vector3 position = border.MinPoint + new Vector3(x * smooth, y * smooth);
DataVertex vertex = new DataVertex();
vertex.isValid = FindPlateInside(edgePoints, position);
vertex.design = position;
return vertex;
});
//边缘所有的线段
for (int i = 0; i < data.sides.Count; i++) {
Compute(data.sides[i], wide, high, border, smooth, data.vertexGrid);
}
}
/// <summary> 向网格和边缘写入顶点数据 </summary>
private void Compute(DataSide side, int wide, int high, DataBorder border, float smooth, GridTool<DataVertex> grid) {
DataLine[] lines = side.lines;
List<SideVertex> sideVertices = new List<SideVertex>();
//计算水平线段顶点
for (int x = 0; x < wide; x++) {
Vector3 a = new Vector3(border.minX + x * smooth, border.minY - 1);
Vector3 b = new Vector3(border.minX + x * smooth, border.maxY + 1);
for (int i = 0; i < lines.Length; i++) {
DataVertex vertex = Compute(a, b, lines[i], smooth, border, grid);
if (vertex == null) { continue; }
float distance = Vector3.Distance(lines[i].a, vertex.design) + lines[i].origin;
SideVertex sideVertex = new SideVertex();
sideVertex.distance = distance;
sideVertex.vertex = vertex;
sideVertices.Add(sideVertex);
}
}
//计算垂直线段顶点
for (int y = 0; y < high; y++) {
Vector3 a = new Vector3(border.minX - 1, border.minY + y * smooth);
Vector3 b = new Vector3(border.maxX + 1, border.minY + y * smooth);
for (int i = 0; i < lines.Length; i++) {
DataVertex vertex = Compute(a, b, lines[i], smooth, border, grid);
if (vertex == null) { continue; }
float distance = Vector3.Distance(lines[i].a, vertex.design) + lines[i].origin;
SideVertex sideVertex = new SideVertex();
sideVertex.distance = distance;
sideVertex.vertex = vertex;
sideVertices.Add(sideVertex);
}
}
sideVertices.Sort();
List<DataVertex> vertices = new List<DataVertex>();
for (int i = 0; i < sideVertices.Count; i++) {
vertices.Add(sideVertices[i].vertex);
}
side.vertices = vertices.ToArray();
}
/// <summary> 向网格写入边缘顶点数据 </summary>
private DataVertex Compute(Vector3 a, Vector3 b, DataLine line, float smooth, DataBorder border, GridTool<DataVertex> grid) {
//计算交点
if (!TryGetIntersectPoint(a, b, line.a, line.b, out Vector3 IntersectPoint)) { return null; }
//计算顶点xy
Vector3 offset = new Vector3(smooth, smooth, 0) * 0.3f;
Vector3 position = IntersectPoint - border.MinPoint + offset;
int vertexX = Mathf.FloorToInt(position.x / smooth);
int vertexY = Mathf.FloorToInt(position.y / smooth);
//填充数据
DataVertex vertex = grid.Get(vertexX, vertexY);
vertex.isValid = true;
vertex.design = IntersectPoint;
return vertex;
}
/// <summary> 转角法查询位置是否在板片内 </summary>
public static bool FindPlateInside(List<Vector3> points, Vector3 position) {
double angles = 0;
for (int i = 0; i < points.Count; i++) {
Vector3 a = points.LoopIndex(i + 0) - position;
Vector3 b = points.LoopIndex(i + 1) - position;
float angle = Vector2.SignedAngle(a, b);
angles += angle;
}
int normal = (int)(angles * 1000);
return normal > 1000;
}
/// <summary>
/// 计算AB与CD两条线段的交点.
/// </summary>
/// <param name="a">A点</param>
/// <param name="b">B点</param>
/// <param name="c">C点</param>
/// <param name="d">D点</param>
/// <param name="intersectPos">AB与CD的交点</param>
/// <returns>是否相交 true:相交 false:未相交</returns>
private bool TryGetIntersectPoint(Vector3 a, Vector3 b, Vector3 c, Vector3 d, out Vector3 intersectPos) {
intersectPos = Vector3.zero;
Vector3 ab = b - a;
Vector3 ca = a - c;
Vector3 cd = d - c;
Vector3 v1 = Vector3.Cross(ca, cd);
// 不共面
if (Mathf.Abs(Vector3.Dot(v1, ab)) > 1e-6) { return false; }
// 平行
if (Vector3.Cross(ab, cd).sqrMagnitude <= 1e-6) { return false; }
Vector3 ad = d - a;
Vector3 cb = b - c;
// 快速排斥
if (Mathf.Min(a.x, b.x) > Mathf.Max(c.x, d.x) || Mathf.Max(a.x, b.x) < Mathf.Min(c.x, d.x)
|| Mathf.Min(a.y, b.y) > Mathf.Max(c.y, d.y) || Mathf.Max(a.y, b.y) < Mathf.Min(c.y, d.y)
|| Mathf.Min(a.z, b.z) > Mathf.Max(c.z, d.z) || Mathf.Max(a.z, b.z) < Mathf.Min(c.z, d.z)) {
return false;
}
// 跨立试验
if (Vector3.Dot(Vector3.Cross(-ca, ab), Vector3.Cross(ab, ad)) > 0
&& Vector3.Dot(Vector3.Cross(ca, cd), Vector3.Cross(cd, cb)) > 0) {
Vector3 v2 = Vector3.Cross(cd, ab);
float ratio = Vector3.Dot(v1, v2) / v2.sqrMagnitude;
intersectPos = a + ab * ratio;
return true;
}
return false;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4a24da15970a3654386664f8d6503d04
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: