-
7. 정점 쉐이더 ( Vertex shader )Software/DirectX 2024. 5. 24. 09:36728x90
Table of Contents
- 정점 쉐이더 단계
* 정점 쉐이더의 특성
* Local Space와 World Space
* Instancing( 인스턴스 생성 (복사본, 프리팹))
* World Matrix(월드 변환 행렬)
1. 카메라 행렬(View Matrix)
2. 투영 행렬(Projection Matrix)
* 2.1 시야 절두체
* 2.2 NDC(Normalize Device Coordinate)
* 2.3 투영변환 행렬
정점 쉐이더 단계
입력 조립기 단에서 삼각형들을 인덱스 목록에 따라 만들어서 정점 셰이더로 넘겨준다.
정점 셰이더는 정점 하나를 받아서 정점 하나를 출력하는 연산 함수로 생각해도 무방하다.정점 쉐이더의 특성
- 정점 셰이더의 함수는 GPU상에서 정점들을 연산하기 때문에 속도가 매우 빠르다.
- 정점 셰이더에서는 변환, 조명, 변위 매핑 등 다영한 특수효과를 처리할 수 있다.
- 정점 셰이더는 정점 데이터에 접근도 할 수 있고 텍스쳐, 변환행렬, 광원 정보등 GPU메모리 전반에 접근할 수 있다.
Local Space와 World Space
- 다리를 다른 공간에서 만들어 세트장에 가져와 배치만 하는것이 훨씬더 용이함
- 다리를 만드는 공간을 Local Space라고 하고 세트장을 World Space라고함
- 다리를 세트장에 옮길때는 World Transform이라는 행렬 변환을 거쳐야 함.(다리를 만든 공간상의 축과 좌표를 세트장의 공간행렬로 변환시키는 작업)
- 이 때 세계 변환을 하는 행렬을 World Matrix라고함
- 게임 세계 모든 물체에는 각각의 World Matrix가 있음
Instancing( 인스턴스 생성 (복사본, 프리팹))
- 한 물체가 한 장면에 여러번 재사용 될 때 , 정점정보를 여러번 재정의 해서 사용하는것은 부하가 심하다.
- 한 물체의 정점정보를 로컬좌표로 저장해놓고, World Matrix만 적절하게 변환해서 여러 군데 배치하면, 그 물체가 여러개 생성되는 것과 같은 효과가 있다. 이는 정점 정보 저장을 위해 메모리를 여러개 사용하지 않아 매우 효율적이게 된다. 이를 인스턴싱이라고 한다.
- 이렇게 생성된 오브젝트들은 주로 오브젝트 리스트에 WorldMatirx정보들을 담아두고 관리한다. 오브젝트 종류별로 다른 리스트에 두고 관리하면 게임을 구성하는 데 있어 편리할 것이다.
(ex) Playerlist , EnermyList - 이렇게 인스턴싱이 준비된 정점정보 객체를 복사본 혹은 프리팹(prefab)이라고 한다.
World Matrix(월드 변환 행렬)
- 이러한 월드 매트릭스는 앞에서 배운것과 마찬가지로 행렬형태로 만들 수있다.
- World Matrix = SRT
- S (Scale) R (Rotation) T (Transform)의 순서로 해당 물체를 월드 좌표계에 해당하는 동차행렬로 변환시킬 수 있고 이를 월드 변환 행렬이라고 한다.
- 후에 월드행렬의 후미에 공전을 위한 공전회전행렬, 이동좌표가 종속되는 부모행렬을 가리키는 부모행렬이 추가된다. 이는 후 장에서 다룬다.
1. 카메라 행렬(View Matrix)
- 카메라의 위치부터 월드 좌표계의 한점을 바라볼때 세계 좌표에서 시야 공간으로 좌표변경을 시야 변환(View Transform)이라고 한다. 해당 행렬을 View Matrix라고 부른다.
- 시야 행렬은 시야 공간에서 세계공간으로 변환하는 좌표행렬의 역행렬이라고 볼 수 있다.
- 월드 행렬 W는 보통 스케일은 다루지 않으므로 RT라고 볼수 있고, 따라서 뷰 행렬 V는 V = W^-1 이며, = T^-1 * R^T가 된다.
- 카메라의 위치와 대상점, 그리고 월드 상향벡터(up vector)만 있으면 카메라의 로컬좌표를 유도할 수 있고 이를 이용해서 View Matrix를 구할 수 있다
- 뷰 매트릭스 구성 매서드(레프트 핸들 기준, 내가 바라보는 방향이 Z+) XMMatrixLookAtLH( FXMVECTOR EyePosition // 카메라의 위치 Q FXMVECTOR FocusPosition // 카메라가 보는 점 T FXMVECTOR UpDirection // 월드 업벡터 J 보통 y축이므로 (0,1,0)이다 )
2. 투영 행렬(Projection Matrix)
3차원 공간을 2차원 이미지로 만들려면 투영변환을 한번 더 거쳐야한다.
투영을 반드시 평행선들이 하나의 소실점으로 수렴하게, 물체의 깊이가 증가함에 따라 투영의 크기가 감소하게 수행해야 한다.
이를 해결하는 방식이 바로 원근투영 (Perspective projection)이다.
투영 변환(Projection Transform)은 월드 좌표 상의 하나의 정점 v를 2차원 투영 평면과 만나는 점 v’로 변환하는 작업이다. 이때 v’를 v의 투영이라고 부른다.2.1 시야 절두체
시야 공간을 원점(카메라 시점)과 가까운 평면사이의 거리 n, 먼평면사이 거리 f, 수직 시야각a , 종횡비(후면버퍼에 그려질 장면의 윈도우 비율)로 표현할 수 있다.
- 점 (x,y,z)가 절두체 안에 있을 필요 충분조건
-r < x’ < r -1 < y’ < 1 n < z < f (n과 f는 가장 가까운 화면을 0,가장 먼 화면을 1이라고 가정한 0과 1 사이의값)
2.2 NDC(Normalize Device Coordinate)
위 방식으로 투영한 좌표계의 문제점은 종횡비를 하드웨어에게 일일히 보고해야 제대로된 좌표가 나온다는 점이다. 이는 연산에 큰 영향을 미친다.
종횡비를 연산에서 신경쓰지 않게 하기 위한 방법은 좌표계를 [-1,1]로 하는 공간안에 위치를 비례하여 사상시키는 것이다. 이 작업을 정규 좌표화(normalize Device coordinate)라고 한다.
noramalize Device coordinate를 거친 좌표는 -1,1 상의 한 점에 비례하여 하드웨어로 넘어가고 GPU는 종횡비를 몰라도 비례된 좌표로 점을 계산할 수 있게 된다. 하지만 NDC공간을 기준으로 한 투영 좌표를 공급하는 것은 프로그래머의 몫이 된다.
x, y는 [-1,1]구간으로 정규화 하지만 z축은 n<z<f의 값으로 정규화 되지 않았음에 유의한다.
NDC좌표는 너비가 2 높이도 2인 고정 출력화면이므로 하드웨어는 종횡비를 신경쓰지 않고 해당 비례좌표에 물체를 넣으면된다. 하지만 앞서 말했듯 비례좌표에 물체가 일그러지지않게 출력하는 것은 프로그래머의 몫이다.2.3 투영변환 행렬
z값도 정규화 시켜야하는데 투영변환 단계에서 z값이사라지게 된다.
따라서 z값을 투영변환 전에 저장시켜놔야 하는데 투영행렬 w값에 넣어서 저장해놓는다.- 정규화된 깊이
- *저장해놓은 z성분은 깊이 비교를 하기 위해 사용**된다. d3d는 깊이성분도 [0,1]구간으로 정규화한다. 이때 z값을 [0.1]값으로 사상하는 함수는 z성분들의 순서를 건드리지 않는 보존함수여야 한다.
깊이 보존함수의 치역이 작은 부분집합(가까운 부근 근처)에 몰려있기 때문에 변환된 z값이 조금만 달라도 컴퓨터가 제대로 인식하지 못하는 현상이 발생한다.
따라서 가까운 평면과 먼 평면을 최대한 가깝게 해서 깊이 정밀도 문제를 해결하는 것이 좋다. - 이렇게 만들어진 원근투영행렬을 곱하면 투영 좌표계에 정점이 들어가고, 여기에 원근 나누기를 하면 NDC에 정점이 들어가게 된다.
- 원근 투영행렬 매서드(왼손좌표계 기준)
XMMatrixPerspectiveFovLH( float FovAngleY, // 수직 시야각(라디안) flaot Aspect, // 종횡비 (넓이/높이) flaot NearZ, // 가까운 시야평면 flaot FarZ // 먼 시야평면
728x90'Software > DirectX' 카테고리의 다른 글
9. D3D 실제 구현 (0) 2024.05.24 8. 테셀레이션 ( Tessellation )과 기하 쉐이더 ( Geometry shader ) (0) 2024.05.24 6. 입력조립기 ( Input Assembler ) (0) 2024.05.24 5. 파이프라인과 3차원 표현 (0) 2024.05.24 4. 타이머 (0) 2024.05.24 - 정점 쉐이더 단계