diff --git a/Runtime/MeshSimplifier.cs b/Runtime/MeshSimplifier.cs
index 70a1cba..bb5cd3e 100644
--- a/Runtime/MeshSimplifier.cs
+++ b/Runtime/MeshSimplifier.cs
@@ -413,6 +413,7 @@ public int Compare(BorderVertex x, BorderVertex y)
private bool enableSmartLink = true;
private int maxIterationCount = 100;
private double agressiveness = 7.0;
+ private double boundaryWeight = 1000.0;
private bool verbose = false;
private double vertexLinkDistanceSqr = double.Epsilon;
@@ -536,6 +537,17 @@ public double Agressiveness
set { agressiveness = value; }
}
+ ///
+ /// Gets or sets the weight for the mesh boundaries. Increase this weight to leave the boundaries with a higher quality.
+ /// Setting this to zero means that boundaries will not be treated differently from other edges.
+ /// Default value: 1000.0
+ ///
+ public double BoundaryWeight
+ {
+ get { return boundaryWeight; }
+ set { boundaryWeight = value; }
+ }
+
///
/// Gets or sets if verbose information should be printed to the console.
/// Default value: false
@@ -795,8 +807,8 @@ private void InitializeVertexAttribute(T[] attributeValues, ref ResizableArra
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private double VertexError(ref SymmetricMatrix q, double x, double y, double z)
{
- return q.m0 * x * x + 2 * q.m1 * x * y + 2 * q.m2 * x * z + 2 * q.m3 * x + q.m4 * y * y
- + 2 * q.m5 * y * z + 2 * q.m6 * y + q.m7 * z * z + 2 * q.m8 * z + q.m9;
+ return (q.m0 * x * x) + (2 * q.m1 * x * y) + (2 * q.m2 * x * z) + (2 * q.m3 * x) + (q.m4 * y * y)
+ + (2 * q.m5 * y * z) + (2 * q.m6 * y) + (q.m7 * z * z) + (2 * q.m8 * z) + q.m9;
}
private double CalculateError(ref Vertex vert0, ref Vertex vert1, out Vector3d result)
@@ -824,24 +836,31 @@ private double CalculateError(ref Vertex vert0, ref Vertex vert1, out Vector3d r
double error1 = VertexError(ref q, p1.x, p1.y, p1.z);
double error2 = VertexError(ref q, p2.x, p2.y, p2.z);
double error3 = VertexError(ref q, p3.x, p3.y, p3.z);
- error = MathHelper.Min(error1, error2, error3);
- if (error == error3)
+ if (error1 <= error2)
{
- result = p3;
+ if (error1 <= error3)
+ {
+ error = error1;
+ result = p1;
+ }
+ else
+ {
+ error = error3;
+ result = p3;
+ }
}
- else if (error == error2)
+ else if (error2 <= error3)
{
+ error = error2;
result = p2;
}
- else if (error == error1)
- {
- result = p1;
- }
else
{
+ error = error3;
result = p3;
}
}
+
return error;
}
#endregion
@@ -1208,6 +1227,40 @@ private void UpdateMesh(int iteration)
{
var refs = this.refs.Data;
+ // Init Quadrics by Plane
+ //
+ // required at the beginning ( iteration == 0 )
+ // recomputing during the simplification is not required,
+ // but mostly improves the result for closed meshes
+ for (int i = 0; i < vertexCount; i++)
+ {
+ vertices[i].q = new SymmetricMatrix();
+ }
+
+ int v0, v1, v2;
+ Vector3d n, p0, p1, p2, p10, p20, dummy;
+ SymmetricMatrix sm;
+ for (int i = 0; i < triangleCount; i++)
+ {
+ v0 = triangles[i].v0;
+ v1 = triangles[i].v1;
+ v2 = triangles[i].v2;
+
+ p0 = vertices[v0].p;
+ p1 = vertices[v1].p;
+ p2 = vertices[v2].p;
+ p10 = p1 - p0;
+ p20 = p2 - p0;
+ Vector3d.Cross(ref p10, ref p20, out n);
+ n.Normalize();
+ triangles[i].n = n;
+
+ sm = new SymmetricMatrix(n.x, n.y, n.z, -Vector3d.Dot(ref n, ref p0));
+ vertices[v0].q += sm;
+ vertices[v1].q += sm;
+ vertices[v2].q += sm;
+ }
+
var vcount = new List(8);
var vids = new List(8);
int vsize = 0;
@@ -1359,40 +1412,37 @@ private void UpdateMesh(int iteration)
UpdateReferences();
}
- // Init Quadrics by Plane & Edge Errors
- //
- // required at the beginning ( iteration == 0 )
- // recomputing during the simplification is not required,
- // but mostly improves the result for closed meshes
- for (int i = 0; i < vertexCount; i++)
- {
- vertices[i].q = new SymmetricMatrix();
- }
-
- int v0, v1, v2;
- Vector3d n, p0, p1, p2, p10, p20, dummy;
- SymmetricMatrix sm;
- for (int i = 0; i < triangleCount; i++)
+ // Add weight for boundaries
+ if (boundaryWeight > 0.0)
{
- v0 = triangles[i].v0;
- v1 = triangles[i].v1;
- v2 = triangles[i].v2;
+ for (int i = 0; i < vertexCount; i++)
+ {
+ if (!vertices[i].borderEdge && !vertices[i].uvFoldoverEdge && !vertices[i].uvSeamEdge)
+ continue;
- p0 = vertices[v0].p;
- p1 = vertices[v1].p;
- p2 = vertices[v2].p;
- p10 = p1 - p0;
- p20 = p2 - p0;
- Vector3d.Cross(ref p10, ref p20, out n);
- n.Normalize();
- triangles[i].n = n;
+ int tstart = vertices[i].tstart;
+ int tcount = vertices[i].tcount;
- sm = new SymmetricMatrix(n.x, n.y, n.z, -Vector3d.Dot(ref n, ref p0));
- vertices[v0].q += sm;
- vertices[v1].q += sm;
- vertices[v2].q += sm;
+ Vector3d n2;
+ for (int j = 0; j < tcount; j++)
+ {
+ int tid = refs[tstart + j].tid;
+ int tvertex = refs[tstart + j].tvertex;
+ int tvertex2 = (tvertex + 1) % 3;
+ int k = triangles[tid][tvertex2];
+
+ var e = vertices[k].p - vertices[i].p;
+ Vector3d.Cross(ref e, ref triangles[tid].n, out n2);
+
+ sm = new SymmetricMatrix(n2.x, n2.y, n2.z, -Vector3d.Dot(ref n2, ref vertices[i].p));
+ sm *= boundaryWeight;
+ vertices[i].q += sm;
+ vertices[k].q += sm;
+ }
+ }
}
+ // Init Edge Errors
for (int i = 0; i < triangleCount; i++)
{
// Calc Edge Error
diff --git a/Runtime/Utility/SymmetricMatrix.cs b/Runtime/Utility/SymmetricMatrix.cs
index fbbbff2..ffb7adc 100644
--- a/Runtime/Utility/SymmetricMatrix.cs
+++ b/Runtime/Utility/SymmetricMatrix.cs
@@ -209,6 +209,23 @@ public SymmetricMatrix(double a, double b, double c, double d)
a.m9 + b.m9
);
}
+
+ ///
+ /// Scales the matrix.
+ ///
+ /// The matrix.
+ /// The scale factor.
+ /// The resulting matrix.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static SymmetricMatrix operator *(SymmetricMatrix m, double s)
+ {
+ return new SymmetricMatrix(
+ m.m0 * s, m.m1 * s, m.m2 * s, m.m3 * s,
+ m.m4 * s, m.m5 * s, m.m6 * s,
+ m.m7 * s, m.m8 * s,
+ m.m9 * s
+ );
+ }
#endregion
#region Internal Methods