Unity

Mesh 를 통해 면적, 부피 계산하는 법

Dean83 2023. 12. 12. 09:35

Mesh를 통해 다양한 모양의 면적, 부피를 계산하는 법. 

 

1. 설명
     - Mesh는 vertices의 점과, 해당 점을 이은 triangles 를 통해 폴리곤을 만들고, 이를 화면에 표현하여 3D로 보여준다.

     - 즉, 3각형의 면적들을 모두 더한다면, 전체 면적을 알 수 있고, 부피의 경우 높이값이 별도로 필요하다.
        - 단, 경우에 따라 triangles 에 있으나 삼각형이 아닌 값들, 중복된 값들, 대각선의 삼각형 등은 제외해야 한다. 
     - 유니티에서는 이를 손쉽게 구할 수 있도록 함수화가 잘 되어 있다. 

 

 

2. 면적 및 부피 구하는 방법

     - 아래에서 명시한 면적 및 부피 구하는 법은 인터넷에서 찾은 계산법이다. 

var triangles = 메쉬변수명.triangles;
var vertices = 메쉬면수명.vertices;

//이미 계산한 폴리곤은 제외하기 위해 계산된 점들을 모아두는 임시 list
List<CalcPointInfo> points = new List<CalcPointInfo>();

double areaSum = 0.0;
double volumnSum = 0.0;

//삼각형은 3점으로 이루어져있기에 i값을 3씩 증가 한다. 
//triangles에는 vertices 의 인덱스 값이 들어가 있다. 
for (int i = 0; i < triangles.Length; i += 3)
{
    Vector3 corner = vertices[triangles[i]];
    Vector3 point1 = vertices[triangles[i + 1]];
    Vector3 point2 = vertices[triangles[i + 2]];

    //소수점 오차로 인해 실제 값은 0 인데 0.000000012 로 표기되면서 조건식 오류가 발생하여
    //반올림하여 처리
    float cornerX = (float)Math.Round(corner.x, 2);
    float cornerY = (float)Math.Round(corner.y, 2);
    float cornerZ = (float)Math.Round(corner.z, 2);
    float point1X = (float)Math.Round(point1.x, 2);
    float point1Y = (float)Math.Round(point1.y, 2);
    float point1Z = (float)Math.Round(point1.z, 2);
    float point2X = (float)Math.Round(point2.x, 2);
    float point2Y = (float)Math.Round(point2.y, 2);
    float point2Z = (float)Math.Round(point2.z, 2);

    corner = new Vector3(cornerX, cornerY, cornerZ);
    point1 = new Vector3(point1X, point1Y, point1Z);
    point2 = new Vector3(point2X, point2Y, point2Z);

    //같은 라인 선상에 있는 좌표는 건너뜀. 예를들어 세점이 모두 x 축만 다를경우 삼각형이 될수 없으므로 제외
    if (cornerX == point1X && cornerX == point2X && cornerY == point1Y && cornerY == point2Y)
        continue;

    if (cornerX == point1X && cornerX == point2X && cornerZ == point1Z && cornerZ == point2Z)
        continue;

    if (cornerZ == point1Z && cornerZ == point2Z && cornerY == point1Y && cornerY == point2Y)
        continue;


    ///대각선으로 그려진 폴리곤은 계산하지 않는다. 면적이기 때문에 오차값이 되어 버린다.
    ///아래의 if문은 대각선으로 그려진 폴리곤일 경우 건너뛰는 계산이다.
    if ((cornerZ != point1Z && cornerX != point1X && cornerY != point1Y)
        || (cornerZ != point2Z && cornerX != point2X && cornerY != point2Y))
        continue;

    //3개의 같은 좌표값으로 중복계산하는걸 방지하는 코드,
    int exist = (from item in points
                 where (corner == item.point1 || corner == item.point2 || corner == item.point3)
                 && (point1 == item.point1 || point1 == item.point2 || point1 == item.point3)
                 && (point2 == item.point1 || point2 == item.point2 || point2 == item.point3)
                 select item).Count();

    if (exist > 0)
        continue;

    CalcPointInfo temp = new CalcPointInfo();
    temp.point1 = corner;
    temp.point2 = point1;
    temp.point3 = point2;
    points.Add(temp);

    //면적
    areaSum += Vector3.Cross(point1 - corner, point2 - corner).magnitude;

    //부피
    volumnSum += Vector3.Dot(corner, Vector3.Cross(point1, point2)) / 6.0f;
}

//면적은 sum 에서 2로 나누어야 한다.
float res = (float)(areaSum / 2.0);