forked from BilalY/Rasagar
140 lines
5.4 KiB
C#
140 lines
5.4 KiB
C#
using System.Linq;
|
|
|
|
namespace UnityEngine.ProBuilder.MeshOperations
|
|
{
|
|
static partial class UVEditing
|
|
{
|
|
/// <summary>
|
|
/// Provided two faces, this method will attempt to project @f2 and align its size, rotation, and position to match
|
|
/// the shared edge on f1. Returns true on success, false otherwise.
|
|
/// </summary>
|
|
/// <param name="mesh"></param>
|
|
/// <param name="f1"></param>
|
|
/// <param name="f2"></param>
|
|
/// <param name="channel"></param>
|
|
/// <returns></returns>
|
|
public static bool AutoStitch(ProBuilderMesh mesh, Face f1, Face f2, int channel)
|
|
{
|
|
var wings = WingedEdge.GetWingedEdges(mesh, new [] { f1, f2 });
|
|
|
|
var sharedEdge = wings.FirstOrDefault(x => x.face == f1 && x.opposite != null && x.opposite.face == f2);
|
|
|
|
if (sharedEdge == null)
|
|
return false;
|
|
|
|
if (f1.manualUV)
|
|
f2.manualUV = true;
|
|
|
|
f1.textureGroup = -1;
|
|
f2.textureGroup = -1;
|
|
|
|
Projection.PlanarProject(mesh, f2);
|
|
|
|
if (AlignEdges(mesh, f2, sharedEdge.edge.local, sharedEdge.opposite.edge.local, channel))
|
|
{
|
|
if (!f2.manualUV)
|
|
UvUnwrapping.SetAutoAndAlignUnwrapParamsToUVs(mesh, new [] { f2 });
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// move the UVs to where the edges passed meet
|
|
/// </summary>
|
|
/// <param name="mesh"></param>
|
|
/// <param name="faceToMove"></param>
|
|
/// <param name="edgeToAlignTo"></param>
|
|
/// <param name="edgeToBeAligned"></param>
|
|
/// <param name="channel"></param>
|
|
/// <returns></returns>
|
|
static bool AlignEdges(ProBuilderMesh mesh, Face faceToMove, Edge edgeToAlignTo, Edge edgeToBeAligned, int channel)
|
|
{
|
|
Vector2[] uvs = GetUVs(mesh, channel);
|
|
SharedVertex[] sharedIndexes = mesh.sharedVerticesInternal;
|
|
|
|
// Match each edge vertex to the other
|
|
int[] matchX = new int[2] { edgeToAlignTo.a, -1 };
|
|
int[] matchY = new int[2] { edgeToAlignTo.b, -1 };
|
|
|
|
int siIndex = mesh.GetSharedVertexHandle(edgeToAlignTo.a);
|
|
|
|
if (siIndex < 0)
|
|
return false;
|
|
|
|
if (sharedIndexes[siIndex].Contains(edgeToBeAligned.a))
|
|
{
|
|
matchX[1] = edgeToBeAligned.a;
|
|
matchY[1] = edgeToBeAligned.b;
|
|
}
|
|
else
|
|
{
|
|
matchX[1] = edgeToBeAligned.b;
|
|
matchY[1] = edgeToBeAligned.a;
|
|
}
|
|
|
|
// scale face 2 to match the edge size of f1
|
|
float dist_e1 = Vector2.Distance(uvs[edgeToAlignTo.a], uvs[edgeToAlignTo.b]);
|
|
float dist_e2 = Vector2.Distance(uvs[edgeToBeAligned.a], uvs[edgeToBeAligned.b]);
|
|
|
|
float scale = dist_e1 / dist_e2;
|
|
|
|
// doesn't matter what point we scale around because we'll move it in the next step anyways
|
|
foreach (int i in faceToMove.distinctIndexesInternal)
|
|
uvs[i] = uvs[i].ScaleAroundPoint(Vector2.zero, Vector2.one * scale);
|
|
|
|
// Figure out where the center of each edge is so that we can move the f2 edge to match f1's origin
|
|
Vector2 f1_center = (uvs[edgeToAlignTo.a] + uvs[edgeToAlignTo.b]) / 2f;
|
|
Vector2 f2_center = (uvs[edgeToBeAligned.a] + uvs[edgeToBeAligned.b]) / 2f;
|
|
|
|
Vector2 diff = f1_center - f2_center;
|
|
|
|
// Move f2 face to where it's matching edge center is on top of f1's center
|
|
foreach (int i in faceToMove.distinctIndexesInternal)
|
|
uvs[i] += diff;
|
|
|
|
// Now that the edge's centers are matching, rotate f2 to match f1's angle
|
|
Vector2 angle1 = uvs[matchY[0]] - uvs[matchX[0]];
|
|
Vector2 angle2 = uvs[matchY[1]] - uvs[matchX[1]];
|
|
|
|
float angle = Vector2.Angle(angle1, angle2);
|
|
if (Vector3.Cross(angle1, angle2).z < 0)
|
|
angle = 360f - angle;
|
|
|
|
foreach (int i in faceToMove.distinctIndexesInternal)
|
|
uvs[i] = Math.RotateAroundPoint(uvs[i], f1_center, angle);
|
|
|
|
float error = Mathf.Abs(Vector2.Distance(uvs[matchX[0]], uvs[matchX[1]])) + Mathf.Abs(Vector2.Distance(uvs[matchY[0]], uvs[matchY[1]]));
|
|
|
|
// now check that the matched UVs are on top of one another if the error allowance is greater than some small value
|
|
if (error > .02f)
|
|
{
|
|
// first try rotating 180 degrees
|
|
foreach (int i in faceToMove.distinctIndexesInternal)
|
|
uvs[i] = Math.RotateAroundPoint(uvs[i], f1_center, 180f);
|
|
|
|
float e2 = Mathf.Abs(Vector2.Distance(uvs[matchX[0]], uvs[matchX[1]])) + Mathf.Abs(Vector2.Distance(uvs[matchY[0]], uvs[matchY[1]]));
|
|
if (e2 < error)
|
|
error = e2;
|
|
else
|
|
{
|
|
// flip 'em back around
|
|
foreach (int i in faceToMove.distinctIndexesInternal)
|
|
uvs[i] = Math.RotateAroundPoint(uvs[i], f1_center, 180f);
|
|
}
|
|
}
|
|
|
|
// If successfully aligned, merge the sharedIndexesUV
|
|
SplitUVs(mesh, faceToMove.distinctIndexesInternal);
|
|
|
|
mesh.SetTexturesCoincident(matchX);
|
|
mesh.SetTexturesCoincident(matchY);
|
|
ApplyUVs(mesh, uvs, channel);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|