Friday, December 13, 2019

unity - How to calculate the surface area of a mesh


I am looking for a way to calculate surface area of a 3D mesh object and found this code from a Unity forum:


 public float Area(Mesh m)
{
Vector3[] mVertices = m.vertices;
Vector3 result = Vector3.zero;

for (int p = mVertices.Length - 1, q = 0; q < mVertices.Length; p = q++)
{
result += Vector3.Cross(mVertices[q], mVertices[p]);
}
Debug.Log(result);
result *= 0.5f;
return result.magnitude;
}

But the problem is that it is not providing the correct area as I have found from testing the fbx with Revit. Revit is showing a different surface area from what this code shows.



Edit: Here is a sample mesh


Front


enter image description here


Back enter image description here


Top enter image description here


Its surface area as calculated by the function above is 97.4913,
while in Revit it's actually 52.811 \$m^2\$.


Edit 2: I don't know how revit calculate it but it provide area and volume information automatically (i have no idea how even revit works:(). enter image description here



Answer



Looking at the formula you're using, it looks like it's designed to calculate the area of a planar polygon, where the vertices are all in clockwise / counterclockwise order about the perimeter.



That's not the same as a 3D mesh.


Try something like this instead:



  • we'll iterate over the triangles of the mesh

  • for each triangle, we'll compute vectors representing the two edges

  • half the magnitude of the cross product of these edges gives us the area of the triangle

  • we'll sum these triangle areas to accumulate the full surface area


Note that if your mesh has any double-sided faces or internal faces, they can bias this result.


float CalculateSurfaceArea(Mesh mesh) {

var triangles = mesh.triangles;
var vertices = mesh.vertices;

double sum = 0.0;

for(int i = 0; i < triangles.Length; i += 3) {
Vector3 corner = vertices[triangles[i]];
Vector3 a = vertices[triangles[i + 1]] - corner;
Vector3 b = vertices[triangles[i + 2]] - corner;


sum += Vector3.Cross(a, b).magnitude;
}

return (float)(sum/2.0);
}

Since it now looks like you want to compute just the area of the mesh facing in a particular direction, you can try this version instead. Pass the direction you want to view the mesh from and it should compute the projected surface area of the faces facing at least partially in that direction.


float CalculateFacingArea(Mesh mesh, Vector3 direction) {
direction = direction.normalized;
var triangles = mesh.triangles;

var vertices = mesh.vertices;

double sum = 0.0;

for(int i = 0; i < triangles.Length; i += 3) {
Vector3 corner = vertices[triangles[i]];
Vector3 a = vertices[triangles[i + 1]] - corner;
Vector3 b = vertices[triangles[i + 2]] - corner;

float projection = Vector3.Dot(Vector3.Cross(b, a), direction);

if (projection > 0f)
sum += projection;
}

return (float)(sum/2.0);
}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...