Game Develop

nan값 조심하자 본문

ComputerGraphics/My Project

nan값 조심하자

MaxLevel 2022. 8. 11. 16:05

예전에 2D포폴했을때는 몬스터->플레이어의 방향벡터를 정규화하는 과정에서 nan값이 발생했었다.

분모에 0이 들어가면 안되는데, 몬스터랑 플레이어랑 거의 겹쳐져버리면 x2-x1값도 0, y2-y1값도 0이라 분모에 루트0값이 들어가버려서 nan값이 발생했었다.

 

근데 이번에도 몬스터가 증발하길래 열심히 추적해서 해결했다. 

 

 

먼저 여차저차해서 몬스터의 WorldMatrix값에 nan값들이 포함되어있는걸 확인 -> rotation.y가 nan값이 발생되는걸 확인-> assert이용해서 어떤 함수에서 rotation.y에 nan값이 대입되는지 확인 ->  해당함수 벡터값 다 출력찍어봐서 확인 -> cmath::acos 함수에서 nan값이 리턴(!).

acos 관련 글 :

https://runebook.dev/ko/docs/cpp/numeric/math/acos

 

C++ - 표준 :: acos, 표준 :: acosf, 표준 :: acosl - 오류가 발생하지 않으면 [0 , π] 범위에서 arg(arccos(arg))

1-3) arg 의 아크 코사인의 주요 값을 계산합니다 . 오류가 발생하지 않으면 [0 , π] 범위 의 arg (arccos(arg)) 의 아크 코사인 이 반환됩니다. 도메인 오류가 발생하면 구현 정의 값이 반환됩니다 (지원

runebook.dev

즉,매개변수가 -1 ~ 1의 범위를 벗어나면 nan값을 리턴.

 

일단 해당함수코드.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void Transform::RotateToDestinationForModel(Transform* transform, Vector3 dest) // 회전시키고자 하는 transform과 목표지점벡터. 
{
    dest = dest - transform->mPosition; 
    dest.Normalize(); // 정규화
 
    Vector3 tempForward = transform->GetForwardVector();
 
    Vector3 forward = tempForward * -1.0f; // 모델 포워드 거꾸로 되어있어서 -1 곱
    float dotValue = Vector3::Dot(forward, dest); // 얼마나 회전할지.  
 
    if (dotValue < -1.0f)
    {
        dotValue = -0.99f;
    }
 
    if (dotValue >= 1.0f)
    {
        dotValue = 0.99f;
    }
 
    dotValue = acos(dotValue);
 
    Vector3 tempDirection = Vector3::Cross(forward, dest); // 어디로 회전할지 
 
    if (tempDirection.y < 0.0f) // 목표지점디렉션이 포워드벡터보다 왼쪽에 있으면
    {
        transform->mRotation.y -= dotValue;
    }
 
    else if (tempDirection.y >= 0.0f) // 디렉션이 포워드벡터보다 오른쪽에 있으면
    {
        transform->mRotation.y += dotValue;
    }
 
    bool check = false;
 
    if (isnan(tempForward.x) || isnan(tempForward.y) || isnan(tempForward.z))
    {
        check = true;
    }
 
    assert(!check && "mRotation.y is Nan!!!!");      
}
cs

 

딱히 별다를게 없는 오브젝트를 타겟을 향해 회전시키는 코드.

말했듯이 acos에 값이 1이 들어가서 nan값이 발생한걸 확인. 1은 내적값 결과라서 확인해본 결과 내적을 위한 두 벡터가 거의 같은값의 벡터가 되버리는 경우가 발생. 거의 같은방향벡터면 사이각이 0이라 코사인 0도인 1을 리턴했기 때문에 acos에 1이 들어가서 nan값을 리턴했던 것.

이제서야 보고나니 런타임중에 충분히 두 벡터가 같을 경우가 있을만 하다고 생각했다. 

일단은 저렇게 임시코드..를 작성. 당장의 생각으로는 저렇게해도 큰 문제가 없다고 판단했다.

애초에 worldMatrix의 값을 건드는 코드일 경우, 반드시 nan값을 체크하는 assert를 박아넣자.

'ComputerGraphics > My Project' 카테고리의 다른 글

그림자매핑 구현.  (0) 2022.10.03
여러가지 개선.  (0) 2022.08.16
기본 UI 구현  (0) 2022.08.03
고유이름(태그) 설정하기.  (0) 2022.07.29
DLL파일 버전 교체할 때 알아두면 좋은 점.  (0) 2022.07.28