This is currently quite hard to achieve.
You can use the Ab4d.SharpEngine.Utilities.MeshAnalyzer class - it simplifies the mesh by combining all positions that use the same 3D coordinates and then generates mesh edges and polygons. But the polygons are still generated from the triangles and there is no code (yet) that would combine polygons with shared edges and similar normals into faces. I have added that to my todo list and will try to implement that in the next version.
Anyway, I have quickly developed a code that could be used by the current version:
Code:
// This returns list of indexes from TriangleIndices for start index of each triangle that form the face
private static List<int> GetFaceTriangles(StandardMesh originalMesh, MeshAnalyzer meshAnalyzer, int triangleIndex)
{
int startIndex = triangleIndex * 3;
int i1 = originalMesh.TriangleIndices[startIndex];
int i2 = originalMesh.TriangleIndices[startIndex + 1];
int i3 = originalMesh.TriangleIndices[startIndex + 2];
var p1 = originalMesh.Vertices[i1].Position;
var p2 = originalMesh.Vertices[i2].Position;
var p3 = originalMesh.Vertices[i3].Position;
var pp1 = GetNewPositionIndex(p1, meshAnalyzer);
var pp2 = GetNewPositionIndex(p2, meshAnalyzer);
var pp3 = GetNewPositionIndex(p3, meshAnalyzer);
var e1 = GetEdgeIndex(pp1, pp2, meshAnalyzer);
var e2 = GetEdgeIndex(pp2, pp3, meshAnalyzer);
var e3 = GetEdgeIndex(pp3, pp1, meshAnalyzer);
var polygonIndex = GetPolygonIndex(e1, e2, e3, meshAnalyzer);
var polygonNormal = meshAnalyzer.Polygons[polygonIndex].Normal;
var otherFacePolygons = new List<int>();
for (var onePolygonIndex = 0; onePolygonIndex < meshAnalyzer.Polygons.Count; onePolygonIndex++)
{
if (onePolygonIndex == polygonIndex)
continue;
var onePolygon = meshAnalyzer.Polygons[onePolygonIndex];
var dot = Vector3.Dot(polygonNormal, onePolygon.Normal);
if (MathUtils.IsSame(dot, 1, 0.001f)) // when dot product is 1, then both vectors point in the same direction
{
// Now check edges if both polygons share the same edge
foreach (var onePolygonEdgeIndex in onePolygon.EdgeIndexes)
{
if (onePolygonEdgeIndex == e1 || onePolygonEdgeIndex == e2 || onePolygonEdgeIndex == e3)
{
// Found polygon on the same face
otherFacePolygons.Add(onePolygonIndex);
break;
}
}
}
}
var triangleIndices = new List<int>();
int firstTriangleIndice = GetTriangleIndexInOriginalMesh(originalMesh, polygonIndex, meshAnalyzer);
triangleIndices.Add(firstTriangleIndice);
foreach (var otherFacePolygonIndex in otherFacePolygons)
{
int oneTriangleIndice = GetTriangleIndexInOriginalMesh(originalMesh, otherFacePolygonIndex, meshAnalyzer);
triangleIndices.Add(oneTriangleIndice);
}
return triangleIndices;
}
private static int GetTriangleIndexInOriginalMesh(StandardMesh originalMesh, int polygonIndex, MeshAnalyzer meshAnalyzer)
{
var polygon = meshAnalyzer.Polygons[polygonIndex];
var e1 = meshAnalyzer.Edges[polygon.EdgeIndexes[0]];
var e2 = meshAnalyzer.Edges[polygon.EdgeIndexes[1]];
int i1 = e1.StartPositionIndex;
int i2 = e1.EndPositionIndex;
int i3;
if (e2.StartPositionIndex != i1 && e2.StartPositionIndex != i2)
i3 = e2.StartPositionIndex;
else
i3 = e2.EndPositionIndex;
Span<Vector3> originalPositions = stackalloc Vector3[3];
originalPositions[0] = meshAnalyzer.Positions[i1];
originalPositions[1] = meshAnalyzer.Positions[i2];
originalPositions[2] = meshAnalyzer.Positions[i3];
var triangleIndices = originalMesh.TriangleIndices;
var vertices = originalMesh.Vertices;
Span<Vector3> oneTrianglePositions = stackalloc Vector3[3];
for (int i = 0; i < triangleIndices.Length; i+=3)
{
int ii1 = triangleIndices[i];
int ii2 = triangleIndices[i + 1];
int ii3 = triangleIndices[i + 2];
oneTrianglePositions[0] = vertices[ii1].Position;
oneTrianglePositions[1] = vertices[ii2].Position;
oneTrianglePositions[2] = vertices[ii3].Position;
int sameCount = 0;
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
if (MathUtils.IsSame(originalPositions[j], oneTrianglePositions[k], 0.0001f))
sameCount++;
}
}
if (sameCount == 3)
return i;
}
return -1;
}
private static int GetPolygonIndex(int edgeIndex1, int edgeIndex2, int edgeIndex3, MeshAnalyzer meshAnalyzer)
{
for (var i = 0; i < meshAnalyzer.Polygons.Count; i++)
{
var polygon = meshAnalyzer.Polygons[i];
if (polygon.EdgeIndexes.Contains(edgeIndex1) &&
polygon.EdgeIndexes.Contains(edgeIndex2) &&
polygon.EdgeIndexes.Contains(edgeIndex3))
return i;
}
return -1;
}
For example, you can call that to get faces for based on all trianges in a box mesh:
Code:
var boxMesh = MeshFactory.CreateBoxMesh(new Vector3(0, 0, 0), new Vector3(80, 40, 60), 1, 1, 1);
var meshAnalyzer = new MeshAnalyzer(boxMesh.Vertices, boxMesh.TriangleIndices);
meshAnalyzer.Analyze();
for (int i = 0; i < boxMesh.TrianglesCount; i++)
{
var faceIndices = GetFaceTriangles(boxMesh, meshAnalyzer, i);
}
NOTE:
This code is not yet fully tested. It will work only with nicely formed meshes (meshes that do not have triangles with duplicate positions).
You can use the new MultiMaterialModelNode to show some triangles with different color as other triangles (using the faceIndices list from the GetFaceTriangles method). See the new MultiMaterialModelNode to see how to do that.
As mentioned earlier, I will try to include this code into the MeshAnalizer in the next version of SharpEngine.