게임엔진프로그래밍 - 수학

이미지
1. 브레젠험 직선 알고리즘 컴퓨터에서 계산이 느린 실수 연산을 사용하지 않고 직선을 그리기 위해 만들이진 알고리즘입니다. 평면을 아래와 같이 8분 면으로 나누어 직선을 그립니다. 링크:  https://sulinep.blogspot.com/2020/05/bresenhams-line-algorithm.html 2. 엔진 기초 수학 여기서는 본격적으로 구현에 들어가기 전 기초 수학 지식을 쌓았습니다.  수학에서의 체는 대수적 구조의 하나로 덧셈, 뺄셈, 곱셈, 나눗셈의 사칙연산을 집합 안에서 소화할 수 있는 집합을 의미합니다. 체를 이루기 위한 조건과 체라는 개념을 알아보았습니다. 처음에 체 라는 개념이 뭔가 머릿속에서 애매했는데 이후 갈로이스 체에 대해 배운 후 조금 더 명확해졌습니다. 스칼라 는 벡터를 정의하기 위한 필수 요소이고 크기만 있고 방향이 없는 성분이다. 벡터는 크기와 방향을 포함하는 표현 도구이다. 겨기서 벡터의 기본 연산자들을 알아보았습니다. 선형성 은 직선처럼 똑바른 도형 또는 그와 비슷한 성질을 가진 대상이라는 뜻으로 함수의 경우 함수가 진행하는 모양이 직선이라는 의미로 사용된다. 선형성을 만족하려면 두 가지 조건을 만족해야 하는데 균질성과 첨가성이다. homogeneity (균질성):   additivity (첨가성): 선형이라고 부르는 수식들은 중첩의 원리 가 적용된다는 특징이 있다. 이때 행렬과 선형 변환의 관계에 대하여도 알아보았었는데 선형 변환과 행렬은 1:1 대응된다. 기저 란 어떤 벡터 공간을 선형 생성하는 선형 독립인 벡터들이다. 각각의 원소들이 다시 벡터 공간을 생성할 수 있어야하고 일차 독립이어야 한다. 표준 기저 는 많은 기저들 중 성분 1개만이 1이고 나머지 성분이 모두 0인 표준 적인 벡터이다. 여기서 벡터 공간 R의 기저를 구성하는 원소의 개수가 해당 공간의 차원 이다. 행렬 은 열기반 행렬과 행기반 행렬 중 어떤 걸 사용하느냐에 따라 계산 방식이 달라진다. 여기서는 벡터의 크기, 회전, ...

오일러 각, 로드리게스 회전 공식, 평면의 방정식

이미지
1. 오일러 각 오일러 각은 강체가 놓인 방향을 3차원 공간에 표시하기 위해 있는 세 개의 각도이다. 1) 짐벌락 (Gimbal lock) 이 현상이 발생하는 이유는 일단 오일러각은 특 징상 세축이 종속적이기 때문에 발생한다. 오일러 각을 이용해 강체를 회전하다 보면 두 개의 축이 거의 일치하여 회전이 2축으로 한정되는 사태를 이야기합니다. 이 현상은 자이로스코프라는 기기를 보면 현상을 쉽계 알 수 있습니다. 이 현상을 최소화 하려면 특정 축이 90가 되지 않거나 종속 구조를 바꾸는 방법이 있습니다. 그림으로 표현하기가 힘들어 유튜브에 좋은 영상이 있어 링크를 남깁니다. https://www.youtube.com/watch?v=zc8b2Jo7mno 2) 오일러각이 두 축에 회전에 대해서 보간이 성립하지 않는 이유 일단 이유는 오일러 각에서는 회전을 세 축으로 나누어 계산하기 때문이다. 특정 각들을 x -> y -> z 순으로 회전했다고 생각해보면 X 축을 먼저 회전 시킨 값에 Y 값을 회전 하고 마지막으로 Z 축 회전을 한다. 이걸 수학 공식으로 풀어보면  일단 X, Y, Z 축 순서대로 각각 (60, 20, 0) 그리고 (10, 20, 0) 도씩 회전 시켰다고 보면 (행렬 계산을 간략화 표기 I = Identity)   이기 때문에 일방적으로 생각하는 (70, 40, 0) 도 회전 시켰다와는 다른 값이 나온다. 만약   와 같이 계산한다면  (70, 40, 0) 도 회전과 똑같을 것입니다. 2. 로드리게스 회전 공식 임의의 축에 대한 회전 을 구현하기 위해 사용한다. 먼저 여기서 벡터의 투영이 쓰이기 때문에 벡터의 투영 공식을 간단히 적어 놓았다 일단 r의 벡터를 구하기하기 위해 P 의 점에서 O의 점을 뺀다. 그 다음 r 벡터에 OO' 벡터를 빼주면 O'P 벡터가 나올 것이다. 다음은 좀 보기 편하게 임의의 축과 평행인 상태에서 바라보면 다음과 같을 것이다. 위에서 OO' 벡터를 구했고 이제 q...

[게임 수학] 외적을 이용한 왼쪽 오른쪽 구분

이미지
벡터의 외적을 이용하면 지정한 물체가 왼쪽에 있는지 오른쪽에 있는지 구분할 수 있습니다. 벡터를 이용해 어떤 물체가 왼쪽에 있는지 오른쪽에 있는지 판단은 외적의 특징을 이용해 판단합니다. 외적의 순서를 바꾸면 항상 부호가 반대의 결과를 가지는 벡터를 만들어냅니다. 1. 타겟의 위치에서 자신의 위치를 빼 타겟을 바라보는 벡터를 만듭니다. 2. 위에서 만든 벡터와 자신의 포워드 벡터를 외적합니다. 3. 외적한 값과 Up 벡터를 내적합니다. 4. 내적한 결과가 양수가 나오면 왼쪽에 위치한 것이고 음수라면 오른쪽에 위치한 것입니다. Vector3 targetDir = this .target.position - this .transform.position; // 타겟 방향으로 향하는 벡터를 구하기 Vector3 crossVec = Vector3.Cross(targetDir, this .transform.forward); // 포워드와 외적 float dot = Vector3.Dot(crossVec, Vector3.up); if (dot > 0 ) // 왼쪽 { desc = "왼쪽" ; } else if (dot < 0 ) // 오른쪽 { desc = "오른쪽" ; } else // 0 이라면 평행하기 때문에 가운데라고 적어두었다. { desc = "가운데" ; }

[카메라] 백페이스 컬링과 원근 투영

이미지
1. 백페이스 컬링 백페이스 컬링은 그리기 단계에서 화면상 보이지 않는 불필요한 폴리곤을 잘라내 렌더링을 하는 기법중 하나입니다. 컬링에는 백페이스 컬링, 오클루전 컬링, 프러스텀 컬링이 있습니다. 오클루전 컬링(Occlusion Culling)은 다른 오브젝트에 가려 카메라에 보이지 않는 오브젝트의 렌더링을 비활성화 하는 기법입니다. 프러스텀 컬링(View Frustum Culling)은 절두체 컬링이라고도 합니다. 해당 컬링은 실제로 카메라의 시야 범위에 포함되는 것들만 렌더링하고 나머지는 렌더링을 비활성화하는 기법입니다. 그럼 백페이스 컬링은 어떤 걸까요? 백페이스 컬링은 카메라에서 보이지 않는 뒷면의 폴리곤을 렌더링하지 않는 기법 입니다. 일단 백페이스 컬링을 위해서는 그리기 순서가 필요합니다. DirectX를 해보신 분을 알겠지만 DirectX에서 사각형을 그릴때 그리기 순서 즉 그려질 버텍스들의 인덱스 순서를 잘 맞춰줘야 원하는데로 그려집니다. 위와 같이 생긴 폴리곤을 그린다고 가정해보면 왼쪽 폴리곤은 반시계방향으로  오른쪽 삼각형은 시계 방향으로 돌아가며 그려집니다. 즉 왼쪽 폴리곤은 그려지고 오른쪽 폴리곤은 컬링 됩니다. 그럼 이걸 어떻게 컴퓨터에서 인지하고 컬링을 해줄까요? 위의 정보는 두 벡터 값으로 표현할 수 있습니다. 그리고 두 벡터 값을 외적하면 해당 축과 직교하는 벡터가 나오는데  이 벡터가 카메라 방향을 향한다면 그려주고 반대라면 컬링합니다. 이제 방향을 향하고 있는지 아닌지는 내적을 이용하면 간단하게 구할수 있습니다. 사용하는 코드에서는 오른손 좌표계를 사용하기 때문에 화면에 그릴려면 (0,0,-1)과 내적하여 양수의 값이 나온다면 컬링합니다. 반대로 (0,0,1)로 내적하면 결과 값이 양수라면 그려주기만 하면됩니다. 왼쪽: 백페이스 컬링 미적용,  오른쪽: 백페이스 컬링 적용 2. 원근 투영 원근 투영 행렬을 유도하기 전에 카메라가 렌더링할 영역을 보면 아래와 같은 모양의 절두체가 나올 겁니다. 절두체는 ...

카메라의 행렬

이미지
1. 회전 행렬 각각의 축에대한 회전 행렬입니다. 이 행렬들은 2차원 회전 행렬에 사용되는 것을 그데로 응용하여 만들 수 있습니다. 좌표가 변화가 되는 것은 한 축이 회전할 때 2개의 좌표만 변화되기 때문에 x축을 기준으로 회전 한다고 보면 x의 값은 변하지 않으니 그데로 두고 나머지 축에 대해서만 연산을 진행합니다. 이 행렬들을 하번에 곱해서 오일러 회전 행렬을 구하는 공식을 유도해보았습니다. (여기서 sp cy등의 의미는 접두: s = sin, c = cos, 접미: y = yaw,  p = pitch,  r = roll) 결과 값을 이용해 행렬을 만들고 최종적으로 TRS 행렬을 만들어주면 됩니다. 2. LookAt 행렬 보통 게임에서의 카메라는 주인공 캐릭터를 바라보거나 특정 대상을 바라봅니다. 이번에는 해당 지점을 바라보는 LookAt 행렬을 만들어보겠습니다. (해당 프로젝트에서는 오른손 좌표계를 사용하며 Z+는 화면 앞쪽을 향합니다.) 여기서 Forward 는 Roll (Z), Right는 Pitch(X), Up은 Yaw(Y) 라고 보겠습니다. 1) 카메라의 위치에서 바라보려는 물체의 위치를 빼서 Forward 백터를 구합니다. 2) World의 Y 좌표와 외적해 Right 벡터를 구합니다. 3) Up 벡터를 구하기 위해 위에서 구했던 Foward 벡터와 Right 벡터를 외적합니다. 4) 마지막으로 위의 3개의 벡터 축을 하나의 행렬로 만들어 역행렬로 만들어주면 끝입니다. 하지만 직교 행렬에서 역행력은 전치 행렬과 같기 때문에 계산이 적은 전치를 이용합니다. 3. 위의 LookAt 행렬에서의 문제점 만약 카메라가 (0, 500, 0)의 위치에서 (0, 0, 0)을 바라보면 어떻게 될까 일단 LookAt 행렬을 구하는 방법을 다시 확인해보면 World의 Y축을 가져와 Right 벡터를 구합니다.  하지만 좌표가 위와 같은 경우라면 외적한 값이 (0, 0, 0) 이 나와버려 이상한 결과가 나와버릴겁니다. 가장 간단한 해결 방법은...