440 likes | 706 Views
3 차원 기초이론과 D3D 의 최소한의 이해. 멀티미디어 프로젝트 인천대학교 컴퓨터공학과 성미영. 개요. Tut01_CreateDevice: 디바이스 Tut02_Vertices: 정점 Tut03_Matrices: 행렬 Tut04_Lights: 광원 Tut05_Textures: 텍스쳐 Tut06_Meshes: 메시 Tut07_IndexBuffer: 인덱스 버퍼. Win32 프로그램과 D3D 프로그램. RegisterClassEx() 로 윈도우 클래스 등록
E N D
3차원 기초이론과 D3D의 최소한의 이해 멀티미디어 프로젝트 인천대학교 컴퓨터공학과 성미영
개요 • Tut01_CreateDevice: 디바이스 • Tut02_Vertices: 정점 • Tut03_Matrices: 행렬 • Tut04_Lights: 광원 • Tut05_Textures: 텍스쳐 • Tut06_Meshes: 메시 • Tut07_IndexBuffer: 인덱스 버퍼
Win32 프로그램과 D3D 프로그램 • RegisterClassEx()로 윈도우 클래스 등록 • CreateWindow()로 윈도우 생성 • InitD3D()에서 Direct3D 객체 생성 • Render()에서 Direct3D 객체 사용 • ShowWindow(), UpdateWindow()로 윈도우를 화면에 표시 • GetMessage(), TranslateMessage(), DispatchMessage()로 구성된 메시지 루프 수행 • 메시지 루프에서 빠져나올 때 Direct3D 객체 해제 • 프로그램 종료
Direct 3D 프로그래밍의 흐름 • Direct3D 객체 생성 • g_pD3D=Direct3DCreate9() • CreateDevice(…, &g_pd3dDevice) • Direct3D 객체 사용 • g_pd3dDevice->Clear() • g_pd3dDevice->BeginScene() • Rendering 내용 정의 • g_pd3dDevice->EndScene() • g_pd3dDevice->Present() • Direct3D 객체 제거 • g_pd3dDevice->Release(); • g_pD3D->Release();
Tut01_CreateDevice: 디바이스 실행화면 함수 상관도
디바이스 • 화면에 직접 폴리곤을 그리는 역할을 하는 인터페이스 (…) • 사용자 소프트웨어와 비디오 카드 사이의 의사소통 라인을 제공하는 객체 • Direct3D 객체에서 생성되는 비디오 카드 접근 자료구조체 • 프리미티브가 렌더링되는 하나의 서피스(surface) = 프레임 버퍼(frame buffer)로의 연결점이다. 프레임 버퍼는 페이지 플립핑(page flipping; 전체 화면 모드에서 후면 버퍼의 내용을 전면 버퍼로 교환) 또는 블리팅(blitting; 윈도우 모드에서 비디오 데이터들을 비디오 메모리로 복사) 응용의 하나의 백 버퍼가 된다.
InitD3D() • Direct3D를 초기화 하기 위한 함수이다. • Direct3DCreate9()함수를 사용하여 D3D의 객체를 생성하고 인터페이스IDirect3D9를 리턴해준다. • IDirect3D9->CreateDevice()함수를 호출 디바이스를 생성한다. • 이 CreateDevice()함수는 중요한 함수이므로 좀더 자세히 알아보도록 하자.
CreateDevice() • HRESULT CreateDevice( UNIT Adapter, D3DDEVTYPE Device Type, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface ); • Adapter : 디바이스를 생성할 비디오 카드 장치의 순서 번호 • DeviceType : 출력 디바이스의 종류 • hFocusWindow : 디바이스가 출력할 윈도우의 핸들이다. • BehaviorFlags : 하드웨어 가속을 사용할 것인지, 소프트웨어적으로 지원할 것인지를 결정하는 플래그 값 • pPresentationParameters : 앞에서 선언한 구조체의 포인터다. • ppReturndeDeviceInterface : 우리가 얻고자 했던 바로 그 값이다. iDirect3DDevice9 의 인터페이스를 갖고 있는 포인터가 담겨서 돌아온다.
d3dpp(D3DPRESENT_PARAMETERS) 작성 //GetAdapterDisplayMode()함수를 이용하여 DisplayMode정보를 받아옴 D3DDISPLAYMODE d3ddm; pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ); //작성할 구조체를 초기화 D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof(d3dpp) ); //true를 적용하여 윈도우 모드를 선택 d3dpp.Windowed = TRUE; //2차원 표면내용을 1차원표면으로 flip하는 방법을 적용시킴 //가장 효율적인 방법 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; //DisplayMode의 포멧방식을 적용시킨다. d3dpp.BackBufferFormat = d3ddm.Format;
DeviceType & BehaviorFlags • 장치 타입 (DeviceType) • HAL Device (Hardware abstraction layer) • 하드웨어를 이용한 연출 (하드웨어를 가지고 그림) • 렌더링 속도 빠름 • 플래그 : D3DDEVTYPE_HAL 세트 • Reference Device • 하드웨어와 소프트웨어를 이용한 연출 (하드웨어로 부족할 때 소프트웨어로 하드웨어를 emulate) • 렌더링 속도 중간 • 플래그 : D3DDEVTYPE_REF • Pluggable Software Device • 소프트웨어를 이용한 연출 • 렌도링 속도 느림 • 플레그 : D3DDEVTYPE_SW • 정점처리 (BehaviorFlags) • D3DCREATE_HARDWARE_VERTEXPROCESSING • 그래픽카드에서 사용할 수 있는 하드웨어 변환과 조명을 사용한다. • D3DCREATE_SOFTWARE_VERTEXPROCESSING • 소프트웨어 변형과 조명을 사용한다.
Render() • Clear(): 먼저 화면을 깨끗이 지운다. • BeginScene(): 이제부터 폴리곤을 그린다고 D3D에게 알린다. • EndScene(): 폴리곤을 다 그렸다고 D3D에게 알린다. • Present(): 화면에 나타내게 한다.
Render() • Clear() • 첫 번째 인자에 0을 설정하고, • 두 번째 인자에 NULL을 설정 함으로써 rendering target을 덮는 하나의 사각형을 사용한다. • 세 번째 인자는 버퍼(render target, 깊이(Z) 버퍼, 스텐실 버퍼)중 rendering target만을 사용한다. • 나머지 세 개의 인자는 render target, 깊이(Z) 버퍼, 그리고 스텐실 버퍼를 위한 지울 값을 반영하기 위해 설정한다. • 현재 render target만을 사용하였으므로 파란색으로 rendering target을 지웠으며 나머지 값은 무시된다. • BeginScene() • 3D배경에 어떤 폴리곤들을 실제로 출력하기 전에 먼저 BeginScene()함수를 사용해서 3D 랜더링 모드로 진입해야 함 • EndScene() • BeginScene() 함수를 호출하면 반드시 EndScene()함수를 호출해야 한다. 또한 이 작업을 거친 후에 출력된 최종 그래픽은 디바이스에 저장이 된다. • Present() • 렌더링된 장면을 화면에 display하는 작업 • 대부분의 경우에 NULL로 설정되어야만 한다 • 첫 번째 인자는 source 사각형이다. • 두 번째 인자는 destination 사각형이다. 이 단계에 샘플 코드는 이 두 인자에 NULL을 설정함으로써 전체 백버퍼(준비버퍼)를 프론트버퍼(출력버퍼)로 present한다. • 세 번째 인자는 이 presentation을 위한 destination 윈도우를 설정한다. 이 인자가 NULL로 설정되었기 때문에 D3DPRESENT_PARAMETERS 의 hWndDeviceWindow 맴버가 사용된다. • 네 번째 인자는 DirtyRegion 인자이다.
페이지 플리핑 (Page Flipping) • 깜빡임 현상(flickering)을 막기 위해 사용하는 방법이다. • D3D에서 후면 버퍼의 내용을 전면 버퍼로 교환(버퍼 주소들의 교환)하는 방식이다.
Tut02_Vertices: 정점 실행화면 함수 상관도
InitVB() • 정점버퍼를 생성하고 정점 값을 채워 넣는 함수이다. • CreateVertexBuffer()함수를 사용하여 버퍼를 생성한다. • FVF를 지정하여 보관할 데이터 형식을 지정한다. • 생성한 다음 Lock()과 Unlock()으로 포인터를 얻어내 정점 정보를 써넣어야 한다. • Lock()을 수행한 정점 버퍼는 반드시 Unlock()를 호출해야 한다.
CreateVertexBuffer() • HRESULT CreateVertexBuffer( UINT Length, DWORD Length , DWORD Usage, D3DPOOL FVF, IDirect3DvertexBuffer9** ppVertexBuffer ); Length : 생성할 정점 버퍼의 바이트 단위 크기 Usage : 정점 버퍼의 종류 혹은 처리 방식지정 FVF : 정점 정보 구조체에 따라 선언된 FVF 플래그 값 Pool : 정점 버퍼가 저장될 메모리의 위치와 관리 방식 지정 ppVertexBuffer : 반환될 정점 버퍼의 인터페이스
Lock() • HRESULT Lock( UINT OffsetToLock, UINT SizeToLock, BYTE ** ppbData, DWORD Flags ); OffsetToLock : Lock을 할 버퍼의 시작점,SizeToLock 과 함께 양쪽 모두 0이 면 버퍼 전체 SizeToLock : Lock을 할 버퍼의 크기,OffsetToLock 과 함께 양쪽 모두 0이면 버퍼 전체 ppbData : 읽고 쓸 수 있게 된 메모리 영역의 포인터 Flags : Lock을 수행할 때 함께 사용하는 플래그
Flexible Vertex Format, FVF • FVF는 사용자 정의 정점 형식이다. • RHW: 동차 좌표계의 W값, 이 값이 있으면 변환이 완료된 정점 • RGBA: Red, Green, Blue, Alpha
FVF 플래그 값의 용도 • 정점의 좌표 : 정점의 3차원자표를 나타낸다. • RHW : 동차 좌표계의 W값. 이값이 있으면 변환이 완료된 정점이다. • 결합가중치 : 스키닝에 사용된다. • 법선벡터 : 정점의 접선 벡터를 나타낸다. 주로 광원 처리시 사용된다. • 확산광 : RGBA(r,g,b,a) 매크로 값이며, 정점의 확산광 색깔을 나타낸다. • 반사광 : RGBA(r,g,b,a) 매크로 값이며, 정점의 반사광 색깔을 나타낸다. • 텍스처 좌표 : 텍스처 좌표값을 나타낸다. D3D는 8개까지 텍스처를 동시에 겹쳐서 사용할 수 있다. 예를 들어 법선 맵핑을 하려면 첫번째 값을 확산 맵 정보로, 두번째 값을 법선 맵 정보로 설정하여 사용할 수 있다.
Render() • 앞에서 본 예제와 다르게 Render()함수 중 BeginScene()과 EndScene()사이에 정점 버퍼의 내용이 추가된다. 1. SetStreamSource()로 출력할 정점 버퍼를 디바이스에 바인딩한다. 2. SetFVF()로 정점 포맷을 디바이스에 지정한다. 3. DrawPrimitive()로 정점 버퍼의 폴리곤을 그린다.
Render() • DrawPrimitive()함수는 삼각형을 그려주는 함수이다. 첫번째 전달 인자에 의하여 다양한 동작을 한다. D3DPT_LINELIST D3DPT_POINTLIST D3DPT_TRIANGLEUST D3DPT_LINESTRIP
Render() D3DPT_TRIANGLESTRIP D3DPT_TRIANGLEFAN
Tut03_Matrices: 행렬 실행화면 함수 상관도
월드 변환(World Transform) • 2개의 물체를 따로따로 출력하기 위해서는 물체가 사용하는 로컬 좌표계가 아닌 전체 월드 좌표계를 도입해야 한다. • 로컬 좌표계 -> 월드 좌표계 • 모든 물체마다 TM(Transform Matrix)이 존재한다. TM을 적용하여 그린 경우
월드 변환 함수 • SetTransform(D3DTS_WORLD, &matWorld)
카메라 변환(Camera Transform) • 3차원 월드 좌표계를 카메라를 기준으로 한 카메라 좌표계로 변환하는 것을 말한다. 월드 좌표계에서 카메라 좌표계로의 변환
투영 변환(Projection Transform) • 3차원 좌표계를 우리가 실제로 보게 되는 화면의 2차원 좌표계로 변환 하는 것이다. 카메라 좌표계에서 투영 좌표계로의 변환
렌더링 파이프라인(Rendering Pipeline) • 최초의 로컬 좌표계가 최종 좌표계로 변환되는 과정이다. D3D의 렌더링 파이프라인
Tut04_Lights: 광원 실행화면 함수 상관도
광원 • 광원 : 암흑과 같은 3차원 공간에 빛이 들어감으로써 정점이 폴리곤으로 보일 수 있다. • 재질값을 이루는 구성 요소 • 주변광(ambient light): 주변광이란 최적 평균 밝기를 말한다. 똑같은 양으로 모든 면에서 나오는 빛. • 확산광(diffuse): 표면의 모든 점들에 균일하게 비춰지는 빛 • 반사광(specular): 특정한 방향으로만 반사하는 빛. 광원의 위치와 카메라에 위치에 따라서 달라진다. • 방출광(emissive): 메시 표면에서 자체적으로 방출되는 빛. 이 빛이 다른 메시에 영향을 주지는 못한다. • 광원의 종류 • 주변 광원(ambient light): 똑같은 양으로 모든 곳을 비추는 빛이다. • 점 광원(point light): 백열전구와 같은 빛이다. • 방향성 광원(directional light): 하나의 방향을 갖는 태양과 같은 빛이다. • 점적 광원(spot light): 정해진 위치와 범위만 비추는 특수한 조명이다.
광원의 설정 • D3DLIGHT9 구조체에 적당한 값을 넣고 SetLight()함수를 통하여 광원을 설치한 다음 LightEnable()함수를 통하여 광원을 켠다. • D3D로 하여금 광원 연산을 하도록 전체 메인스위치(SetRenderState(D3DRS_LIGHTING, TRUE))를 켜야 한다.
Tut05_Textures: 텍스쳐 실행화면 함수 상관도
텍스쳐 • 텍스쳐 : 3차원 메시에 2차원 이미지를 덧붙여서 좀 더 현실감 있는 장면을 연출해준다. • 텍스쳐의 종류 1차원 2차원 3차원
텍스쳐 좌표계 • 텍스쳐 좌표계 : 텍스쳐를 제어하기 위한 텍스쳐만의 전용 좌표계 1차원 2차원 3차원
정점, nomal, 텍스쳐 좌표 입력방법 • 정점은 일반 X축과 Y축을 중심으로 뒤쪽이 Z의 증가이며 앞쪽이 Z의 감소이다 • normal은 점의 normal벡터로서 삼각형의 수직인 방향을 나타낸다. 앞의 코드는 정면을 바라보고 있으므로 Z축의 음(-)의 방향이 normal벡터이다 • 텍스쳐 좌표는 사각형을 그렸을 경우 다음과 같다 • 텍스쳐 좌표를 다음과 같이 하였을 경우 네 개의 그림이 매핑된다. 0, 0 1, 0 0, 1 1, 1 0, 0 2, 0 0, 2 2, 2
텍스쳐 사용 1. IDirect3DTexture9 인터페이스 선언 2. 텍스쳐 좌표를 갖는 정점 선언 3. 텍스쳐 생성 4. 텍스쳐 스테이지 설정 5. 그려질 텍스쳐 지정 6. 메시 그리기
Tut06_Meshes: 메시 실행화면 함수 상관도
메시 • X파일은 DirectX에서 지원하는 기본적은 3차원 메시 파일 포맷이다. • 실제로 게임을 제작할 때는 프로그래머는 디자이너들이 제작한 3차원 메시파일을 읽어들여 출력해야 한다. • X파일 추출기를 이용하여 메시값을 추출해낸다. • 추출된 X파일은 IDirect3DXMesh를 통해서 완벽하게 제어가 가능하다. • D3DXLoadMeshFromX()함수를 사용한다.
인덱스 버퍼 • 인덱스 버퍼란 정점의 인덱스를 보관하기 위한 전용 버퍼를 말한다. • 메모리 소모량이 적고 캐시를 이용해 높은 효율을 낼 수 있다. • 캐시를 통한 최적화는 인덱스 버퍼를 사용할 때만 가능한 것으로 통상 출력 속도가 두 배 정도 빨라진다. • 인덱스 버퍼는 IDirect3DIndexBuffer9인터페이스를 사용한다. • SetFVF()함수로 정점 버퍼의 정보를 D3D에 전달한다. • SetStreamSource()함수로 정점 버퍼사용할 준비를 한다. • SetIndices()함수를 사용하여 인덱스 버퍼를 사용할 준비를한다. • 기존에 사용했던 DrawPrimitive()함수가 아닌 DrwaIndexedPrimitive()함수를 사용하여 정점 버퍼 + 인덱스 버퍼로 폴리곤을 출력한다.