Tutorial5- 텍스쳐
- 프로그래밍/3D그래픽스 & 쉐이더
- 2011. 3. 29. 23:54
폴리곤, 조명, 카메라 등의 조합만으로는 현실감이 없는 밋밋한 3D밖에 맛 볼수 없다.
이러한 3D에 활력을 불어 넣어주는 것이 바로 텍스쳐이다.
폴리곤들의 조합(메시)에 옷을 입히는 작업이라고 보면 쉽게 이해될 것이다.
텍스쳐의 종류는 1차원, 2차원, 3차원 등이 있다.
각 텍스쳐에는 텍스쳐를 제어하기 위한 텍스쳐만의 좌표계가 필요하다.
일반적으로 가장 많이 사용하는 좌표계는 2차원 u, v 좌표계이다. 모든 텍스쳐 좌표계는 기본적으로 0.0 ~ 1.0사이의 실수값을 갖게 되고, 이 값의 범위를 넘게되면 다른 처리를 해줘야만 다양한 효과를 낼 수 있다. 그러한 효과에는 Clamp, Mirror, Wrap, Border 등이 있다.
u.v좌표 : (x값 0.0~1.0) (y값 0.0~1.0)
<사진출저: 한국콘텐츠아카데미>
텍스쳐를 사용하기 위한 준비
1. IDirect3DTexture9 인터페이스 선언
LPDIRECT3DTEXTURE9 g_pTexture = NULL; // 텍스쳐 정보
2. 텍스쳐 좌표를 갖는 정점 선언
struct CUSTOMVERTEX
{
D3DXVECTOR3 position; // 3차원 좌표
D3DCOLOR color; // 색깔
FLOAT tu, tv; // 텍스쳐 좌표
};
/// 사용자 정점 구조체에 관한 정보를 나타내는 FVF값
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
3. 텍스쳐 생성( 파일을 로드하는 방법과, 라이트맵핑과 같이 직접 생성도 한다. )
D3DXCreateTextureFromFile( g_pd3dDevice, "banana.bmp", &g_pTexture )
4. 텍스쳐 스테이지 설정(텍스쳐 스테이지는 여러장의 텍스쳐와 색깔정보를 섞어서 출력할때 사용된다.)
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,
D3DTOP_MODULATE );
5. 그려질 텍스쳐 지정
g_pd3dDevice->SetTexture( 0, g_pTexture ); // 0번 텍스쳐 스테이지에 텍스쳐 고정
6. 메시 그리기
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2*50-2 );
텍스쳐를 사용하기 위해서는 많은 전처리 및 설정이 필요하면 별도의 정점도 선언해야 한다.
또한 메시의 형태에 따라 텍스쳐이미지의 제작방법도 다르다. 이러한 부분은 차후에 좀더 알아보도록 하자.
<텍스쳐 소스분석>
// 1. InitGeometry()
// 기하 정보 초기화
// 정점 버퍼와 텍스처 생성
HRESULT InitGeometry()
{
/// D3DX계열 함수를 사용해서 파일로부터 텍스쳐 생성(banana.bmp)
if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice, "banana.bmp",
&g_pTexture ) ) )
{
/// 현재폴더에 파일이 없으면 상위폴더 검색
if( FAILED( D3DXCreateTextureFromFile( g_pd3dDevice,
"..\\banana.bmp", &g_pTexture ) ) )
{
/// 텍스쳐 생성 실패
MessageBox(NULL, "Could not find banana.bmp", "Textures.exe",
MB_OK);
return E_FAIL;
}
}
/// 정점버퍼 생성
if( FAILED( g_pd3dDevice->CreateVertexBuffer(
50*2*sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &g_pVB, NULL ) ) )
{
return E_FAIL;
}
/// 정점버퍼를 값으로 채운다.
/// 텍스쳐의 u,v좌표값을 0.0 ~ 1.0 사이의 값으로 채워넣고 있다.
CUSTOMVERTEX* pVertices;
if( FAILED( g_pVB->Lock( 0, 0, (void**)&pVertices, 0 ) ) )
return E_FAIL;
for( DWORD i=0; i<50; i++ )
{
FLOAT theta = (2*D3DX_PI*i)/(50-1);
pVertices[2*i+0].position = D3DXVECTOR3( sinf(theta),-1.0f, cosf(theta) );
pVertices[2*i+0].color = 0xffffffff;
// SHOW_HOW_TO_USE_TCI가 선언안되어 있으면 텍스쳐 좌표를 생성함
#ifndef SHOW_HOW_TO_USE_TCI
// 텍스쳐의 u좌표 0/49, 1/49, 2/49 ... 49/49 (즉 0.0 ~ 1.0)
pVertices[2*i+0].tu = ((FLOAT)i)/(50-1);
// 텍스쳐의 v좌표 1.0
pVertices[2*i+0].tv = 1.0f;
#endif
pVertices[2*i+1].position = D3DXVECTOR3( sinf(theta), 1.0f, cosf(theta) );
pVertices[2*i+1].color = 0xff808080;
// SHOW_HOW_TO_USE_TCI가 선언안되어있으면 텍스쳐 좌표를 생성함.
#ifndef SHOW_HOW_TO_USE_TCI
// 텍스쳐의 u좌표 0/49, 1/49, 2/49 ... 49/49 (즉 0.0 ~ 1.0)
pVertices[2*i+1].tu = ((FLOAT)i)/(50-1);
// 텍스쳐의 v좌표 0.0
pVertices[2*i+1].tv = 0.0f;
#endif
}
g_pVB->Unlock();
return S_OK;
}
// 2. Render()
// 화면에 그려주기
VOID Render()
{
// 후면버퍼와 Z버퍼를 지운다.
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// 렌더링 시작
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
// 월드,뷰,프로젝션 행렬을 설정한다.
SetupMatrices();
// 생성한 텍스쳐를 0번 텍스쳐 스테이지에 올린다.
// 텍스쳐 스테이지는 여러장의 텍스쳐와 색깔정보를 섞어서 출력할때 사용된다.
// 여기서는 텍스쳐의 색깔과 정점의 색깔정보를 modulate연산으로 섞어서 출력한다.
// 0번 텍스쳐 스테이지에 텍스쳐 고정
g_pd3dDevice->SetTexture( 0, g_pTexture );
// MODULATE연산으로 색깔을 섞음
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,
D3DTOP_MODULATE );
// 첫번째 섞을색은 텍스쳐 색
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1,
D3DTA_TEXTURE );
// 두번째 섞을색은 정점 색
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2,
D3DTA_DIFFUSE );
// alpha연산은 사용하지 않음
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,
D3DTOP_DISABLE );
#ifdef SHOW_HOW_TO_USE_TCI
// D3D의 텍스쳐 좌표 생성 기능을 사용하는 예를 보여준다.
// 여기서는 카메라좌표계에서의 정점정보를 사용해서 텍스쳐 좌표를 생성한다.
// 4x4크기의 텍스쳐 변환행렬을 텍스쳐좌표인덱스(TCI=Texture Coord Index)전달인자로
// 사용해서 x,y,z TCI좌표를 u,v텍스쳐 좌표로 변환한다.
// 사용한 것은 단순히 (-1.0 ~ +1.0) 값을 (0.0 ~ 1.0) 사이의 값으로 변환하는 행렬이다.
// world,view,projection변환을 거친 정점은 (-1.0 ~ +1.0)사이의 값을 갖게 된다.
// tu = 0.5*x + 0.5
// tv = -0.5*y + 0.5
D3DXMATRIXA16 mat;
mat._11 = 0.25f; mat._12 = 0.00f; mat._13 = 0.00f; mat._14 = 0.00f;
mat._21 = 0.00f; mat._22 =-0.25f; mat._23 = 0.00f; mat._24 = 0.00f;
mat._31 = 0.00f; mat._32 = 0.00f; mat._33 = 1.00f; mat._34 = 0.00f;
mat._41 = 0.50f; mat._42 = 0.50f; mat._43 = 0.00f; mat._44 = 1.00f;
// 텍스쳐 변환행렬
g_pd3dDevice->SetTransform( D3DTS_TEXTURE0, &mat );
// 2차원 텍스쳐 사용
g_pd3dDevice->SetTextureStageState( 0,
D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );
// 카메라 좌표계 변환
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX,
D3DTSS_TCI_CAMERASPACEPOSITION );
#endif
// 정점버퍼의 내용을 그린다.
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0,
sizeof(CUSTOMVERTEX) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2*50-2 );
// 렌더링 종료
g_pd3dDevice->EndScene();
}
// 후면버퍼를 보이는 화면으로!
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
전체 소스를 받아보면 #ifdef문은 주석으로 막아준 #define SHOW_HOW_TO_USE_TCI를 열고 컴파일 해보면 무엇인지 알수있을 것이다. 그 부분은 반사맵핑이라는 기법이다
'프로그래밍/3D그래픽스 & 쉐이더' 관련 글
인덱스버퍼
2011.03.30
Tutorial6- 메쉬
2011.03.30
DX물체가 화면에 안뜰때 고려해볼 사항
2011.03.29
Tutorial4- 조명(Light)-광원,재질
2011.03.29