-
게임 엔진
- 사용자 입력 (User Input)
- 자원 관리 (Resource Management)
- 그래픽 로딩과 렌더링 (Loading and Rendering Graphics)
- 스크립트 해석과 실행 (Interpreting and Executing Scripts)
- 음향 처리 (Playing Sound Effects)
- 인공 지능 (Artificial Intelligence)
-
기본 요소
-
점
-
선
-
면
- 메쉬(모델)
-
모델 좌표계
- 모델은 각자의 기본 모델 좌표를 가지고 있다. (지역)
-
이는 나중에 월드 좌표계로 변환되어야 한다.
- 이 때, 월드 변환 행렬이 적용된다.
-
와인딩 순서
- 메쉬를 구성하는 다각형의 정점들의 나열 순서.
- 은면 제거(Back Face Culling)를 위해서 사용.
- DirectX는 기본으로 시계 방향이다.
- 즉, 카메라가 볼 때 시계 방향이면 보이는 면, 시계 반대 방향이면 은면.
-
변환 파이프라인
-
월드(World) 변환
- 정점(모델 좌표계)을 월드 좌표계로.
-
카메라(View) 변환
- 월드 좌표계를 카메라(View) 좌표계로.
-
투영(Projection) 변환
- 카메라(View) 좌표계를 투영 좌표계로.
- 이 변환으로 인해 3D -> 2D 가 된다.
-
화면(Screen) 변환
- 투영 좌표계를 화면 좌표계로.
-
정리
- 정점 -> 월드 -> 카메라 -> 투영 -> 화면
- 모델을 구성하는 모든 정점(모델 좌표)를 변환 파이프라인을 거치면 화면상의 픽셀 좌표를 얻을 수 있다.
-
월드 변환
- 회전 변환과 평행이동 변환을 수행한 결과.
- 그것이 월드 좌표.
-
카메라 변환
-
카메라 평면
- 3차원 공간이 투영되어 가상 카메라에 나타나는 2차원 평면.
- 월드 좌표계의 정점들은 카메라의 좌표를 기준으로 다시 정의되어야 함.
-
위치, 방향, Field Of View 등의 속성.
-
FOV(Field Of View)
- 카메라에서 보이는 공간.
- 이 공간 안에 속한 객체들만 카메라를 통해 볼 수 있다.
- 카메라 중심을 기준으로 좌우, 상하 대칭.
- 화각(Viewing Angle)
- 카메라에서 볼 수 있는 각도.
-
방향
- 카메라의 회전양.
- 회전한 만큼 돌아가니까 방향이 변하는 게 맞지?
-
위치
- 카메라의 위치.
- 좌표.
-
과정
- 1) 카메라를 월드 좌표계의 원점으로 평행이동.
- 2) 같은 변환을 게임 세계의 모든 객체에 적용.
- 3) 카메라 좌표계의 축들이 월드 좌표계의 축들과 일치하게 카메라를 회전.
- 4) 같은 변환을 게임 세계의 모든 객체에 적용.
- 결과로 카메라 좌표가 만들어짐.
-
원근 투영 변환
- 원근을 2D로 나타내기 위하여.
- 객체와의 거리가 증가하면 객체는 카메라의 FOV 중심으로 움직이는 경향. (멀어지니까)
- 카메라와 객체까지의 거리는 z좌표의 델타값.
- x값과 y값을 상대적인 z값으로 나누면 2차원으로 변환이 가능.
- 결과로 투영 좌표(뷰포트(Viewport) 좌표, 클립 공간)가 만들어진다.
-
카메라 평면
- 투영 윈도우라고도 한다.
- FOV 공간에 있는 정점들이 투영되는 공간.
-
투영 평면
- -1 < x < 1 and -1 < y < 1 인, 카메라의 화각 사이의 평면
-
FOV 화각이 90도일 때
- FOV 정점들을 투영 변환 하면 x좌표와 y좌표는 -1과 1사이의 값을 갖게 된다. (z값으로 나누니까)
- FOV 공간에 포함되지 않는 정점들은 x좌표와 y좌표가 -1보다 작거나 1보다 큰 값을 가진다
-
FOV 화각이 90도가 아닐 때
- Xprojected = x / (z / d)
Yprojected = y / (z / d)
- d는 카메라에서 투영 평면까지의 거리를 의미.
- 투영 평면을 카메라에서 멀게 하면 화각이 작아진다. (가깝게 하면 커진다.)
- 투영 평면의 크기는 변하지 않기 때문. (언제나 -1보다 크고 1보다 작다)
- 즉, d의 크기를 조절하면 FOV 화각의 효과를 만들어 낼 수 있다.
- DirectX11 에서는 투영 평면까지의 거리가 항상 1.0이다. (화각이 항상 90도이다.)
- 즉, 투영 변환이 일어나기 전에, 계산된 투영 평면의 좌표에 d 값을 임의로 계산시켜서 화각의 효과를 낸다.
-
절두체
- 카메라가 [ 볼 수 있는 ] 가장 가까운 평면을 근평면, 가장 먼 평면을 원평면이라 한다.
- FOV에 따라 정사각뿔 형태의 공간이 생기는데, 이는 근평면과 원평면 사이의 공간만으로 잘리게 된다. ( 볼 수 있는 공간이 근평면 ~ 원평면이니까. )
- 이 사이 공간을 절두체라고 한다.
-
화면 좌표 변환
- 2차원으로 변환된 투영 좌표를 화면 좌표로 바꾸는 변환.
-
뷰포트(Viewport)
- 렌더링할 대상의 화면 영역. (Render Target?)
-
요소
- (화면 좌표계에서의) 원점 위치 (Left, Top)
- 가로 크기
- 세로 크기
-
화면 좌표 계산
- 투영 좌표계의 한 점
- ScreenX = projVertex.x * (뷰포트 가로 / 2) + 뷰포트 원점.x + (뷰포트 가로 / 2)
ScreenY = (-1) * projVertex.y * (뷰포트 세로 / 2) + 뷰포트 원점.y + (뷰포트 세로 / 2)
- 화면 좌표계는 Y축이 반대 방향이므로 Y좌표에 -1을 곱해 줌.
- 이렇게 최종적으로 픽셀로 나타나는 화면 좌표가 만들어진다.
-
기본 수학
- 벡터의 합
-
벡터의 차
- 한 점 A에서 점 B로 객체를 이동할 때 이동 방향은 (B벡터 - A벡터)의 단위 벡터이다.
- 직접 그려보면 알게 된다.
- 스칼라 곱 (실수배)
- 벡터의 크기
-
벡터의 정규화 (크기를 1로)
- 단위 벡터(노멀 벡터) : 방향만을 나타내고자 할 때 사용.
- [ 방향을 나타내는 단위 벡터 ]에 이동거리를 곱하여 얻어진 벡터를 [ 물체 위치 벡터 ]에 더하면 최종 위치가 나온다.
- 다각형의 방향을 나타낼 때도 사용.
- 즉, 메시를 구성하는 면이 어느 방향으로 향하는지를 단위 벡터로 표현.
- normal
-
벡터의 내적
-
정의
- 두개의 벡터가 이루는 각도를 구할 수 있다.
- 결과값은 실수이다.
- 결과값이 0이라면 수직.
- 결과값이 0보다 크면 예각.
- 결과값이 0보다 작으면 둔각.
-
카메라를 보는가?
- 메시의 평면 법선 벡터를 알면 그 면이 카메라를 향하는지를 알 수 있다. (은면인가 아닌가)
- [ 평면의 법선 벡터 ] 와 [ 카메라에서 평면의 모서리 점 ] 까지의 벡터를 내적.
- 예각이면 보는 방향이 비슷한 쪽이다. 즉, 카메라를 보고 있지 않다.
- 둔각이면 보는 방향이 다르다. 즉, 카메라를 보고 있다.
-
직교 투영 벡터
- 한 벡터를 한 단위 벡터에 직교 투영하면
- p = ( |v|cosθ )n = ( |v||n|cosθ )n = ( v · n )n
- 단위 벡터의 크기( |n| )은 1이니까 맘대로 곱함.
- 단위 벡터에 수직인 벡터에 직교 투영을 하면
- q = v - ( v · n )n
- p와 q는 서로 직교하며, p + q = v가 된다.
- dot
-
벡터의 외적
- 두 개의 벡터에 수직인 벡터를 구할 수 있다.
-
왼손 법칙이 적용된다.
- 엄지가 A벡터
- 검지가 B벡터
- 중지가 ( A X B )가 된다.
- 엄지 검지 바뀌면 ( B X A )가 되지? 다르지?
- ( A X B ) = (-1) * ( B X A)
-
법선 벡터
- 면의 방향.
- 면이 바깥쪽으로 향하는 방향.
- 바깥쪽이 무슨 소리여?
- 보통 정규화 하여 단위 벡터로 사용한다.
- 회전축을 구하기 위해 사용될 수 있다.
- 회전 된 위치의 벡터랑 회전하기 전 위치의 벡터를 외적하면 회전축이 나옴.
- 그리고 내적을 하면 회전양이 나오겠지?
- cross
-
평면의 방정식
- [ 평면 위의 한 점 ] 과 [ 평면의 법선 벡터 ]로 이루어진다.
-
평면 벡터
- 법선 벡터 ( a, b, c )에 원점에서 평면까지의 거리 d가 추가 되어 ( a, b, c, d )의 벡터.
- 차후 필요하면 공부해서 추가.
-
행렬
- 차후 필요하면 공부해서 추가.
-
행렬을 사용한 변환 파이프라인
-
모델 좌표계의 한 점
- 모든 변환 행렬은 이 점에다가 곱하는 것이다.
-
월드 변환 행렬
- 월드 좌표계에서 객체의 위치와 방향을 표현.
-
월드 변환 행렬 W
- Right x, Right y, Right z, 0
Up x, Up y, Up z, 0
Look x, Look y, Look z, 0
Position x, Position y, Position z, 1
- 4번째 행 : 객체의 위치
- 1번째 행 : Right 벡터 ( x축 )
- 2번째 행 : Up 벡터 ( y축 )
- 3번째 행 : Look 벡터 ( z축 )
- [ 축이 어떤 방향인가? ] 만을 나타낸다.
- ( 1,1 ), ( 2,2 ), ( 3,3 )은 객체의 크기 변환을 나타낼 수 있다. (Right의 x, Up의 y, Look의 z)
- 이제 월드 좌표계에서 이동을 하고 싶다면, 행렬의 한 행만을 뽑아서 각 요소에 거리를 곱하면 이동한 좌표가 나온다.
-
충돌 검사
- 월드 상의 모든 객체들의 좌표가 있기 때문에, 충돌 검사를 여기서 수행한다.
-
만드는 법
- 우리가 직접 Right, Up, Look 벡터를 만들고 초기화하여 쭉~ 사용한다.
-
카메라 변환 행렬
- 카메라도 게임의 한 요소이므로, 월드 좌표에서의 위치와 방향을 가진다.
- 말하자면, 카메라의 정보는 월드 좌표상의 정보이다.
- 이 변환은 카메라를 기준으로 월드를 나타내야하기 때문에 필요.
- 카메라 변환 행렬, 또는 뷰 행렬이라고 부른다.
-
개념
- 월드 좌표를 카메라에 맞춰라?
- 카메라가 월드의 한 지점에 위치하려면 카메라의 정보에 월드 변환 행렬을 적용시켜야 한다.
- 반대로 말하자면, 카메라의 월드 좌표에 월드 변환 행렬을 적용한 걸 반대로 따라가면 원래 카메라의 정보가 나온다.
- 즉, 카메라의 위치, 회전 정보에 월드 변환 행렬의 역행렬을 곱하게 되면, 카메라를 기준으로 좌표가 맞춰지게 된다!!!
-
카메라 변환 행렬 V
- m_vRight.x, m_vUp.x, m_vLook.x, 0
m_vRight.y, m_vUp.y, m_vLook.y, 0
m_vRight.z, m_vUp.z, m_vLook.z, 0
-(m_vPosition · m_vRight), -(m_vPosition · m_vUp), -(m_vPosition · m_vLook), 1
- 월드 변환 행렬 W의 역행렬
- 4번째 행은 내적의 결과인 실수값. (회전양)
- m_v 라는 접두어는 카메라의 벡터 정보를 뜻한다. (카메라도 월드의 한 좌표니까)
-
만드는 법
-
월드 변환 행렬의 역행렬
- 역행렬 함수. D3DXMatrixInverse
-
D3DXMatrixLookAtLH 함수 사용
- Eye 벡터, At 벡터, Up 벡터가 인자로 들어간다.
- Eye 벡터 = 카메라의 위치.
- At 벡터 = 카메라가 바라보는 지점.
- Up 벡터 = 월드 좌표의 Up 벡터. 보통 ( 0, 1, 0 ) 사용
- m_vLook = normal( pAt -pEye )
m_vRight = normal( cross( pUp, m_vLook ) )
m_vUp = cross( m_vLook, m_vRight )
- 이런 방법으로 카메라 변환 행렬을 생성.
-
투영 변환 행렬
-
투영 공식
- 2DProjectedX = ViewSpaceX / ViewSpaceZ
2DProjectedY = ViewSpaceY / ViewSpaceZ
- 이는 FOV가 90도일 때, ( x, y, z ) 를 ( x/z, y/z, 1 ) 즉, ( x/z, y/z ) 로 만드는 것이다.
-
이 변환의 문제점
- FOV가 90도인 것은 일반적이지 않다. ( 게임 대부분은 60도나 45도의 화각을 가진다고 함. )
- 모니터는 정사각형이 아니라 직사각형이다.
- 즉, 투영 좌표계에서 화면 좌표계로 될 때, 늘려져서 보인다는 말이다.
- 가로와 세로의 비율이 1:1이 아니기 때문에 왜곡이 발생.
-
방법
- x와 y를 z로 나누기 전에 미리 왜곡시키자.
- 가로가 세로보다 크다면 x를 더 작게.
- 이것은 크기 변환에 해당한다.
- 이러한 왜곡에 사용되는 변환 행렬을 원근 투영 변환 행렬이라고 한다.
-
원근 투영 변환 행렬
- R = 종횡비 ( 4:3 = 1.333... , 16:9 = 1.777... )
- 카메라 좌표계에 크기 변환 행렬을 곱하여 미리 왜곡시킨다.
- x 값의 왜곡이 필요하다면...
- 1/R, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 1
0, 0, 0, 0
- 이 값을 곱하면 카메라 x가 작아진다.
- 이렇게 해서 나온 좌표계를 동차 클립 좌표계라고 한다.
- 동차 클립 좌표계를 z로 나눠주면 투영 좌표계가 나온다
- ( 4, 4 )에 있던 1이 ( 4, 3 )으로 갔다. 이는 ( x, y, z, 1 )을 ( x, y, z, z )라는 결과로 바꿔준다.
- 맨 마지막 z를 w값이라고 하며, 깊이 관련의 계산에 사용 가능하다. (깊이 값을 따로 남겨두는 것)
-
투영 변환 행렬
-
임의의 FOV 값을 가지는 카메라의 투영 변환 행렬
- 1/tan(θ), 0, 0, 0
0, 1/tan(θ), 0, 0
0, 0, 1, 1
0, 0, 0, 0
-
종횡비와 FOV 모두 가지는 최종 투영 변환 행렬
- { 1/tan(θ) } / R, 0, 0, 0
0, 1/tan(θ), 0, 0
0, 0, 1, 1
0, 0, 0, 0
- 이 w값을 사용하여 동차 클립 좌표계의 값도 구할 수 있다.
-
만드는 법
-
D3DXMatrixPerspectiveFovLH 함수 사용
- fovy
- y축 방향의 FOV각도 (라디안)
- r
- 종횡비
- zn
- 근평면의 z값
- z-near
- zf
- 원평면의 z값
- z-far
-
화면 좌표 변환 행렬
-
DirectX 11의 뷰포트 구조체
-
D3D11_VIEWPORT
- 왼쪽 위 x
- 왼쪽 위 y
- 가로
- 세로
- 최소 깊이
- 최대 깊이
-
투영 좌표계의 ( x, y )를 화면 좌표계로 변환
- xScreen = x * ( 뷰포트 가로 / 2 ) + 왼쪽 위 x + ( 뷰포트 가로 / 2 )
yScreen = y * ( 뷰포트 세로 / 2 ) + 왼쪽 위 y + ( 뷰포트 세로 / 2 )
-
화면 좌표 변환 행렬
- ( Width / 2 ), 0, 0, 0
0, -( Height / 2), 0, 0
0, 0, ( MaxDepth - MinDepth ), 0
TopLeftX * ( Width / 2 ), TopLeftY * ( Height / 2 ), MinDepth, 1
-
변환 파이프라인을 넘나들자
-
마우스 픽킹
- 마우스를 찍어서 좌표를 알려주거나, 물체와의 충돌을 감지.
- 화면 좌표계부터 쭉~ 역변환을 하여 카메라 좌표, 또는 월드 좌표까지 간다.
- 그리고 판별.
-
DirectX11 라이브러리
-
벡터
-
D3DXVECTOR3
- (2, 3, 4)가 존재.
- x, y, z
-
평면
-
D3DXPLANE
- a, b, c, d
-
행렬
-
D3DXMATRIX
- 4*4 행렬
-
연산
-
벡터
-
D3DXVec3Length
- 크기
-
D3DXVec3Dot
- 내적
-
D3DXVec3Normalize
- 정규화
-
D3DXVec3Scale
- 스칼라곱 (실수배)
-
D3DXAdd
- 덧셈
-
D3DXSubtract
- 뺄셈
-
D3DXVec3Cross
- 외적
-
행렬
-
D3DXMatrixIdentity
- 단위 행렬
-
D3DXMatrixInverse
- 역행렬
-
D3DXMatrixMultiply
- 행렬곱
-
D3DXMatrixScaling
- 크기 변환
-
D3DXMatrixTranslation
- 평행 이동 변환
-
D3DXMatrixRotationX
- (X, Y, Z)가 존재.
- X축을 중심으로 Angle만큼 회전.
- 회전 변환
-
D3DXMatrixRotationAxis
- 벡터 하나를 축으로 회전 변환
-
D3DXMatrixRotationYawPitchRoll
- x축을 Pitch, y축을 Yaw, z축을 Roll 만큼 회전 변환.
- 회전의 순서는 z축, x축, y축이다.
-
평면
-
D3DXPlaneFromPointNormal
- 한 점과 법선 벡터로부터 평면을 반환
-
D3DXPlaneFromPoints
- 세 점으로 평면을 반환
-
D3DXPlaneDotNormal
- 평면 벡터와 한 벡터의 내적값 반환
-
D3DXPlaneDot
- 한 점을 나타내는 벡터를 사용하여 평면 벡터와 내적.
- 점과 평면의 위치 관계
- 0이면 평면 위에, 음수면 평면 뒤에, 양수면 평면 앞에 존재한다.
-
D3DXPlaneNormalize
- 법선 벡터의 크기로 a, b, c, d를 정규화.
- 정규화된 d 값이 원점에서 평면까지의 거리를 나타낸다.
-
벡터 변환
-
D3DXVec3TransformCoord
- 벡터를 ( x, y, z, 1 )의 동차 좌표로 바꾸어 행렬과 곱하고, 3차원 벡터로 반환. ( w 나누기를 수행 )
-
D3DXVec3TransformNormal
- 법선 벡터를 ( x, y, z, 0 )의 동차 좌표로 바꾸어 행렬과 곱하고, 정규화하여 3차원 벡터로 반환.
-
D3DXVec3Transform
- 벡터를 ( x, y, z, 1 )의 동차 좌표로 바꾸어 행렬과 곱하고, 4차원 벡터로 반환. ( w 나누기 수행 안 함 )