제6장 텍스처링 2010-1학기 컴퓨터게임(DirectX)
텍스처링 텍스처 매핑은 이미지 데이터를 삼각형에 입힐 수 있게 하는 테크닉 장면의 세밀함과 사실감을 극적으로 높여줌 IDirect3DTexture9 인터페이스로 텍스처 표현 내용 삼각형에 입혀질 텍스처의 일부를 지정하는 방법 텍스처를 만드는 방법 부드러운 이미지를 만들기 위해 텍스처에 필터링을 적용하는 방법 2010-1학기 컴퓨터게임(DirectX)
텍스처 좌표 Direct3D는 수평으로 진행하는 u-축과 수직으로 진행하는 v-축으로 구성된 텍스처 좌표 시스템을 이용. u ,v좌표 시스템은 텍셀이라 불리우는 텍스쳐의 요소를 표현하는데 사용되며, v-축은 아래쪽이 양의 방향임 좌표 간격이 [0,1]로 정규화 되어 있다. 2010-1학기 컴퓨터게임(DirectX)
텍스처상의 삼각형 영역 정의 3D 삼각형에 대해서 텍스처 상의 매핑될 삼각형 영역을 정의해야 한다. 이 과정을 위해서는 다시 버텍스 구조체를 수정하고 텍스처 위의 버텍스를 정의하는 텍스처 좌표 쌍을 추가해야 함 struct Vertex { Vertex(){} Vertex( float x, float y, float z, float nx, float ny, float nz, float u, float v) _x = x; _y = y; _z = z; _nx = nx; _ny = ny; _nz = nz; _u = u; _v = v; } 2010-1학기 컴퓨터게임(DirectX)
float _u, _v; // texture coordinates static const DWORD FVF; }; float _x, _y, _z; float _nx, _ny, _nz; float _u, _v; // texture coordinates static const DWORD FVF; }; const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; 버텍스 포맷 기술에 D3DFVF_TEX1을 추가하여 버텍스 구조체에 한 쌍의 텍스처 좌표가 포함되어 있음을 지정하였음 이 세 개의 버텍스 객체로 만들어지는 삼각형들은 텍스처 좌표에서의 텍스처 삼각형으로도 정의됨 2010-1학기 컴퓨터게임(DirectX)
텍스처의 작성과 활성화 텍스처 데이터는 일반적으로 디스크에 보관된 이미지 파일에서 읽혀져 IDirect3DTexture9 객체로 로드됨. 이 작업을 위해서 D3DXCreateTextureFromFile 함수가 사용됨 HRESULT D3DXCreateTextureFromFile( LPDIRECT3DDEVICE9 pDevice, //텍스처를 만들어낼 장치 LPCSTR pSrcFile, // 이미지를 읽어들일 파일명 LPDIRECT3DTEXTURE9* ppTexture // 만들어진 텍스처를 받을 포인터 ); 이 함수는 BMP, DDS, DIB, JPG, PNG, TGA 등의 이미지 파일 포맷을 읽어들일 수 있음 2010-1학기 컴퓨터게임(DirectX)
예를 들어, STONEWALL.BMP라는 파일에서 텍스처를 만들고자 한다면 다음과 같이 코드를 작성한다. IDirect3Dtexture9* _stonewall; D3DXCreateTextureFromFile(_device,”stonewall.bmp”, &_stonewall); 현재 텍스처를 지정하는 데는 다음과 같은 메서드를 이용 HRESULT IDirect3DDevice9::SetTexture( DWORD Stage, //0-7 범위의 값으로 텍스처를 지정 //stage – 멀티텍스처링. 0은 사용안함. IDirect3DBaseTexture9* pTexture //지정할 텍스처의 포인터 ); 예 Device->SetTexture(0, _stonewall); 2010-1학기 컴퓨터게임(DirectX)
특정한 텍스처링 상태에 텍스처를 이용하지 않고자 한다면 pTexture를 0으로 지정함 예를 들어 물체에 텍스처를 입히지 않고자 한다면 다음과 같은 코드를 이용 Device->SetTexture(0,0); renderObjectWithoutTexture(); 만약 장면 내에 서로 다른 텍스처를 이용하는 삼각형이 있다면 다음과 비슷한 코드 구조를 이용 Device->SetTexture(0, _tex0); drawTrisUsingTex0(); Device->SetTexture(0, _tex1); drawTrisUsingTex1(); 2010-1학기 컴퓨터게임(DirectX)
필터 텍스처는 스크린 스페이스에서 삼각형에 입혀진다. 일반적으로 텍스처 삼각형과 스크린 삼각형의 크기는 서로 다르므로, 텍스처 삼각형이 스크린 삼각형보다 작은 경우에는 텍스처 삼각형을 확대하여 크기를 맞추고, 텍스처 삼각형이 더 큰 경우에는 텍스처 삼각형을 축소함 위의 두 가지 경우에 모두 얼마간의 왜곡이 발생하므로 필터링을 통해 이와 같은 왜곡 현상을 줄이고 부드러운 이미지를 만들어낼 수 있음 2010-1학기 컴퓨터게임(DirectX)
텍스처 필터 텍스처 필터를 지정하기 위해서는 IDirect3DDevice9::SetSamplerState를 이용하며 세 가지 다른 타입의 필터를 제공. 근접점 샘플링(Nearest point sampling) 디폴트 필터링 방식이며 가장 떨어지는 품질과 결과를 만들어내지만 또한 가장 빠른 속도를 가짐 예 Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 2010-1학기 컴퓨터게임(DirectX)
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 선형 필터링(Linear filtering) – 선형 필터링은 비교적 높은 품질의 결과물을 만들어내며 현재의 하드웨어 성능을 고려하면 실행 속도 또한 빠른 편임. Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 2010-1학기 컴퓨터게임(DirectX)
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); 비등방성 필터링(Anisotropic filtering) – 비등방성 필터링은 가장 높은 품질의 결과물을 만들어내지만 실행 속도 또한 가장 느림 Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC); 이 필터를 이용할 때, 필터링의 품질을 결정하는 D3DSAMP_MAXANISOTROPY 레벨을 지정해야 함. Device->SetSamplerState(0, D3DSAMP_ MAXANISOTROPY, 4) 레벨값의 범위는 D3DCAPS9 구조체에서 확인 2010-1학기 컴퓨터게임(DirectX)
밉맵 텍스처의 크기를 급격하게 변경하는 것을 막는 테크닉 중요하게 생각하는 디테일을 보존하면서 여러 개의 작은 해상도로 텍스처로 만드는 방식 밉맵필터 밉맵을 이용하는 방법을 결정하기 위해 밉맵 필터 지정 Device->SetSamplerState(0,D3DSAMP_MIPFILTER, Filter); Filter 부분에는 다음 옵션 중 하나를 넣는다. D3DTEXF_NONE – 밉맵을 이용하지 않는다. D3DTEXF_POINT – 이 필터를 이용하면 Direct3D는 스크린 삼각형과 가장 비슷한 크기의 밉맵 레벨을 선택 D3DTEXF_LINEAR – 이 필터를 이용하면 Direct3D는 가장 비슷한 두 개의 밉맵 레벨에 min과 mag 필터에 따른 필터링을 적용 2010-1학기 컴퓨터게임(DirectX)
만약 장치에서 밉맵을 지원한다면 D3DXCreateTextureFromFile을 이용해 자동으로 밉맵 체인을 생성 Direct3D에서 밉맵 이용하기 만약 장치에서 밉맵을 지원한다면 D3DXCreateTextureFromFile을 이용해 자동으로 밉맵 체인을 생성 밉맵의 구성과 이용에 필요한 대부분의 과정은 자동으로 처리 2010-1학기 컴퓨터게임(DirectX)
어드레스 모드 텍스처 좌표의 범위가 [0,1]내에 있어야 하나, 때로는 범위를 넘어설 수도 있다. [0,1] 범위를 넘어서는 텍스처 좌표를 처리하는 방법은 Direct3D 어드레스 모드에 의해 정의됨 어드레스 모드: wrap, border color, clamp, mirror 2010-1학기 컴퓨터게임(DirectX)
AddressModes 예제 // set wrap address mode if( ::GetAsyncKeyState('W') & 0x8000f ) { Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP); Device->SetSamplerState(0, D3DSAMP_ADDRESSV, } // set border color address mode if( ::GetAsyncKeyState('B') & 0x8000f ) D3DTADDRESS_BORDER); 2010-1학기 컴퓨터게임(DirectX)
Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER); Device->SetSamplerState(0, D3DSAMP_BORDERCOLOR, 0x000000ff); } // set clamp address mode if( ::GetAsyncKeyState('C') & 0x8000f ) { Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); 2010-1학기 컴퓨터게임(DirectX)
// set mirror address mode if( ::GetAsyncKeyState('M') & 0x8000f ) { Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR); Device->SetSamplerState(0, D3DSAMP_ADDRESSV, } 2010-1학기 컴퓨터게임(DirectX)
예제 애플리케이션 사각형에 텍스처를 입히고 텍스처 필터를 지정하는 방법 소개 장면에 텍스처를 추가하는 과정 1) 텍스처 좌표를 지정하고 물체의 버텍스를 구성 2) D3DXCreateTextureFromFile 함수를 이용해 IDirect3DTexture9 인터페이스에 텍스처를 읽어들임 3) 축소, 확대, 밉맵 필터를 지정 4) 물체를 그리기 전에 IDirect3DDevice9::SetTexture함수를 이용해 물체와 연결할 텍스처를 지정 2010-1학기 컴퓨터게임(DirectX)
첫 번째는 사각형의 버텍스를 보관할 버텍스 버퍼이며 두 번째는 사각형에 입힐 텍스처를 보관하기 위한 것 전역 변수 인스턴스를 만듬 첫 번째는 사각형의 버텍스를 보관할 버텍스 버퍼이며 두 번째는 사각형에 입힐 텍스처를 보관하기 위한 것 IDirect3DVertexBuffer9* Quad = 0; IDirect3DTexture9* Tex = 0; Setup 루틴 텍스처 좌표를 포함하는 두 개의 삼각형으로 사각형 구성 비트맵 파일 dx5_logo.bmp를 IDirect3DTexture9 인터페이스에 로드 SetTexture 메서드를 이용해 텍스처를 활성화 축소와 확대 필터를 선형 필터로 지정하고 밉맵 필터를 D3DTEXF_POINT로 지정 2010-1학기 컴퓨터게임(DirectX)
Quad->Lock(0, 0, (void**)&v, 0); bool Setup() { Device->CreateVertexBuffer(6 * sizeof(Vertex), D3DUSAGE_ WRITEONLY, Vertex::FVF, D3DPOOL_MANAGED, &Quad, 0); Vertex* v; Quad->Lock(0, 0, (void**)&v, 0); // quad built from two triangles, note texture coordinates: v[0] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f); v[1] = Vertex(-1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f); v[2] = Vertex( 1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f); v[3] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f); v[4] = Vertex( 1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f); v[5] = Vertex( 1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f); 2010-1학기 컴퓨터게임(DirectX)
D3DXCreateTextureFromFile(Device, “dx5_logo.bmp", &Tex); // 텍스처를 활성화 Quad->Unlock(); // 텍스처 데이터를 로드한다. D3DXCreateTextureFromFile(Device, “dx5_logo.bmp", &Tex); // 텍스처를 활성화 Device->SetTexture(0, Tex); // 텍스처 필터를 지정 Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ LINEAR); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ POINT); Device->SetRenderState(D3DRS_LIGHTING, false); 2010-1학기 컴퓨터게임(DirectX)
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI * 0.5f, // 90 - degree // 투영 행렬 지정 D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI * 0.5f, // 90 - degree (float)Width / (float)Height, 1.0f, 1000.0f); Device->SetTransform(D3DTS_PROJECTION, &proj); return true; } 현재 매핑된 텍스처를 이용해 사각형 렌더링 bool Display(float timeDelta) { if( Device ) Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); 2010-1학기 컴퓨터게임(DirectX)
Device->SetStreamSource(0, Quad, 0, sizeof(Vertex)); Device->SetFVF(Vertex::FVF); Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; 2010-1학기 컴퓨터게임(DirectX)
2010-1학기 컴퓨터게임(DirectX)
IDirect3DDevice9* Device = 0; const int Width = 640; #include "d3dUtility.h" IDirect3DDevice9* Device = 0; const int Width = 640; const int Height = 480; IDirect3DVertexBuffer9* Quad = 0; IDirect3DTexture9* Tex = 0; struct Vertex { Vertex(){} Vertex(float x, float y, float z, float nx, float ny, float nz, float u, float v) 2010-1학기 컴퓨터게임(DirectX)
_nx = nx; _ny = ny; _nz = nz; _u = u; _v = v; } float _x, _y, _z; { _x = x; _y = y; _z = z; _nx = nx; _ny = ny; _nz = nz; _u = u; _v = v; } float _x, _y, _z; float _nx, _ny, _nz; float _u, _v; // texture coordinates static const DWORD FVF; }; const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1; bool Setup() Device->CreateVertexBuffer(6 * sizeof(Vertex), D3DUSAGE_ WRITEONLY, Vertex::FVF, D3DPOOL_MANAGED, &Quad, 0); 2010-1학기 컴퓨터게임(DirectX)
Quad->Lock(0, 0, (void**)&v, 0); Vertex* v; Quad->Lock(0, 0, (void**)&v, 0); // quad built from two triangles, note texture coordinates: v[0] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f); v[1] = Vertex(-1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f); v[2] = Vertex( 1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f); v[3] = Vertex(-1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f); v[4] = Vertex( 1.0f, 1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f); v[5] = Vertex( 1.0f, -1.0f, 1.25f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f); Quad->Unlock(); 2010-1학기 컴퓨터게임(DirectX)
D3DXCreateTextureFromFile( Device, "dx5_logo.bmp", &Tex); Device->SetTexture(0, Tex); Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT); Device->SetRenderState(D3DRS_LIGHTING, false); D3DXMATRIX proj; D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI * 0.5f, // 90 - degree (float)Width / (float)Height, 1.0f, 1000.0f); 2010-1학기 컴퓨터게임(DirectX)
Device->SetTransform(D3DTS_PROJECTION, &proj); return true; } void Cleanup() { d3d::Release<IDirect3DVertexBuffer9*>(Quad); d3d::Release<IDirect3DTexture9*>(Tex); bool Display(float timeDelta) if( Device ) Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0); Device->BeginScene(); 2010-1학기 컴퓨터게임(DirectX)
Device->SetStreamSource(0, Quad, 0, sizeof(Vertex)); Device->SetFVF(Vertex::FVF); Device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); Device->EndScene(); Device->Present(0, 0, 0, 0); } return true; LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) case WM_DESTROY: ::PostQuitMessage(0); break; 2010-1학기 컴퓨터게임(DirectX)
if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, Width, Height, true, D3DDEVTYPE_HAL, &Device)) ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; 2010-1학기 컴퓨터게임(DirectX)
::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); 2010-1학기 컴퓨터게임(DirectX)
2010-1학기 컴퓨터게임(DirectX)