Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved the core model simplification algorithm #28

Merged
merged 3 commits into from
Mar 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Runtime/LODGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -597,11 +597,11 @@ private static Mesh SimplifyMesh(Mesh mesh, float quality, SimplificationOptions
meshSimplifier.PreserveBorderEdges = options.PreserveBorderEdges;
meshSimplifier.PreserveUVSeamEdges = options.PreserveUVSeamEdges;
meshSimplifier.PreserveUVFoldoverEdges = options.PreserveUVFoldoverEdges;
meshSimplifier.PreserveSurfaceCurvature = options.PreserveSurfaceCurvature;
meshSimplifier.EnableSmartLink = options.EnableSmartLink;
meshSimplifier.VertexLinkDistance = options.VertexLinkDistance;
meshSimplifier.MaxIterationCount = options.MaxIterationCount;
meshSimplifier.Agressiveness = options.Agressiveness;

meshSimplifier.Initialize(mesh);
meshSimplifier.SimplifyMesh(quality);

Expand Down
116 changes: 115 additions & 1 deletion Runtime/MeshSimplifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ public int Compare(BorderVertex x, BorderVertex y)
private bool preserveBorderEdges = false;
private bool preserveUVSeamEdges = false;
private bool preserveUVFoldoverEdges = false;
private bool preserveSurfaceCurvature = false;
private bool enableSmartLink = true;
private int maxIterationCount = 100;
private double agressiveness = 7.0;
Expand Down Expand Up @@ -503,6 +504,16 @@ public bool PreserveUVFoldoverEdges
set { preserveUVFoldoverEdges = value; }
}

/// <summary>
/// Gets or sets if the discrete curvature of the mesh surface be taken into account during simplification.
/// Default value: false
/// </summary>
public bool PreserveSurfaceCurvature
{
get { return preserveSurfaceCurvature; }
set { preserveSurfaceCurvature = value; }
}

/// <summary>
/// Gets or sets if a feature for smarter vertex linking should be enabled, reducing artifacts in the
/// decimated result at the cost of a slightly more expensive initialization by treating vertices at
Expand Down Expand Up @@ -763,6 +774,7 @@ public MeshSimplifier(Mesh mesh)
#endregion

#region Private Methods

#region Initialize Vertex Attribute
private void InitializeVertexAttribute<T>(T[] attributeValues, ref ResizableArray<T> attributeArray, string attributeName)
{
Expand Down Expand Up @@ -799,6 +811,45 @@ private double VertexError(ref SymmetricMatrix q, double x, double y, double z)
+ 2 * q.m5 * y * z + 2 * q.m6 * y + q.m7 * z * z + 2 * q.m8 * z + q.m9;
}



[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double CurvatureError(ref Vertex Vi, ref Vertex Vj)
{
double diffVector = (Vi.p - Vj.p).Magnitude;

HashSet<Triangle> trianglesWithVi = GetTrianglesContainingVertex(ref Vi);
HashSet<Triangle> trianglesWithVj = GetTrianglesContainingVertex(ref Vj);
HashSet<Triangle> trianglesWithViOrVjOrBoth = new HashSet<Triangle>(trianglesWithVi);
trianglesWithViOrVjOrBoth.UnionWith(trianglesWithVj);
HashSet<Triangle> trianglesWithViAndVjBoth = GetTrianglesContainingBothVertices(ref Vi, ref Vj);


double maxDotOuter = 0;

foreach (var triangleWithViOrVjOrBoth in trianglesWithViOrVjOrBoth)
{
double maxDotInner = 0;

Vector3d normVecTriangleWithViOrVjOrBoth = triangleWithViOrVjOrBoth.n;

foreach (var triangleWithViAndVjBoth in trianglesWithViAndVjBoth)
{
Vector3d normVecTriangleWithViAndVjBoth = triangleWithViAndVjBoth.n;

double dot = Vector3d.Dot(ref normVecTriangleWithViOrVjOrBoth, ref normVecTriangleWithViAndVjBoth);

if (dot > maxDotInner) { maxDotInner = dot; }
}

if (maxDotInner > maxDotOuter) { maxDotOuter = maxDotInner; }

}

return diffVector * maxDotOuter;
}


private double CalculateError(ref Vertex vert0, ref Vertex vert1, out Vector3d result)
{
// compute interpolated vertex
Expand All @@ -813,7 +864,15 @@ private double CalculateError(ref Vertex vert0, ref Vertex vert1, out Vector3d r
-1.0 / det * q.Determinant2(), // vx = A41/det(q_delta)
1.0 / det * q.Determinant3(), // vy = A42/det(q_delta)
-1.0 / det * q.Determinant4()); // vz = A43/det(q_delta)
error = VertexError(ref q, result.x, result.y, result.z);

double curvatureError = 0;

if (preserveSurfaceCurvature)
{
curvatureError = CurvatureError(ref vert0, ref vert1);
}

error = VertexError(ref q, result.x, result.y, result.z) + curvatureError;
}
else
{
Expand Down Expand Up @@ -844,6 +903,7 @@ private double CalculateError(ref Vertex vert0, ref Vertex vert1, out Vector3d r
}
return error;
}

#endregion

#region Calculate Barycentric Coordinates
Expand Down Expand Up @@ -1675,6 +1735,60 @@ private void CalculateSubMeshOffsets()
}
}
#endregion

#region Triangle helper functions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private HashSet<Triangle> GetTrianglesContainingVertex(ref Vertex toCheck)
{
int trianglesCount = toCheck.tcount;
int startIndex = toCheck.tstart;

HashSet<Triangle> tris = new HashSet<Triangle>();

for (int a = startIndex; a < startIndex + trianglesCount; a++)
{
tris.Add(triangles[refs[a].tid]);
}

return tris;
}


[MethodImpl(MethodImplOptions.AggressiveInlining)]
private HashSet<Triangle> GetTrianglesContainingBothVertices(ref Vertex vertex1, ref Vertex vertex2)
{
HashSet<Triangle> tris = new HashSet<Triangle>();


int trianglesCount = vertex1.tcount;
int startIndex = vertex1.tstart;

for (int a = startIndex; a < startIndex + trianglesCount; a++)
{
Triangle tri = triangles[refs[a].tid];

Vertex v1 = vertices[tri.v0];
Vertex v2 = vertices[tri.v1];
Vertex v3 = vertices[tri.v2];

int hashcode = vertex2.GetHashCode();

if (v1.GetHashCode().Equals(hashcode) || v2.GetHashCode().Equals(hashcode) || v3.GetHashCode().Equals(hashcode))
{
tris.Add(tri);
}

}



return tris;
}


#endregion Triangle helper functions


#endregion

#region Public Methods
Expand Down
7 changes: 7 additions & 0 deletions Runtime/SimplificationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public struct SimplificationOptions
PreserveBorderEdges = false,
PreserveUVSeamEdges = false,
PreserveUVFoldoverEdges = false,
PreserveSurfaceCurvature = false,
EnableSmartLink = true,
VertexLinkDistance = double.Epsilon,
MaxIterationCount = 100,
Expand All @@ -68,6 +69,12 @@ public struct SimplificationOptions
[Tooltip("If the UV foldover edges should be preserved.")]
public bool PreserveUVFoldoverEdges;
/// <summary>
/// If the discrete curvature of the mesh surface be taken into account during simplification. Taking surface curvature into account can result in good quality mesh simplification, but it can slow the simplification process significantly.
/// Default value: false
/// </summary>
[Tooltip("If the discrete curvature of the mesh surface be taken into account during simplification. Taking surface curvature into account can result in very good quality mesh simplification, but it can slow the simplification process significantly.")]
public bool PreserveSurfaceCurvature;
/// <summary>
/// If a feature for smarter vertex linking should be enabled, reducing artifacts in the
/// decimated result at the cost of a slightly more expensive initialization by treating vertices at
/// the same position as the same vertex while separating the attributes.
Expand Down