내일배움캠프 Unity 90일차 TIL - 팀 9와 4분의 3 - 개발일지

Wooooo·2024년 3월 6일
0

내일배움캠프Unity

목록 보기
92/94

[오늘의 키워드]

Mesh.vertices 프로퍼티 접근 시 GC 생성


[Mesh.vertices 프로퍼티 접근 시 GC 생성]

Code

public static Vector3[] CalcaultateSmoothNormal(this Mesh mesh)
{
    Dictionary<Vector3, List<int>> indicesDict = new(comparer: new Vector3EqualityComparer());

    for (int i = 0; i < mesh.vertexCount; i++)
    {
        if (!indicesDict.ContainsKey(mesh.vertices[i]))
            indicesDict.Add(mesh.vertices[i], new());

        indicesDict[mesh.vertices[i]].Add(i);
    }

    Vector3[] normals = new Vector3[originNormals.Length];

    foreach (var indices in indicesDict.Values)
    {
        Vector3 normal = Vector3.zero;

        foreach (var index in indices)
            normal += mesh.normals[index];

        normal /= indices.Count;

        foreach (var index in indices)
            normals[index] = normal;
    }

    return normals;
}

Profiler

정점이 4400개 정도 되는 나무 오브젝트에 코드를 적용해보니 1초 정도 병목이 발생하길래 원인을 찾아보니 코드에서 엄청난 양의 GC가 발생하고 있었다.

Mesh.vertices 프로퍼티는 메시의 정점 배열을 똑같이 복사해서 반환해준다
그런데 나는 이 프로퍼티를 반복문을 돌며 인덱싱 중이었다..........

정점 4400개 * 반복당 최소 2회 복사 = 대략 정점 4천만 개 급의 GC 생성 ,,,,,,

Code

public static Vector3[] CalcaultateSmoothNormal(this Mesh mesh)
{
    Dictionary<Vector3, List<int>> indicesDict = new(comparer: new Vector3EqualityComparer());

    // 프로퍼티로 접근하면 접근할때마다 복사하기 때문에 로컬변수로 빼놔야함
    var originVertices = mesh.vertices;
    var originNormals = mesh.normals;

    for (int i = 0; i < mesh.vertexCount; i++)
    {
        if (!indicesDict.ContainsKey(originVertices[i]))
            indicesDict.Add(originVertices[i], new());

        indicesDict[originVertices[i]].Add(i);
    }

    Vector3[] normals = new Vector3[originNormals.Length];

    foreach (var indices in indicesDict.Values)
    {
        Vector3 normal = Vector3.zero;

        foreach (var index in indices)
            normal += originNormals[index];

        normal /= indices.Count;

        foreach (var index in indices)
            normals[index] = normal;
    }

    return normals;
}

반복문을 돌기 전에 배열을 복사해놓고 반복문을 수행하도록 했다.


프로퍼티는 변수가 아니다... getter와 setter 모두 메서드이기 때문에 프로퍼티에 접근한다는건 곧 메서드를 실행한다는 걸 기억하자.

아니면 설명이라도 잘 읽자.

profile
game developer

0개의 댓글