Download presentation
Presentation is loading. Please wait.
1
/11 CUDA 를 이용한 병렬 프로그래밍 DirectX 3D 를 이용한 3D 프로그래밍 2009. 7. 13
2
/11 1.1 CUDA 를 사용한 Programming 의 장점 1 GPU 는 CPU 에 비해 ALU 의 수가 많다. 따라서, 작업을 동시에 처리할 수 있는 능력이 뛰어나다. 그렇기 때문에 GPU 에서 Program 이 실행되면, 반복적인 작업을 많이 처리하는 작업에서 월등한 성능향상을 기대할 수 있다. GPU 에서 실행하는 Program 을 CUDA 를 이용하면 만들 수 있다. 또한 기존의 GPU Based Programming 과는 달리 CUDA 는 C 언어에 기본을 두고 있기 때문에, C 언 어 Programmer 가 쉽게 접근할 수 있다. GPU 는 CPU 에 비해 ALU 의 수가 많다. 따라서, 작업을 동시에 처리할 수 있는 능력이 뛰어나다. 그렇기 때문에 GPU 에서 Program 이 실행되면, 반복적인 작업을 많이 처리하는 작업에서 월등한 성능향상을 기대할 수 있다. GPU 에서 실행하는 Program 을 CUDA 를 이용하면 만들 수 있다. 또한 기존의 GPU Based Programming 과는 달리 CUDA 는 C 언어에 기본을 두고 있기 때문에, C 언 어 Programmer 가 쉽게 접근할 수 있다.
3
/11 1.2 CUDA 에서 Thread Hierarchy 2 Thread 는 Function 을 실행하는 기본 단 위이다. CUDA 에서는, function 을 몇 개 의 Thread 가 실행되게 할 것인지 정할 수 있다. Thread 의 수는 Block 과 Grid 의 사이즈 를 정함으로써 정할 수 있다. Thread 는 Block 내에 속해 있고, Block 은 Grid 에 속해 있다. 각 Block 과 Grid 는 최소 1 차원에서 최 대 4 차원까지의 Dimension 을 가질 수 있다. Block 과 Grid 의 dimension 은 dim3 type 변수를 이용해 정의할 수 있다. Thread 는 Function 을 실행하는 기본 단 위이다. CUDA 에서는, function 을 몇 개 의 Thread 가 실행되게 할 것인지 정할 수 있다. Thread 의 수는 Block 과 Grid 의 사이즈 를 정함으로써 정할 수 있다. Thread 는 Block 내에 속해 있고, Block 은 Grid 에 속해 있다. 각 Block 과 Grid 는 최소 1 차원에서 최 대 4 차원까지의 Dimension 을 가질 수 있다. Block 과 Grid 의 dimension 은 dim3 type 변수를 이용해 정의할 수 있다.
4
/11 1.2 CUDA 에서 Thread Hierarchy – programming example 3 실제로 Programming 을 할 때 Thread 의 수를 정하는 것을 예제 코드로 보여주고 있다. 아래의 코드는 wgrd*hgrd 사이즈 Grid, wblk*hblk 사이즈 Block 만큼의 Thread 가 func 를 동시에 실 행하게끔 하는 코드이다. 규칙은 함수명 >> ( 파라메터 ); 이다. 실제로 Programming 을 할 때 Thread 의 수를 정하는 것을 예제 코드로 보여주고 있다. 아래의 코드는 wgrd*hgrd 사이즈 Grid, wblk*hblk 사이즈 Block 만큼의 Thread 가 func 를 동시에 실 행하게끔 하는 코드이다. 규칙은 함수명 >> ( 파라메터 ); 이다.
5
/11 1.3 CUDA 에서의 Function declaration(qualifier) 4 Function 을 declaration 할 때는 function 의 return type 앞에 __xxx__ 가 붙게 된다. __xxx__ 를 이용해 function 이 실행되는 장치를 결정 내릴 수 있다. __device__, __host__, __global__ 이렇게 세 가지가 있다. Function 을 declaration 할 때는 function 의 return type 앞에 __xxx__ 가 붙게 된다. __xxx__ 를 이용해 function 이 실행되는 장치를 결정 내릴 수 있다. __device__, __host__, __global__ 이렇게 세 가지가 있다. __device__ 장치내에서 실행되는 함수임을 의미한다. 또한, 이 함수는 장치내에서 실행되는 함수 안에서만 실 행될 수 있다. __global__ 역시 장치내에서 실행되는 함수이다. 그러나 이 함수는 host 에서 실행되는 함수에서만 불려질 수 있다. __host__ host 에서 실행되는 함수이며, host 에서 실행되는 함수에 의해서만 불려질 수 있다
6
/11 1.3 CUDA 에서의 Function declaration(qualifier) 5 Qualifier 에는 몇 가지 제한 사항이 있는데 정리하면 다음과 같다. __device__ 와 __global__ 은 재귀함수형식으로 사용될 수 없다. 또한, static variable 을 함수 내에 선언 할 수 없다. __global__ 함수는 void return type 를 가져야 한다. Qualifier 에는 몇 가지 제한 사항이 있는데 정리하면 다음과 같다. __device__ 와 __global__ 은 재귀함수형식으로 사용될 수 없다. 또한, static variable 을 함수 내에 선언 할 수 없다. __global__ 함수는 void return type 를 가져야 한다.
7
/11 1.4 CUDA 에서의 Variable qualifier 6 Variable 에도 Qualifier 를 붙일 수 있다. Qualifier 를 이용해 Variable 의 저장 위치를 정의할 수 있다. Qualifier 에는 __device__, __constant__, __shared__ 이렇게 세 가지가 있다. Variable 에도 Qualifier 를 붙일 수 있다. Qualifier 를 이용해 Variable 의 저장 위치를 정의할 수 있다. Qualifier 에는 __device__, __constant__, __shared__ 이렇게 세 가지가 있다. __device__ global memory 에 저장되고, 프로그램이 살아있는 동안 지속되며, Grid 내의 모든 Thread 와 Host 에 서 접근이 가능하다. __device__ constant memory 에 저장된다. 그 외의 성격은 __device__ 와 같다 __device__ Thread 가 속한 Block 내의 shared memory 에 저장된다. Block 이 소멸됨과 동시에 변수도 소멸된다. Block 내의 모든 Thread 가 참조 할 수 있다.
8
/11 1.5 CUDA 에서의 Memory Hierarchy 7 CUDA 에서의 Memory hierarchy 는 왼쪽 그 림과 같다. Variable 을 선언할 때 variable 을 어느 memory 에 할당시키느냐에 따라 program 수행 속도가 차이가 나므로, 때에 따라 적 절한 memory 를 사용해야 한다. CUDA 에서의 Memory hierarchy 는 왼쪽 그 림과 같다. Variable 을 선언할 때 variable 을 어느 memory 에 할당시키느냐에 따라 program 수행 속도가 차이가 나므로, 때에 따라 적 절한 memory 를 사용해야 한다.
9
/11 1.6 CUDA 에서 Programming flow 8 1. CUDA 를 사용할 Device 를 초기화 시킨다.(Optional) 2. device 에서 사용할 포인터를 생성 3. cudaMalloc 을 이용해 장치내에 메모리를 잡는다. 4. host 에서 사용할 포인터를 생성 5. device 에서 필요한 값이 있으면, cudaMemcpy(d_p, h_p, size, cudaMemcpyHostToDevice); 6. device 에서 실행될 함수를 실행시켜 d_p 에 값을 채워넣음. 7. cudaMemcpy(h_p, d_p, size, cudaMemcpyDeviceToHost); 함수를 통해 device memory 에서 host memory 로 값을 받아옴. 1. CUDA 를 사용할 Device 를 초기화 시킨다.(Optional) 2. device 에서 사용할 포인터를 생성 3. cudaMalloc 을 이용해 장치내에 메모리를 잡는다. 4. host 에서 사용할 포인터를 생성 5. device 에서 필요한 값이 있으면, cudaMemcpy(d_p, h_p, size, cudaMemcpyHostToDevice); 6. device 에서 실행될 함수를 실행시켜 d_p 에 값을 채워넣음. 7. cudaMemcpy(h_p, d_p, size, cudaMemcpyDeviceToHost); 함수를 통해 device memory 에서 host memory 로 값을 받아옴.
10
/11 2.1 DirectX 3D 에 대해서 9 DirectX 3D 는 Microsoft 에서 만든 Graphic card device 를 제어할 수 있는 API 모음이다. 요즘은 Graphic Card 제조사도 다양하고, Chip 의 수도 다양하기 때문에, programmer 가 직접 device 를 제어하는 것은 사실상 불가능에 가깝기 때문에, DirectX 를 사용하면 효과적이다. Application 과 Device 사이에는 Direct3D 와 HAL 이 존재해 Application 과 Device 를 연결해 준다. HAL 은 Direct3D 조차 무수한 device 를 직접 control 하는 것은 불가능하기 때문에, HAL(Hardware Abstraction Layer) 가 존재해 Direct3D 와 Device 를 연계 시켜준다. 또한, 최신버전인 DirectX 10 보다 자료의 양이 더 많은 DirectX 9.0C 를 이용했다. DirectX 3D 는 Microsoft 에서 만든 Graphic card device 를 제어할 수 있는 API 모음이다. 요즘은 Graphic Card 제조사도 다양하고, Chip 의 수도 다양하기 때문에, programmer 가 직접 device 를 제어하는 것은 사실상 불가능에 가깝기 때문에, DirectX 를 사용하면 효과적이다. Application 과 Device 사이에는 Direct3D 와 HAL 이 존재해 Application 과 Device 를 연결해 준다. HAL 은 Direct3D 조차 무수한 device 를 직접 control 하는 것은 불가능하기 때문에, HAL(Hardware Abstraction Layer) 가 존재해 Direct3D 와 Device 를 연계 시켜준다. 또한, 최신버전인 DirectX 10 보다 자료의 양이 더 많은 DirectX 9.0C 를 이용했다.
11
/11 2.2 Direct3D 초기화 10 Direct3D 를 사용하려면 먼저 장치를 초기화 해야한다. 1.IDirect3D9 인터페이스의 포인터를 얻는다. 2. 하드웨어 별로 지원 가능한 기능에 차이가 있기 때문에, 장치특성 (D3DCAPS9) 을 확인한 다. 3.IDirect3Ddevice9 인스턴스의 특성을 지정하기 위해 D3DPRESENT_PARAMETERS 구 조체 인스턴스를 초기화 한다. 4. 하드웨어 장치를 나타내는 C++ 객체인 IDirect3DDevice9 객체를 만든다. 1.IDirect3D9 인터페이스의 포인터를 얻는다. 2. 하드웨어 별로 지원 가능한 기능에 차이가 있기 때문에, 장치특성 (D3DCAPS9) 을 확인한 다. 3.IDirect3Ddevice9 인스턴스의 특성을 지정하기 위해 D3DPRESENT_PARAMETERS 구 조체 인스턴스를 초기화 한다. 4. 하드웨어 장치를 나타내는 C++ 객체인 IDirect3DDevice9 객체를 만든다.
12
/11 2.3 Framework 11 Direct3D 를 사용하면 거의 모든 프로그램이 같은 작업을 계속 해야 하므로, 이를 매번 코딩하는 것 은 상당히 소모적인 작업이다. 따라서, Framework 를 만들어 두면, 매 번 programming 할 때, 수고를 덜어 줄 수 있다. d3dUtility.cpp/.h 에 각종 초기화 작업을 배치한다. Main.cpp 에선 vertex 등을 생성하고, display 하는 함수와, WinMain 함수를 둔다. Framework 은 Framework.zip 으로 압축해 두었다. Direct3D 를 사용하면 거의 모든 프로그램이 같은 작업을 계속 해야 하므로, 이를 매번 코딩하는 것 은 상당히 소모적인 작업이다. 따라서, Framework 를 만들어 두면, 매 번 programming 할 때, 수고를 덜어 줄 수 있다. d3dUtility.cpp/.h 에 각종 초기화 작업을 배치한다. Main.cpp 에선 vertex 등을 생성하고, display 하는 함수와, WinMain 함수를 둔다. Framework 은 Framework.zip 으로 압축해 두었다.
13
/11 2.4 Vertex 12 Direct3D 에서는 모든 Model 을 작은 삼각형 mesh 의 집합으로 표시한다. 이 때, mesh 의 꼭지점을 Vertex 라고 한다. Direct3D 에서 Vertex 를 표현할 때, FVF(Flexible Vertex Format) 로 표현하게 된다. 즉, Vertex 의 구 성 성분을 직접 정의 할 수 있다. Vertex 는 structure 로 구성성분을 정의 내릴 수 있다. 아래 예제 코드는 vertex 의 구성성분으로 공 간 좌표와 색으로 정의 되고 있다. Direct3D 에서는 모든 Model 을 작은 삼각형 mesh 의 집합으로 표시한다. 이 때, mesh 의 꼭지점을 Vertex 라고 한다. Direct3D 에서 Vertex 를 표현할 때, FVF(Flexible Vertex Format) 로 표현하게 된다. 즉, Vertex 의 구 성 성분을 직접 정의 할 수 있다. Vertex 는 structure 로 구성성분을 정의 내릴 수 있다. 아래 예제 코드는 vertex 의 구성성분으로 공 간 좌표와 색으로 정의 되고 있다.
14
/11 2.5 Index 13 아래의 그림 처럼 D3D 에서 사각형을 만드려면, 삼각형 mesh 두 개가 필요하다. 이때 필요한 vertex 의 수는 각 삼각형 당 3 개씩이므로, 총 6 개가 필요하지만, 그림에서처럼 V0 와 V2 는 서로 겹쳐지므로, 총 필요한 Vertex 의 수는 4 개이다. 따라서, 중복되는 Vertex 2 개를 더 생성함으로써 메모리를 낭비하지 않기 위해, Index 를 사용한다. 즉, Index 는 Mesh 에 사용될 vertex 의 list 라고 볼 수 있다. Ex) Vertex vertexList[4] = {v0, v1, v2, v3}; WORD indexList[6] = {0, 1, 2, // 좌측 삼각형 0, 2, 3}; // 우측 삼각형 이렇게 하게 되면, Vertex 에 비해 WORD 는 크기가 작으므로, Memory 를 아낄 수 있다. 아래의 그림 처럼 D3D 에서 사각형을 만드려면, 삼각형 mesh 두 개가 필요하다. 이때 필요한 vertex 의 수는 각 삼각형 당 3 개씩이므로, 총 6 개가 필요하지만, 그림에서처럼 V0 와 V2 는 서로 겹쳐지므로, 총 필요한 Vertex 의 수는 4 개이다. 따라서, 중복되는 Vertex 2 개를 더 생성함으로써 메모리를 낭비하지 않기 위해, Index 를 사용한다. 즉, Index 는 Mesh 에 사용될 vertex 의 list 라고 볼 수 있다. Ex) Vertex vertexList[4] = {v0, v1, v2, v3}; WORD indexList[6] = {0, 1, 2, // 좌측 삼각형 0, 2, 3}; // 우측 삼각형 이렇게 하게 되면, Vertex 에 비해 WORD 는 크기가 작으므로, Memory 를 아낄 수 있다.
15
/11 2.6 가상 카메라 14 D3D 에서 Mesh 를 이용해 Model 을 여러 개 생성하면, 실제로 보여질 수 있는 model 이 있는가 하면, 없는 model 도 있다. 가상 카메라는 눈으로 보는 시점을 정의 내리며, 가상 카메라의 시야에 들어오지 않은 model 은 이 후 과정에서 처리되지 않는다. 가상 카메라는 사각뿔 모양으로 만들어지며, 수평, 수직 시야각과 투영윈도우, 가까운 평면, 먼 평 면으로 이루어 진다. D3D 에서 Mesh 를 이용해 Model 을 여러 개 생성하면, 실제로 보여질 수 있는 model 이 있는가 하면, 없는 model 도 있다. 가상 카메라는 눈으로 보는 시점을 정의 내리며, 가상 카메라의 시야에 들어오지 않은 model 은 이 후 과정에서 처리되지 않는다. 가상 카메라는 사각뿔 모양으로 만들어지며, 수평, 수직 시야각과 투영윈도우, 가까운 평면, 먼 평 면으로 이루어 진다.
16
/11 2.7 Rendering Pipeline 15 D3D 에서 Vertex list 를 가지고 화면에 출력하는 과정은 아래와 같다. 아래와 같은 과정을 Rendering Pipeline 이라고 한다. 로컬 스페이스 -> 월드 스페이스 -> 뷰 스페이스 -> 후면 추려내기 -> 조명 -> 클리핑 -> 투영 -> 뷰포트 -> 래스터라이즈
17
/11 2.7.1 로컬스페이스 16 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 로컬스페이스는 각 model 을 그리기 위한 스페이스이다. 우선 다른 model 들과의 상관관계를 고려하지 않고 자체의 좌표시 스템을 이용해 modeling 하는 공간이므로, 쉽고 단순하게 modeling 이 가능하다. 로컬스페이스는 각 model 을 그리기 위한 스페이스이다. 우선 다른 model 들과의 상관관계를 고려하지 않고 자체의 좌표시 스템을 이용해 modeling 하는 공간이므로, 쉽고 단순하게 modeling 이 가능하다.
18
/11 2.7.2 월드스페이스 17 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 월드스페이스는 여러 개의 model 들이 그려지는 공간이다. 로컬스페이스에서 modeling 된 model 들이 world space 에서 scene 을 이루게 된다. Local space 에서 world space 로 변환될 때는 각 model 의 크기와 위 치, 방위각등이 결정된다. World space 로의 변환은 하나의 model 을 변환할 때마다 각 model 의 상태를 결정해 줘야 하므로, model 당 한 번의 world space 변환을 하게 된다. 아래는 예제코드 ( 위치만 정의내림 ) 월드변환을 한 번만 실행시키면, 동일 위치에 model 이 그려지게 된 다. 월드스페이스는 여러 개의 model 들이 그려지는 공간이다. 로컬스페이스에서 modeling 된 model 들이 world space 에서 scene 을 이루게 된다. Local space 에서 world space 로 변환될 때는 각 model 의 크기와 위 치, 방위각등이 결정된다. World space 로의 변환은 하나의 model 을 변환할 때마다 각 model 의 상태를 결정해 줘야 하므로, model 당 한 번의 world space 변환을 하게 된다. 아래는 예제코드 ( 위치만 정의내림 ) 월드변환을 한 번만 실행시키면, 동일 위치에 model 이 그려지게 된 다.
19
/11 2.7.3 뷰스페이스 18 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 World Space 로 변환하고 나면, 물체의 위치등이 결정되고, 이 때 카 메라의 위치도 결정이 된다. 그러나 카메라의 위치가 임의의 좌표에 ( 원하는 위치더라도 ) 있다면 연산을 할 때 수월하지 않기 때문에, 카메라의 위치를 좌표계의 원 점에 위치시킬 필요가 있다. 이러한 과정을 뷰스페이스 변환이라고 하고, 카메라의 위치가 원점에 위치하고 방향을 +z 축을 향하게 둔 공간을 view space 라고 한다. 이렇게 view space 변환을 하게 되면, 카메라의 위치와 함께 모든 위 치가 같이 변해서, 결국 카메라로 보는 물체의 위치와 크기 방위각 등은 일정하게 된다. 아래는 view space 변환을 행할 행렬을 얻기 위 한 함수를 나타내며, 카메라의 위치와 보는 지점은 현재 위치와 보 는 지점이 된다. 위와 같은 함수를 통해 행렬을 얻으면 다음과 같은 함수를 통해 view space 변환을 실행할 수 있다. World Space 로 변환하고 나면, 물체의 위치등이 결정되고, 이 때 카 메라의 위치도 결정이 된다. 그러나 카메라의 위치가 임의의 좌표에 ( 원하는 위치더라도 ) 있다면 연산을 할 때 수월하지 않기 때문에, 카메라의 위치를 좌표계의 원 점에 위치시킬 필요가 있다. 이러한 과정을 뷰스페이스 변환이라고 하고, 카메라의 위치가 원점에 위치하고 방향을 +z 축을 향하게 둔 공간을 view space 라고 한다. 이렇게 view space 변환을 하게 되면, 카메라의 위치와 함께 모든 위 치가 같이 변해서, 결국 카메라로 보는 물체의 위치와 크기 방위각 등은 일정하게 된다. 아래는 view space 변환을 행할 행렬을 얻기 위 한 함수를 나타내며, 카메라의 위치와 보는 지점은 현재 위치와 보 는 지점이 된다. 위와 같은 함수를 통해 행렬을 얻으면 다음과 같은 함수를 통해 view space 변환을 실행할 수 있다.
20
/11 2.7.4 후면추려내기, 조명, 클리핑 19 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 후면 추려내기란, 관찰점에서 앞면에 의해 가려진 뒷면을 이후 처리 과정에서 처리하지 않는 작업을 나타낸다. 이는 D3D 에 의해 자동으 로 처리되는 과정이다. 후면 추려내기에서 앞면은 view space 에서 시계방향으로 vertex 를 가진 polygon 을 앞면으로 취급하게 된다. 조명 역시 카메라처럼 원하는 위치의 월드스페이스 내에 정의 내릴 수 있으며, view space 변환 시 카메라와 마찬가지로 이동하게 된다. 클리핑은 카메라의 시점에 포함되지 않는 물체들을 추려내는 과정 을 말하며, 이 역시 D3D 에서 자동으로 처리된다. 후면 추려내기란, 관찰점에서 앞면에 의해 가려진 뒷면을 이후 처리 과정에서 처리하지 않는 작업을 나타낸다. 이는 D3D 에 의해 자동으 로 처리되는 과정이다. 후면 추려내기에서 앞면은 view space 에서 시계방향으로 vertex 를 가진 polygon 을 앞면으로 취급하게 된다. 조명 역시 카메라처럼 원하는 위치의 월드스페이스 내에 정의 내릴 수 있으며, view space 변환 시 카메라와 마찬가지로 이동하게 된다. 클리핑은 카메라의 시점에 포함되지 않는 물체들을 추려내는 과정 을 말하며, 이 역시 D3D 에서 자동으로 처리된다.
21
/11 2.7.5 투영 20 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 이 과정 까지 거치면, 컴퓨터의 시스템 내에서 3D 물체와 카메라, 조 명들이 모두다 결정이 됐다. 그러나 컴퓨터의 모니터는 2D 그래픽 을 표시하기 때문에, 3D 물체를 카메라의 시점에서 2D 그래픽화 하 는 과정이 남아 있으며, 이러한 과정을 투영이라고 한다. 투영은 원근 투영 (perspective projection) 을 이용하므로, 카메라의 정의에서 먼 평면에 있는 물체가 가장 작고, 가까운 평면에 있는 물 체가 가장 크게 그려지게 된다. 화면은 투영 윈도우에 맺히게 되는데, 앞서 view space 에서 카메라 를 +z 를 향하게 했으므로, 투영 윈도우는 +z 평면이고 z 의 값은 1 이 된다. 따라서 view space 에서 z < 1 인 model 은 나타나지 않는다. 아래는 투영 행렬을 만들고, 투영시키는 과정을 나타내는 코드를 나 타냈다. 이 과정 까지 거치면, 컴퓨터의 시스템 내에서 3D 물체와 카메라, 조 명들이 모두다 결정이 됐다. 그러나 컴퓨터의 모니터는 2D 그래픽 을 표시하기 때문에, 3D 물체를 카메라의 시점에서 2D 그래픽화 하 는 과정이 남아 있으며, 이러한 과정을 투영이라고 한다. 투영은 원근 투영 (perspective projection) 을 이용하므로, 카메라의 정의에서 먼 평면에 있는 물체가 가장 작고, 가까운 평면에 있는 물 체가 가장 크게 그려지게 된다. 화면은 투영 윈도우에 맺히게 되는데, 앞서 view space 에서 카메라 를 +z 를 향하게 했으므로, 투영 윈도우는 +z 평면이고 z 의 값은 1 이 된다. 따라서 view space 에서 z < 1 인 model 은 나타나지 않는다. 아래는 투영 행렬을 만들고, 투영시키는 과정을 나타내는 코드를 나 타냈다.
22
/11 2.7.6 Viewport 변환, 래스터라이즈 21 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 로컬스페이스 월드스페이스 뷰스페이스 후면추려내기 조명 클리핑 투영 뷰포트 래스터라이즈 Viewport 변환은 실제 display 될 화면의 영역을 지정하는 과정이다. Windows application 의 경우 windows mode 에서 display 를 하게 될 경우 client 영역에서만 화면이 그려질 수 있고, 원하는 경우에는 client 영역에서도 작은 사각형 영역에만 그릴 수도 있다. 이러한 경 우에 필요한 과정이 viewport 변환이며, 전체화면 display 에 경우 이 과정은 생략할 수 있다. 이전까지의 과정에선 polygon 의 색이 결정돼 있지 않지만, 래스터 라이즈 과정을 거치면서 비로서 각 mesh 의 색이 결정되게 된다. 여기까지의 과정이 모두 완료되면, 비로서 화면에 display 가 된다. Viewport 변환은 실제 display 될 화면의 영역을 지정하는 과정이다. Windows application 의 경우 windows mode 에서 display 를 하게 될 경우 client 영역에서만 화면이 그려질 수 있고, 원하는 경우에는 client 영역에서도 작은 사각형 영역에만 그릴 수도 있다. 이러한 경 우에 필요한 과정이 viewport 변환이며, 전체화면 display 에 경우 이 과정은 생략할 수 있다. 이전까지의 과정에선 polygon 의 색이 결정돼 있지 않지만, 래스터 라이즈 과정을 거치면서 비로서 각 mesh 의 색이 결정되게 된다. 여기까지의 과정이 모두 완료되면, 비로서 화면에 display 가 된다.
23
/11 2.8 Vertex Buffer 와 Index Buffer 22 앞서 vertex 와 index 에 대해서 배웠다. 그러나 이 들을 array 로 저장하게 되면, system memory 에 저장되므로, rendering 에 시간지연이 생기므로, 이를 buffer 에 저장해 device memory 에 저장하게 된다. 좌측의 코드는 VertexBuffer 와 IndexBuffer 를 만 드는 함수이다. Length – 버퍼에 할당할 바이트 수 Usage – 버퍼가 이용되는 방법을 결정한다. 보통 0 을 지정 FVF – Vertex 의 Format Pool – 버퍼가 위치할 메모리 풀 ppVertexBuffer - - 만들어질 Vertex Buffer 를 받을 포인터 pSharedHandle – 이용되지 않음. 0 으로 지정 Format – 인덱스의 크기를 지정 D3DFMT_INDEX16 또는 D3DFMT_INDEX32 를 이용하는데 장치의 지원 여부에 따라 결 정 ppIndexBuffer – 만들어질 index buffer 를 받을 포인터 앞서 vertex 와 index 에 대해서 배웠다. 그러나 이 들을 array 로 저장하게 되면, system memory 에 저장되므로, rendering 에 시간지연이 생기므로, 이를 buffer 에 저장해 device memory 에 저장하게 된다. 좌측의 코드는 VertexBuffer 와 IndexBuffer 를 만 드는 함수이다. Length – 버퍼에 할당할 바이트 수 Usage – 버퍼가 이용되는 방법을 결정한다. 보통 0 을 지정 FVF – Vertex 의 Format Pool – 버퍼가 위치할 메모리 풀 ppVertexBuffer - - 만들어질 Vertex Buffer 를 받을 포인터 pSharedHandle – 이용되지 않음. 0 으로 지정 Format – 인덱스의 크기를 지정 D3DFMT_INDEX16 또는 D3DFMT_INDEX32 를 이용하는데 장치의 지원 여부에 따라 결 정 ppIndexBuffer – 만들어질 index buffer 를 받을 포인터
24
/11 2.9 버퍼 메모리에 접근 23 만들어진 buffer 에 접근하기 위해서는 Lock 함수를 사용해서 buffer 를 잠궈야 하고, 접근 후에는 반 드시 Unlock 을 시켜야 한다. IndexBuffer 도 사용법이 비슷하므로, VertexBuffer 에 대해서만 정리하 겠다. Lock 을 수행한 후에는, ppbData 를 이용해 vertex 의 값을 쓰면 된다. 만들어진 buffer 에 접근하기 위해서는 Lock 함수를 사용해서 buffer 를 잠궈야 하고, 접근 후에는 반 드시 Unlock 을 시켜야 한다. IndexBuffer 도 사용법이 비슷하므로, VertexBuffer 에 대해서만 정리하 겠다. Lock 을 수행한 후에는, ppbData 를 이용해 vertex 의 값을 쓰면 된다.
25
/11 2.10 드로잉 준비 24 우선 Stream source 를 지정해야 한다. Stream Source 를 Vertex Buffer 와 연결하여 rendering pipeline 에 buffer 를 보낼 수 있게 하는 작업이다. 그 다음 Vertex 의 Format 을 지정해야 한다. 앞서 vertex 는 FVF 이므로, 프로그래머가 정의하기에 따라 vertex 의 format 이 달라지므로, device 에 format 을 알려줘야 한다. 그 다음 index buffer 를 지정해야 한다. 이로써 모든 준비과정이 완료됐다. 우선 Stream source 를 지정해야 한다. Stream Source 를 Vertex Buffer 와 연결하여 rendering pipeline 에 buffer 를 보낼 수 있게 하는 작업이다. 그 다음 Vertex 의 Format 을 지정해야 한다. 앞서 vertex 는 FVF 이므로, 프로그래머가 정의하기에 따라 vertex 의 format 이 달라지므로, device 에 format 을 알려줘야 한다. 그 다음 index buffer 를 지정해야 한다. 이로써 모든 준비과정이 완료됐다.
26
/11 2.11 드로잉 25 드로잉을 시작할 때는 device 에 장면의 시작을 알려야 하고, 마친 후에는 장면의 끝을 알려줘야 한 다. 앞서 정의한 Index 를 이용해 그리는 함수 드로잉을 시작할 때는 device 에 장면의 시작을 알려야 하고, 마친 후에는 장면의 끝을 알려줘야 한 다. 앞서 정의한 Index 를 이용해 그리는 함수
27
/11 2.6 프로그램 구조 26 전역 변수로 IDirect3DDevice9*, IDirect3DVertexBuffer9*, IDirect3DIndexBuffer9*, int Width, int Height 를 선언한다. Vertex 의 구조체를 정의한다. Setup 함수에서는 Vertex buffer 와 Index buffer 를 생성하고, buffer 내에 vertex 와 index 정보를 채워 넣는다. 그리고, 카메라의 위치와 방향을 정하고, 투영행렬을 지정한다. Display 함수에서는 그림을 출력시키고, 필요하다면 물체의 회전 등을 월드변환 또는 뷰스페이스 변환을 통해 미리 변환시킨다. 마지막으로 Cleanup 함수에서는 ib 와 vb 를 해제시킨다. Ex> d3d::Release ( 버퍼 ); 전역 변수로 IDirect3DDevice9*, IDirect3DVertexBuffer9*, IDirect3DIndexBuffer9*, int Width, int Height 를 선언한다. Vertex 의 구조체를 정의한다. Setup 함수에서는 Vertex buffer 와 Index buffer 를 생성하고, buffer 내에 vertex 와 index 정보를 채워 넣는다. 그리고, 카메라의 위치와 방향을 정하고, 투영행렬을 지정한다. Display 함수에서는 그림을 출력시키고, 필요하다면 물체의 회전 등을 월드변환 또는 뷰스페이스 변환을 통해 미리 변환시킨다. 마지막으로 Cleanup 함수에서는 ib 와 vb 를 해제시킨다. Ex> d3d::Release ( 버퍼 );
Similar presentations