This commit is contained in:
MuHua-123
2024-11-29 18:10:02 +08:00
parent 84243e75a8
commit 698464b9d7
81 changed files with 3073 additions and 671 deletions
@@ -0,0 +1,151 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 烘焙顶点计算
/// </summary>
public class UnitAlgorithmBakingVertex : UnitAlgorithm<DataPlateBaking> {
/// <summary> 烘焙顶点计算 </summary>
public UnitAlgorithmBakingVertex() { }
public void Compute(DataPlateBaking plateBaking) {
DataBorder border = plateBaking.border;
Vector3[] points = border.points;
//计算内部顶点
//plateBaking.grid = new GridTool<DataPlateVertex>(border.GridWide, border.GridHigh, (x, y) => {
// Vector3 position = border.MinPoint + new Vector3(x * border.smooth, y * border.smooth);
// DataPlateVertex vertex = new DataPlateVertex();
// vertex.isValid = FindPlateInside(points, position);
// vertex.position = position;
// return vertex;
//});
//List<DataPlateSide> plateSides = plateBaking.plate.plateSides;
//边缘所有的线段
//for (int i = 0; i < plateSides.Count; i++) {
//Compute(plateSides[i], border.GridWide, border.GridHigh, border, border.smooth, plateBaking.grid);
//}
}
/// <summary> 向网格和边缘写入顶点数据 </summary>
private void Compute(DataPlateSide side, int wide, int high, DataBorder border, float smooth, GridTool<DataPlateVertex> grid) {
DataPlateLine[] lines = side.dataBaking.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++) {
DataPlateVertex vertex = Compute(a, b, lines[i], smooth, border, grid);
if (vertex == null) { continue; }
float distance = Vector3.Distance(lines[i].a, vertex.position) + 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++) {
DataPlateVertex vertex = Compute(a, b, lines[i], smooth, border, grid);
if (vertex == null) { continue; }
float distance = Vector3.Distance(lines[i].a, vertex.position) + lines[i].origin;
SideVertex sideVertex = new SideVertex();
sideVertex.distance = distance;
sideVertex.vertex = vertex;
sideVertices.Add(sideVertex);
}
}
sideVertices.Sort();
List<DataPlateVertex> vertices = new List<DataPlateVertex>();
for (int i = 0; i < sideVertices.Count; i++) {
vertices.Add(sideVertices[i].vertex);
}
//side.vertices = vertices.ToArray();
}
/// <summary> 向网格写入边缘顶点数据 </summary>
private DataPlateVertex Compute(Vector3 a, Vector3 b, DataPlateLine line, float smooth, DataBorder border, GridTool<DataPlateVertex> 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);
//填充数据
DataPlateVertex vertex = grid.Get(vertexX, vertexY);
vertex.isValid = true;
vertex.position = IntersectPoint;
return vertex;
}
public class SideVertex : IComparable<SideVertex> {
public float distance;
public DataPlateVertex vertex;
public int CompareTo(SideVertex other) {
return other.distance >= distance ? 1 : -1;
}
}
/// <summary> 转角法查询位置是否在板片内 </summary>
public static bool FindPlateInside(Vector3[] points, Vector3 position) {
double angles = 0;
for (int i = 0; i < points.Length; 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: e8b300a54238da848b5628cef749aeb2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -11,6 +11,32 @@ public class UnitAlgorithmBezier : UnitAlgorithm<DataPlate> {
/// <summary> 贝塞尔算法 </summary>
public UnitAlgorithmBezier() { }
public void Compute(DataPlate data) {
List<Vector3> points = new List<Vector3>();
for (int i = 0; i < data.plateSides.Count; i++) {
Compute(data.plateSides[i]);
//points.AddRange(data.plateSides[i].positions);
}
//去除重复边缘点
points = points.Distinct().ToList();
//data.edgePoints = points;
}
public void Compute(DataPlateSide 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;
dataBezier.Compute();
//data.length = dataBezier.length;
//data.positions = dataBezier.positions.ToArray();
//data.lines = dataBezier.lines.ToArray();
}
public class DataBezier {
//输入
public float smooth;
@@ -22,97 +48,57 @@ public class UnitAlgorithmBezier : UnitAlgorithm<DataPlate> {
//输出
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);
public List<DataPlateLine> lines = new List<DataPlateLine>();
/// <summary> 计算曲线细分点 </summary>
public void Compute() {
//细分点
if (bezier == Bezier.) { positions = new List<Vector3> { aPoint, bPoint }; }
if (bezier == Bezier.) { positions = Compute(aPoint, aBezier, bPoint); }
if (bezier == Bezier.) { positions = Compute(aPoint, aBezier, bBezier, bPoint); }
//线段
lines = new List<DataPlateLine>();
for (int i = 0; i < positions.Count - 1; i++) {
DataPlateLine line = new DataPlateLine();
line.a = positions.LoopIndex(i + 0);
line.b = positions.LoopIndex(i + 1);
line.origin = length;
lines.Add(line);
length += line.Distance;
}
}
//去除重复边缘点
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);
/// <summary> 二阶贝塞尔线段 </summary>
private List<Vector3> Compute(Vector3 a, Vector3 b, Vector3 c) {
List<Vector3> points = new List<Vector3>();
//方向,距离
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;
}
if (data.bezier == Bezier.) {
data.positions = Compute(data.aPoint, data.aBezier, data.bPoint, data.smooth);
/// <summary> 三阶贝塞尔线段 </summary>
private List<Vector3> Compute(Vector3 a, Vector3 b, Vector3 c, Vector3 d) {
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;
}
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>
@@ -1,28 +1,35 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary>
/// 散点边界算法
/// </summary>
public class UnitAlgorithmBorder : UnitAlgorithm<DataPlate> {
public class UnitAlgorithmBorder : UnitAlgorithm<DataPlateBaking> {
/// <summary> 散点边界算法 </summary>
public UnitAlgorithmBorder() { }
public void Compute(DataPlate plate) {
List<Vector3> edgePoints = new List<Vector3>(plate.edgePoints);
plate.border = Border(edgePoints);
public void Compute(DataPlateBaking plateBaking) {
//List<DataPlateSide> plateSides = plateBaking.plate.plateSides;
//List<Vector3> points = new List<Vector3>();
//for (int i = 0; i < plateSides.Count; i++) {
// points.AddRange(plateSides[i].dataBaking.positions);
//}
//plateBaking.border = Border(points.Distinct().ToArray());
}
public static DataBorder Border(List<Vector3> points) {
public static DataBorder Border(Vector3[] points) {
float minX = 0; float minY = 0;
float maxX = 0; float maxY = 0;
for (int i = 0; i < points.Count; i++) {
for (int i = 0; i < points.Length; 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);
return new DataBorder(minX, maxX, minY, maxY, points);
}
}
@@ -6,7 +6,7 @@ using UnityEngine;
/// <summary>
/// 多边形耳切法
/// </summary>
public class UnitAlgorithmEarCutting : UnitAlgorithm<DataPlate> {
public class UnitAlgorithmEarCutting : UnitAlgorithm<DataPlateDesign> {
/// <summary> 多边形耳切法 </summary>
public UnitAlgorithmEarCutting() { }
@@ -17,27 +17,27 @@ public class UnitAlgorithmEarCutting : UnitAlgorithm<DataPlate> {
public Vector3 cPoint;//+1
}
public void Compute(DataPlate data) {
List<Vector3> points = new List<Vector3>(data.edgePoints);
public void Compute(DataPlateDesign plateDesign) {
List<Vector3> points = new List<Vector3>(plateDesign.points);
//判断散列点排序方向
Vector3[] allArray = points.ToArray();
bool isClockWise = IsClockWise(allArray);
Vector3[] allPoints = plateDesign.points;
bool isClockWise = IsClockWise(allPoints);
//耳切法生成三角形
List<DataTriangle> triangles = new List<DataTriangle>();
ComputeAuriculare(triangles, points, allArray, isClockWise);
data.triangles = triangles;
ComputeAuriculare(triangles, points, allPoints, isClockWise);
plateDesign.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);
public static void ComputeAuriculare(List<DataTriangle> triangles, List<Vector3> edgePoints, Vector3[] allPoints, bool isClockWise) {
List<DataTriangle> temp = ComputeAuriculare(edgePoints, allPoints, isClockWise);
if (temp.Count == 0) { return; }
triangles.AddRange(temp);
ComputeAuriculare(triangles, edgePoints, allArray, isClockWise);
ComputeAuriculare(triangles, edgePoints, allPoints, isClockWise);
}
/// <summary> 计算一个有效的耳点 </summary>
public static List<DataTriangle> ComputeAuriculare(List<Vector3> edgePoints, Vector3[] allArray, bool isClockWise) {
public static List<DataTriangle> ComputeAuriculare(List<Vector3> edgePoints, Vector3[] allPoints, bool isClockWise) {
Vector3[] array = edgePoints.ToArray();
List<DataTriangle> polygons = new List<DataTriangle>();
for (int i = 0; i < array.Length; i++) {
@@ -45,7 +45,7 @@ public class UnitAlgorithmEarCutting : UnitAlgorithm<DataPlate> {
// 等于180,大于180,不可能为耳点
if (!GetAngleType(auriculare, isClockWise)) { continue; }
// 包含其他点,不可能为耳点
if (IsInsideTriangle(auriculare, allArray)) { continue; }
if (IsInsideTriangle(auriculare, allPoints)) { continue; }
// 包含其他耳点,不可能成为耳点
if (!IsInsideAuriculare(auriculare, edgePoints)) { continue; }
edgePoints.Remove(auriculare.aPoint);
@@ -35,7 +35,7 @@ public class UnitAlgorithmEdgePoint : UnitAlgorithm<DataPolygon> {
#region
/// <summary> 二阶贝塞尔线段 </summary>
public List<Vector3> CreateLine(DataPoint aPoint, DataPoint bPoint, Vector3 b, float smooth) {
public List<Vector3> CreateLine(DataPlatePoint aPoint, DataPlatePoint bPoint, Vector3 b, float smooth) {
List<Vector3> points = new List<Vector3>();
//方向,距离
Vector2 direction = (bPoint.position - aPoint.position).normalized;
@@ -53,7 +53,7 @@ public class UnitAlgorithmEdgePoint : UnitAlgorithm<DataPolygon> {
return points;
}
/// <summary> 三阶贝塞尔线段 </summary>
public List<Vector3> CreateLine(DataPoint aPoint, DataPoint bPoint, float smooth) {
public List<Vector3> CreateLine(DataPlatePoint aPoint, DataPlatePoint bPoint, float smooth) {
List<Vector3> points = new List<Vector3>();
//方向,距离
Vector2 direction = (bPoint.position - aPoint.position).normalized;
@@ -0,0 +1,239 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
/// <summary>
/// 贝塞尔算法 边缘细分 Jobs
/// </summary>
public class UnitAlgorithmJobsSideSubdivision : UnitAlgorithm<DataPlateDesign>, UnitAlgorithm<DataPlateBaking> {
/// <summary> 贝塞尔算法 边缘细分 Jobs </summary>
public UnitAlgorithmJobsSideSubdivision() { }
public void Compute(DataPlateDesign plateDesign) {
int count = plateDesign.plate.plateSides.Count;
List<DataPlateSide> plateSides = plateDesign.plate.plateSides;
NativeArray<JobSubdivision> jobSubdivisions = new NativeArray<JobSubdivision>(count, Allocator.TempJob);
NativeArray<JobHandle> jobHandles = new NativeArray<JobHandle>(count, Allocator.TempJob);
//创建作业任务
for (int i = 0; i < count; i++) {
jobSubdivisions[i] = ToJob(plateSides[i]);
jobHandles[i] = jobSubdivisions[i].Schedule();
}
//执行作业
JobHandle.CompleteAll(jobHandles);
//作业结果转换
List<Vector3> points = new List<Vector3>();
for (int i = 0; i < count; i++) {
DataPlateSideDesign design = plateSides[i].dataDesign;
JobToDesign(design, jobSubdivisions[i]);
points.AddRange(design.positions);
}
plateDesign.points = points.Distinct().ToArray();
//释放作业
jobSubdivisions.Dispose();
jobHandles.Dispose();
}
public void Compute(DataPlateBaking plateBaking) {
//int count = plateBaking.plate.plateSides.Count;
//List<DataPlateSide> plateSides = plateBaking.plate.plateSides;
//NativeArray<JobSubdivision> jobSubdivisions = new NativeArray<JobSubdivision>(count, Allocator.Temp);
//NativeArray<JobHandle> jobHandles = new NativeArray<JobHandle>(count, Allocator.Temp);
////创建作业任务
//for (int i = 0; i < count; i++) {
// jobSubdivisions[i] = ToJob(plateSides[i]);
// jobHandles[i] = jobSubdivisions[i].Schedule();
//}
////执行作业
//JobHandle.CompleteAll(jobHandles);
////作业结果转换
////List<Vector3> points = new List<Vector3>();
//for (int i = 0; i < count; i++) {
// DataPlateSideBaking sideBaking = plateSides[i].dataBaking;
// JobToBaking(sideBaking, jobSubdivisions[i]);
// //points.AddRange(sideBaking.positions);
//}
////plateBaking.points = points.Distinct().ToArray();
}
/// <summary> 转换作业系统数据 </summary>
public JobSubdivision ToJob(DataPlateSide side) {
JobSubdivision jobSubdivision = new JobSubdivision();
jobSubdivision.bezier = side.bezier;
jobSubdivision.aPoint = side.aPoint.position;
jobSubdivision.bPoint = side.bPoint.position;
jobSubdivision.aBezier = side.aBezier;
jobSubdivision.bBezier = side.bBezier;
//距离
float distance = Vector2.Distance(jobSubdivision.aPoint, jobSubdivision.bPoint);
jobSubdivision.distance = distance;
//求余,得商数
jobSubdivision.quotient = side.bezier == Bezier. ? 2 : 10;
jobSubdivision.length = new NativeArray<float>(1, Allocator.TempJob);
jobSubdivision.positions = new NativeArray<Vector3>(jobSubdivision.quotient, Allocator.TempJob);
jobSubdivision.lines = new NativeArray<JobDataLine>(jobSubdivision.quotient - 1, Allocator.TempJob);
return jobSubdivision;
}
/// <summary> 作业系统数据转换设计数据 </summary>
public void JobToDesign(DataPlateSideDesign design, JobSubdivision job) {
design.length = job.length[0];
design.positions = job.positions.ToArray();
DataPlateLine[] lines = new DataPlateLine[job.lines.Length];
for (int i = 0; i < job.lines.Length; i++) {
lines[i] = ToData(job.lines[i]);
}
design.lines = lines;
job.length.Dispose();
job.positions.Dispose();
job.lines.Dispose();
}
/// <summary> 作业系统数据转换烘焙数据 </summary>
public void JobToBaking(DataPlateSideBaking baking, JobSubdivision job) {
baking.length = job.length[0];
baking.positions = job.positions.ToArray();
DataPlateLine[] lines = new DataPlateLine[job.lines.Length];
for (int i = 0; i < job.lines.Length; i++) {
lines[i] = ToData(job.lines[i]);
}
baking.lines = lines;
job.length.Dispose();
job.positions.Dispose();
job.lines.Dispose();
}
/// <summary> 转换托管数据 </summary>
public DataPlateLine ToData(JobDataLine jobDataLine) {
DataPlateLine line = new DataPlateLine();
line.a = jobDataLine.a;
line.b = jobDataLine.b;
line.origin = jobDataLine.origin;
return line;
}
/// <summary> 作业系统数据 </summary>
public struct JobDataLine {
/// <summary> 线段起点a </summary>
public Vector3 a;
/// <summary> 线段终点b </summary>
public Vector3 b;
/// <summary> 原始距离 </summary>
public float origin;
}
[BurstCompile]
public struct JobSubdivision : IJob {
#region
/// <summary> 贝塞尔类型 </summary>
public Bezier bezier;
/// <summary> a点 </summary>
public Vector3 aPoint;
/// <summary> b点 </summary>
public Vector3 bPoint;
/// <summary> a点贝塞尔点 </summary>
public Vector3 aBezier;
/// <summary> b点贝塞尔点 </summary>
public Vector3 bBezier;
/// <summary> a-b距离 </summary>
public float distance;
/// <summary> 细分数 </summary>
public int quotient;
#endregion
#region
/// <summary> 总长度 </summary>
public NativeArray<float> length;
/// <summary> 点 </summary>
public NativeArray<Vector3> positions;
/// <summary> 线 </summary>
public NativeArray<JobDataLine> lines;
#endregion
public void Execute() {
//细分点
if (bezier == Bezier.) { ComputeBezierA(); }
if (bezier == Bezier.) { ComputeBezierB(); }
if (bezier == Bezier.) { ComputeBezierC(); }
//线段
for (int i = 0; i < quotient - 1; i++) {
JobDataLine line = new JobDataLine();
line.a = positions[i];
line.b = positions[i + 1];
line.origin = length[0];
lines[i] = line;
length[0] += Vector3.Distance(line.a, line.b);
}
}
public void ComputeBezierA() {
positions[0] = aPoint;
positions[1] = bPoint;
}
public void ComputeBezierB() {
for (int i = 0; i < quotient; i++) {
float t = i * (distance / quotient) / distance;
Vector2 position = ComputeBezier(aPoint, aBezier, bPoint, t);
positions[i] = position;
}
}
public void ComputeBezierC() {
for (int i = 0; i < quotient; i++) {
float t = i * (distance / quotient) / distance;
Vector2 position = ComputeBezier(aPoint, aBezier, bBezier, bPoint, t);
positions[i] = position;
}
}
}
/// <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: 39a35ef3408d163469eb7c66d1df96ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -10,12 +10,12 @@ using UnityEngine;
/// <summary>
/// 三角形合并网格
/// </summary>
public class UnitAlgorithmMergeTriangle : UnitAlgorithm<DataPlate> {
public class UnitAlgorithmMergeTriangle : UnitAlgorithm<DataPlateDesign>, UnitAlgorithm<DataPlateBaking> {
/// <summary> 三角形合并网格 </summary>
public UnitAlgorithmMergeTriangle() { }
public void Compute(DataPlate data) {
List<DataTriangle> polygons = data.triangles;
public void Compute(DataPlateDesign plateDesign) {
List<DataTriangle> polygons = plateDesign.triangles;
//三角形合并
List<Vector3> vertices = vertices = MergeVertices(polygons);
List<int> triangles = JobFindTriangleIndex(polygons, vertices);
@@ -23,12 +23,28 @@ public class UnitAlgorithmMergeTriangle : UnitAlgorithm<DataPlate> {
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();
plateDesign.mesh = new Mesh();
plateDesign.mesh.vertices = vertices.ToArray();
plateDesign.mesh.uv = uv.ToArray();
plateDesign.mesh.triangles = triangles.ToArray();
plateDesign.mesh.RecalculateBounds();
plateDesign.mesh.RecalculateNormals();
}
public void Compute(DataPlateBaking plateBaking) {
//List<DataTriangle> polygons = plateBaking.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]); }
////附加数据
//plateBaking.mesh = new Mesh();
//plateBaking.mesh.vertices = vertices.ToArray();
//plateBaking.mesh.uv = uv.ToArray();
//plateBaking.mesh.triangles = triangles.ToArray();
//plateBaking.mesh.RecalculateBounds();
//plateBaking.mesh.RecalculateNormals();
}
/// <summary> 合并顶点 </summary>
private List<Vector3> MergeVertices(List<DataTriangle> polygons) {
@@ -54,7 +70,7 @@ public class UnitAlgorithmMergeTriangle : UnitAlgorithm<DataPlate> {
triangleIndex.triangles = trianglesArray;
JobHandle dependency = new JobHandle();
JobHandle handle = triangleIndex.ScheduleParallel(polygons.Count, 2048, dependency);
JobHandle handle = triangleIndex.ScheduleParallel(polygons.Count, 32, dependency);
handle.Complete();
List<int> triangles = new List<int>();
@@ -5,55 +5,58 @@ using UnityEngine;
/// <summary>
/// 菱形绘制三角形算法
/// </summary>
public class UnitAlgorithmRhombus : UnitAlgorithm<DataPlate> {
public class UnitAlgorithmRhombus : UnitAlgorithm<DataPlateBaking> {
public void Compute(DataPlate data) {
public void Compute(DataPlateBaking plateBaking) {
List<DataTriangle> triangles = new List<DataTriangle>();
data.vertexGrid.Loop((x, y) => {
DataVertex vertex = data.vertexGrid.Get(x, y);
if (!vertex.isValid) { return; }
List<DataPlateVertex> vertexs = new List<DataPlateVertex>();
//plateBaking.grid.Loop((x, y) => {
// DataPlateVertex vertex = plateBaking.grid.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(plateBaking.grid, x, y + 1, ref vertex.above);
// TryGet(plateBaking.grid, x, y - 1, ref vertex.below);
// TryGet(plateBaking.grid, x - 1, y, ref vertex.left);
// TryGet(plateBaking.grid, 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;
// TryGet(plateBaking.grid, x - 1, y + 1, ref vertex.leftAbove);
// TryGet(plateBaking.grid, x - 1, y - 1, ref vertex.leftBelow);
// TryGet(plateBaking.grid, x + 1, y + 1, ref vertex.rightAbove);
// TryGet(plateBaking.grid, 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));
// }
// vertexs.Add(vertex);
//});
//plateBaking.triangles = triangles;
//plateBaking.vertexs = vertexs.ToArray();
}
/// <summary> 校验性获取网格上的点 </summary>
private void TryGet(GridTool<DataVertex> grid, int x, int y, ref DataVertex vertex) {
private void TryGet(GridTool<DataPlateVertex> grid, int x, int y, ref DataPlateVertex vertex) {
vertex = null;
if (!grid.TryGet(x, y, out DataVertex data)) { return; }
if (!grid.TryGet(x, y, out DataPlateVertex data)) { return; }
if (data.isValid) { vertex = data; }
}
/// <summary> 创建三角形 </summary>
private DataTriangle CreateDataTriangle(DataVertex a, DataVertex b, DataVertex c) {
private DataTriangle CreateDataTriangle(DataPlateVertex a, DataPlateVertex b, DataPlateVertex c) {
DataTriangle triangle = new DataTriangle();
triangle.b = a.design;
triangle.c = b.design;
triangle.a = c.design;
triangle.b = a.position;
triangle.c = b.position;
triangle.a = c.position;
return triangle;
}
}
@@ -0,0 +1,64 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 烘焙的缝合线
/// </summary>
public class UnitAlgorithmSutureBaking : UnitAlgorithm<DataSutureSide> {
/// <summary> 烘焙的缝合线 </summary>
public UnitAlgorithmSutureBaking() { }
public void Compute(DataSutureSide sutureSide) {
AllVertexs(sutureSide);
//缝合范围内的顶点
SetVertex(sutureSide);
//顶点转换位置
SetPositions(sutureSide);
}
/// <summary> 顶点距离数据 </summary>
private List<DataSutureSideVertex> GetVertex(DataPlateVertex[] vertexsArray, bool isReversal) {
float length = 0;
List<DataSutureSideVertex> vertexs = new List<DataSutureSideVertex>();
List<DataPlateVertex> sideVertexs = new List<DataPlateVertex>(vertexsArray);
if (isReversal) { sideVertexs.Reverse(); }
for (int i = 0; i < sideVertexs.Count - 1; i++) {
DataSutureSideVertex vertex = new DataSutureSideVertex(length, sideVertexs[i], sideVertexs[i + 1]);
vertexs.Add(vertex); length += vertex.Distance;
}
return vertexs;
}
/// <summary> 全部顶点 </summary>
private void AllVertexs(DataSutureSide sutureSide) {
DataPlateVertex[] vertexsArray = sutureSide.plateSide.dataBaking.vertexs;
List<DataSutureSideVertex> allVertexs = GetVertex(vertexsArray, false);
sutureSide.dataBaking.allVertexs = allVertexs.ToArray();
}
/// <summary> 缝合范围内的顶点 </summary>
private void SetVertex(DataSutureSide sutureSide) {
//全部顶点
List<DataSutureSideVertex> allVertexs = GetVertex(sutureSide.plateSide.dataBaking.vertexs, sutureSide.isReversal);
//缝合范围内的顶点
float maxLength = sutureSide.suture.length;
List<DataSutureSideVertex> vertexs = new List<DataSutureSideVertex>();
for (int i = 0; i < allVertexs.Count; i++) {
if (allVertexs[i].origin <= maxLength) { vertexs.Add(allVertexs[i]); }
}
sutureSide.dataBaking.vertexs = vertexs.ToArray();
}
/// <summary> 顶点转换位置 </summary>
private void SetPositions(DataSutureSide sutureSide) {
Vector3 platePosition = sutureSide.plateSide.plate.dataBaking.position;
Vector3 plateEulerAngles = sutureSide.plateSide.plate.dataBaking.eulerAngles;
List<Vector3> positions = new List<Vector3>();
DataSutureSideVertex[] vertexs = sutureSide.dataBaking.vertexs;
for (int i = 0; i < vertexs.Length; i++) {
Quaternion quaternion = Quaternion.Euler(plateEulerAngles);
Vector3 baking = quaternion * vertexs[i].a.position;
Vector3 position = baking + platePosition;
positions.Add(position);
}
sutureSide.dataBaking.positions = positions.ToArray();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9735cc247f76e0b42b50f8b7956d3c8a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,52 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 设计的缝合线
/// </summary>
public class UnitAlgorithmSutureDesign : UnitAlgorithm<DataSutureSide> {
/// <summary> 设计的缝合线 </summary>
public UnitAlgorithmSutureDesign() { }
public class Line {
public float origin;
public Vector3 a;
public Vector3 b;
public Line(float origin, Vector3 a, Vector3 b) {
this.origin = origin;
this.a = a;
this.b = b;
}
public float Distance => Vector3.Distance(a, b);
}
public void Compute(DataSutureSide sutureSide) {
float maxLength = sutureSide.suture.length;
Vector3 platePosition = sutureSide.plateSide.plate.dataDesign.position;
List<Vector3> sidePositions = new List<Vector3>(sutureSide.plateSide.dataDesign.positions);
float length = 0;
List<Line> lines = new List<Line>();
if (sutureSide.isReversal) { sidePositions.Reverse(); }
for (int i = 0; i < sidePositions.Count - 1; i++) {
Line line = new Line(length, sidePositions[i], sidePositions[i + 1]);
lines.Add(line);
length += line.Distance;
}
List<Vector3> positions = new List<Vector3>();
for (int i = 0; i < lines.Count; i++) {
Line line = lines[i];
if (line.origin < maxLength) { positions.Add(line.a + platePosition); }
float nextDistance = line.origin + line.Distance;
if (nextDistance < maxLength) { continue; }
if (nextDistance == maxLength) { positions.Add(line.b + platePosition); break; }
float distance = maxLength - line.origin;
Vector3 direction = (line.b - line.a).normalized;
Vector3 position = line.a + direction * distance;
positions.Add(position + platePosition);
break;
}
sutureSide.dataDesign.positions = positions.ToArray();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b98adb17aebd36b4ab5dfe90020fb902
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -6,97 +6,95 @@ using UnityEngine;
/// <summary>
/// 顶点算法
/// </summary>
public class UnitAlgorithmVertex : UnitAlgorithm<DataPlate> {
public class UnitAlgorithmVertex : UnitAlgorithm<DataPlateBaking> {
public class SideVertex : IComparable<SideVertex> {
public float distance;
public DataVertex vertex;
public Vector3 position;
public int CompareTo(SideVertex other) {
return other.distance >= distance ? 1 : -1;
if (other == null || this == null) { return 0; }
if (other == this) { return 0; }
if (other.distance > distance) { return -1; }
if (other.distance < distance) { return 1; }
return 0;
}
}
public void Compute(DataPlate data) {
float smooth = data.smooth;
DataBorder border = data.border;
List<Vector3> edgePoints = new List<Vector3>(data.edgePoints);
public void Compute(DataPlateBaking plateBaking) {
DataBorder border = plateBaking.border;
Vector3[] points = border.points;
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;
});
//plateBaking.grid = new GridTool<DataPlateVertex>(border.GridWide, border.GridHigh, (x, y) => {
// Vector3 position = new Vector3(x, y) * border.smooth + border.MinPoint;
// DataPlateVertex vertex = new DataPlateVertex();
// vertex.isValid = FindPlateInside(points, position);
// vertex.position = position;
// return vertex;
//});
//边缘所有的线段
for (int i = 0; i < data.sides.Count; i++) {
Compute(data.sides[i], wide, high, border, smooth, data.vertexGrid);
}
//List<DataPlateSide> plateSides = plateBaking.plate.plateSides;
//for (int i = 0; i < plateSides.Count; i++) {
// SubdivideSideVertex(plateBaking, plateSides[i]);
//}
}
/// <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>();
private void SubdivideSideVertex(DataPlateBaking plateBaking, DataPlateSide plateSides) {
DataBorder border = plateBaking.border;
DataPlateLine[] lines = plateSides.dataBaking.lines;
//计算水平线段顶点
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);
List<SideVertex> sideVertexs = new List<SideVertex>();
for (int x = 0; x < border.GridWide; x++) {
Vector3 a = new Vector3(border.minX + x * border.smooth, border.minY - 1);
Vector3 b = new Vector3(border.minX + x * border.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;
if (!TryGetIntersectPoint(a, b, lines[i].a, lines[i].b, out Vector3 IntersectPoint)) { continue; }
float distance = Vector3.Distance(lines[i].a, IntersectPoint) + lines[i].origin;
SideVertex sideVertex = new SideVertex();
sideVertex.distance = distance;
sideVertex.vertex = vertex;
sideVertices.Add(sideVertex);
sideVertex.position = IntersectPoint;
sideVertexs.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 y = 0; y < border.GridHigh; y++) {
Vector3 a = new Vector3(border.minX - 1, border.minY + y * border.smooth);
Vector3 b = new Vector3(border.maxX + 1, border.minY + y * border.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;
if (!TryGetIntersectPoint(a, b, lines[i].a, lines[i].b, out Vector3 IntersectPoint)) { continue; }
float distance = Vector3.Distance(lines[i].a, IntersectPoint) + lines[i].origin;
SideVertex sideVertex = new SideVertex();
sideVertex.distance = distance;
sideVertex.vertex = vertex;
sideVertices.Add(sideVertex);
sideVertex.position = IntersectPoint;
sideVertexs.Add(sideVertex);
}
}
sideVertices.Sort();
List<DataVertex> vertices = new List<DataVertex>();
for (int i = 0; i < sideVertices.Count; i++) {
vertices.Add(sideVertices[i].vertex);
//排序
sideVertexs.Sort();
//写入网格,写入顶点
Vector3 offset = border.MinPoint - new Vector3(border.smooth, border.smooth, 0) * 0.3f;
List<DataPlateVertex> vertexs = new List<DataPlateVertex>();
for (int i = 0; i < sideVertexs.Count; i++) {
Vector3 position = sideVertexs[i].position;
Vector3 gridPosition = position - offset;
int vertexX = Mathf.FloorToInt(gridPosition.x / border.smooth);
int vertexY = Mathf.FloorToInt(gridPosition.y / border.smooth);
//填充数据
//DataPlateVertex vertex = plateBaking.grid.Get(vertexX, vertexY);
//vertex.isValid = true;
//vertex.position = position;
////写入顶点
//vertexs.Add(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;
plateSides.dataBaking.vertexs = vertexs.ToArray();
}
/// <summary> 转角法查询位置是否在板片内 </summary>
public static bool FindPlateInside(List<Vector3> points, Vector3 position) {
public static bool FindPlateInside(Vector3[] points, Vector3 position) {
double angles = 0;
for (int i = 0; i < points.Count; i++) {
for (int i = 0; i < points.Length; i++) {
Vector3 a = points.LoopIndex(i + 0) - position;
Vector3 b = points.LoopIndex(i + 1) - position;
float angle = Vector2.SignedAngle(a, b);