Unity에 Mesh Collider가 많이 밀집되어 있으면 Invalid world AABB라고 불리는 버그를 피할 수 있습니다

17158 단어 UnityC#

버그 개요


두루뭉술하게 말하다

  • 이벤트: 대량의 망상 접착기가 밀집된 상태에서 그 게임Object는 허공으로 사라집니다

  • 원인:transform.position - (Nan, NaN, NaN)

  • 근본 원인: Unity(PhysiX?)원인

  • 대책: 대량으로 생성되고 초만원이 서로 부딪치는 게임Object가 망상균형기 동적생성균형기를 사용하지 않으면 좋을 수 있다(마지막 보충)
  • 그런 느낌도 있지만 구제불능의 잘못이 있는 것 같은데'인valid world AABB'라는 단어로 표현하자면 비슷한 기사가 하나도 없어 골치 아프다.
    다음은 조사해서 알게 된 것들을 많이 쓰겠습니다.

    발생 단계


    내 상황은 트로피 테스트 경기에서 일어났다.

    사용한 메달은 블렌더가 적절히 제작한 모형에 라이트바디와 메시콜리더로 물리적 연산을 적용한 매우 일반적인 것이다.

    이렇게 해서 어쨌든 대량의 메달을 경기장에 떨어뜨려 보았지만 처음에는 문제없이 움직였다

    300장이 넘는 곳에서 갑자기 메달과 스트레스(메달 이동을 밀어붙이는 대)가 사라졌다.그리고 처리가 무거워졌다.

    보면 "Invalid world AABB.Object is too large or too far away from the origin"등의 욕설을 듣는다.

    그래서transform.포지션을 보면 알 수 있듯이 직접적인 원인은 좌표가 Nan으로 변했기 때문이다.왜 나인이 됐는지 고민해야 한다는 얘기다.(장난 아님)

    원인의 고찰


    NaN(비수)은 0/0 같은 것으로 수학적으로 정의되지 않은 결과에 사용됩니다.이번에 위치를 계산할 때 그런 연산이 있었다면 그 경위라는 것이다.
    그러나 원인을 분류한 후에 나는 우리의 각본에 이런 오류가 없다고 확신한다.이렇게 되면 물리 연산 이외에는 의심의 여지가 없다.
    처음엔 블렌더가 만든 모형에 무슨 문제가 있는 줄 알았더니 유닛 원통에 그물 모양 균형기를 덧댄 녀석으로 교체했는데 결과적으로 같은 오류가 발생한 것도 상관없다.

    이어서 우리는 표면 수량을 줄인 거친 모형(앞에)을 만들어 격자 균형기로 설정해 보았다.
    이렇게 몇 번 해봤는데 800장 정도면 괜찮았는데 똑같은 오류가 났어요.
    그물균형기에 따라 충돌 횟수가 많을수록 이 문제가 발생할 가능성이 높다는 것이다.그물 균형기 자체의 원인이라는 것이다.
    이후 대량의 메달이 한꺼번에 사라졌다. 동시에 이 버그가 발생하지 않았다면 어디의 메달 좌표가 낸이 되면 그와 인접한 메달의 물리적 연산도 낸이 사용했기 때문에 그 메달의 좌표도 오염되었을까?초콜릿 케이스만 스트레스가 한꺼번에 사라졌기 때문일 것이다.
    이후 같은 오류를 조사했지만 원트 픽스는...
    https://issuetracker.unity3d.com/issues/assertion-failed-invalid-aabb-a-error-appears-after-multiple-object-collision

    빈대를 피하다


    그래서 유닛을 사용하면서도 어쩔 수 없는 잘못이라고 생각한다.어떻게 된 거야?
    그물균형기를간단하게만들면그만큼수가많아도발생하기 어렵지만몇장이라도된다는보증이 없기 때문에(틀린장수는모양이같은균형기라도매번50%내외의범위내에서변한다)안심할 수 없다.
    좌표가 잘못된 GameObject는 float.IsNaN() 등으로 판단할 수 있습니다
    bool HasInvalidPosition(){
       return float.IsNaN(transform.position.x) || float.IsNaN(transform.position.y) || float.IsNaN(transform.position.z);
       //今回は全要素がNaNになるからxだけでもいいけど
    }
    
    ...그런데 그걸 했다고 해서'Destroy'나'Is Kinematic 좌표로 다시 바꾸지 않으면'처리가 계속 떨어진다.
    하지만 어떤 방법이든 메달 게임의 신뢰성을 떨어뜨리기 때문에 결국 버그 자체를 회피할 수밖에 없다.
    격자 균형기를 사용하지 않는 방법밖에 없다는 것이다.

    이처럼 초콜릿 박스를 몇 개 지정하면 수천 장을 넣어도 틀리지 않고 비슷한 행동을 하지만 처리 자체가 오히려 심해진다.근데 등에는 배를 바꿀 수가 없어요.
    물론 이 게임처럼'대량의 대상에 대해 모두 격자 균형기를 설정해야 하고 그 밀집'을 피해야 하는 것이 아니라면 격자 균형기를 피할 필요가 없다.
    어쩌면 아무리 검색해도 같은 상황에 빠지지 않은 보도의 원인일지도 모른다.

    아직, 아직 포기하지 않았어!


    하지만 초코박스로 지목하면 오히려 무거워지고 동작도 부자연스러워 그걸로 만족하나요!?
    아마도 격자 균형기는 더욱 최적화할 수 있을 것이다!
    따라서 균형기용 격자를 동적으로 생성한다.
    PolygonalMesh.cs
    using UnityEngine;
    
    public class PolygonalMesh : MonoBehaviour
    {
    
        public int angle = 12; //何角形か
        public float radius = 1f; //半径
        public float height = 2f; //高さ
    
        void Start()
        {
    
            //頂点を配置
            Vector3[] vertices = new Vector3[angle * 2];
    
            for (int i = 0, j = 0; i < vertices.Length; i += 2, j++)
            {
                float rad = 2 * Mathf.PI * j / angle;
                vertices[i + 0] = new Vector3(Mathf.Cos(rad), -height / 2f, Mathf.Sin(rad));
                vertices[i + 1] = new Vector3(Mathf.Cos(rad), height / 2f, Mathf.Sin(rad));
            }
    
            //メッシュを定義
            int[] triangles = new int[angle * 6 + (angle - 2) * 6];
    
            for (int i = 0, j = 0; i < angle * 6; i += 6, j++) //側面
            {
                int k = (j == angle - 1) ? -1 : j;
                triangles[i + 0] = j * 2;
                triangles[i + 1] = j * 2 + 1;
                triangles[i + 2] = k * 2 + 3;
                triangles[i + 3] = j * 2;
                triangles[i + 4] = k * 2 + 3;
                triangles[i + 5] = k * 2 + 2;
            }
    
            for (int i = angle * 6, j = 0; i < triangles.Length; i += 6, j += 2) //上下面
            {
                triangles[i + 0] = 0;
                triangles[i + 1] = j + 2;
                triangles[i + 2] = j + 4;
                triangles[i + 3] = 1;
                triangles[i + 4] = j + 5;
                triangles[i + 5] = j + 3;
            }
    
            Mesh mesh = new Mesh();
            mesh.vertices = vertices;
            mesh.triangles = triangles;
    
            mesh.RecalculateNormals();
    
            GetComponent<MeshCollider>().sharedMesh = mesh;
    
        }
    }
    
    자기가 썼을 때도 왠지 모르게'정다각기둥의 그물 모양을 만들어 균형기로 설정한다'고 했다.어떤 형태의 정다각주든 만들 수 있으니 자유롭게 사용하세요.
    그나저나 그물코에 직접 접촉한 적이 없어 이 기사를 참고했다.
    https://sleepygamersmemo.blogspot.com/2017/04/unity-mesh-square.html
    그럼, 이 녀석을 메달에 붙이면...

    이렇게 예쁜 12각기둥으로 변했다.
    박스 이퀄라이저로 만들면 움푹 들어간 부분이 조금씩 나오고, 다른 메달이 찔리면 그림이 겹치기 때문에 이를 막는 것도 높다.

    자신 있게 벽으로 둘러친 듯 1천장 넘게 쳤지만 고장 날 기미는 전혀 보이지 않았다.
    또한 룸 이퀄라이저에서 만들 때는 8각형으로 만들어졌지만 굉장히 잘 처리되지 않았다(1000장이면 내 환경에서는 20fps 정도). 이번에는 12각형인데도 70fps 정도를 유지하며 완벽했다.이거...했어!?

    역시 안 돼.


    즐겁게 기사를 쓰고 있을 때 게임 화면이 또 나왔다

    사라졌지?
    음, 이번에 와자와 함께 메달을 모았는데...
    1천장이 나왔지만 고장 날 때까지 1분 이상 걸렸고 발생 확률도 상당히 낮았는데...
    보통 게임이라면 많더라도 300장 모으지 않고...
    박스 이퀄라이저의 방법은 처리가 너무 느려서 원래는 안 되는데...
    즉,'동적 생성 균형기'의 방법은 근본적이지는 않지만 현실적인 해결책이 될 수 있다는 것이다.
    이렇게 하면 하나를 타협할 수 없나요?
    이렇게 말하지만 중대한 버그는 대응 요법만으로도 어렵기 때문에 근본적으로 수정할 수 있을 것으로 기대된다.

    좋은 웹페이지 즐겨찾기