『Lena's by ☆볶기!!』: Restart !!

Rorolena
Texture와 Filtering설정

오랜만의 다이렉트 포스팅 입니다.
이번에도 용책을 기준으로
Texture를 입히는 방법과
Filtering을 설정하는 방법을
설명해도록 하겠습니다.

주요 내용은 다음과 같습니다.

Texture를 선언)_
IDirect3DTexture9* Textures[5] = {0,};

구조체 설정)_
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;
 }

 FLOAT _x, _y, _z, _nx, _ny, _nz, _u, _v;
 static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;

...

U, V좌표 입력)_
Vertex V;
Vertex* pV;
VB->Lock(0, 0, (VOID**)&pV, 0);

for(INT x=0; x<4; x++)
 {
 for(INT _v=0; _v<2; _v++)
 {
  for(INT _u=0; _u<2; _u++)
  {
   V._x = x+_u;
   V._y = -_v;
   V._z = 0;

   V._nx = V._x;
   V._ny = V._y;
   V._nz = V._z;

   V._u = _u;
   V._v = _v;

   *pV++ = V;    
  }
 }
}

for(INT x=0; x<4; x++)
{
 for(INT _v=0; _v<2; _v++)
 {
  for(INT _u=0; _u<2; _u++)
  {
   V._x = x+_u;
   V._y = -(1+(_v*2));
   V._z = 0;

   V._nx = V._x;
   V._ny = V._y;
   V._nz = V._z;

   V._u = (float)(x+_u)/4;
   V._v = _v;

   *pV++ = V;    
  }
 }
}

...

텍스쳐 로드)_
D3DXCreateTextureFromFile(
  Device, "Tex1.jpg", &Textures[0]);
D3DXCreateTextureFromFile(
  Device, "Tex2.jpg", &Textures[1]);
D3DXCreateTextureFromFile(
  Device, "Tex3.jpg", &Textures[2]);
D3DXCreateTextureFromFile(
  Device, "Tex4.jpg", &Textures[3]);
D3DXCreateTextureFromFile(
  Device, "Tex5.jpg", &Textures[4]);

필터링 적용)_
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

렌더링 설정)_
Device->SetRenderState(D3DRS_LIGHTING, FALSE);

...

텍스쳐 출력)_
Device->SetTexture(0, Textures[0]);
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4, 0, 2);

Device->SetTexture(0, Textures[1]);
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4, 6, 2);

Device->SetTexture(0, Textures[2]);
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4, 12, 2);

Device->SetTexture(0, Textures[3]);
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4,18, 2);

Device->SetTexture(0, Textures[4]);
Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 16, 24, 8);

이 소스의 완성 모습은 다음과 같습니다.

이번 포스팅부터는 조금씩
설명이 필요하리라 생각합니다.

지금까지 보셨던 소스는
기존 포스팅 소스와 비교 해보시길 바라며
먼저 u, v 좌표계부터 설명 드리겠습니다.

u, v 텍스쳐 좌표계)_
u, v좌표계, 텍셀 좌표계, 텍스쳐 좌표계라고 하며

이좌표는 지정 폴리곤부터 폴리곤까지
지정 x, y큼 텍스쳐를 입히는 것입니다.

좀더 쉽게 말씀드리면
Vertex가 찍어놓은 3좌표 와 좌표사이에
2d 그림을 입히는 것이라 할수 있습니다.

그러하여 로드한 이미지를 한장 출력하는데
시작점을 0, 0 끝점을 1, 1로 지정하면 텍스쳐가 출력됩니다.

이이야기를 좀더 다르게 이야기 해보면
0 과 1 이외에도 0.25나 2.0같은 값을 입력이 가능합니다.
이럴경우 그만큼까지 잘려 그려지거나 혹은
그려지고 여백이 나오게 됩니다.

예로 위의 4개의 이미지 아래 있는
이미지는 한장의 텍스쳐로 분할하여 출력하였습니다.

기타 사항으로 다음 포스팅때 말씀 드리겠지만
한자리에 8장의 텍스쳐를 올릴수 있습니다.

텍스쳐 좌표계를 사용하려면?)_
텍스쳐 좌표계를 사용하는 절차는 간단합니다.
위의 소스에서 지목 해놓은 부분만 유심히 보시면
금방 아실수 있듣이

텍스쳐 선언
IDirect3DTexture9* Textures[5] = {0,};

옵션 추가
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;

좌표 입력
V._u = _u;
V._v = _v;

텍스쳐 로드
D3DXCreateTextureFromFile(
  Device, "Tex1.jpg", &Textures[0]);

필터링 설정
Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

텍스쳐 출력
Device->SetTexture(0, Textures[0]);

순으로 이루어집니다.

[추가사항]
D3DXCreateTextureFromFile 관한 이야기입니다.
D3DXCreateTextureFromFile이 합수에 불러지는 포멧은
JPEG, BGM, GIF, RAW, PNG, TGA, DDS, DIB등등 포토샾에서
만들수 있는 대부분의 포멧을 불러오는것이 가능합니다.

필터링은 무엇인가?)_
아마 게임을 하시다보면 옵션에서
이방성 관련 설정을 보신적이 있을것입니다.

필터링이란 이런것을 말하는 것으로
불러온 이미지의 계단현상을 막기위하여 사용합니다.

이 필터링을 사용하지 않을경우
로드된 이미지가 지글거린 다던지
거지같은 텍스쳐 품질을 보실수 있습니다.

필터링에 설정 가능한 옵션은 다음과 같습니다.

필터의 종류 효과 명칭
NONE 필터를 사용하지 않음
POINT 최근점 샘플림 최근점 샘플링
LINEAR 선택된 텍셀의 상하좌우 픽셀의 평균값 선형 필터링
ANISOTROPIC 텍스쳐 왜곡현상을 해결하기 위해 보간할 때,
밉맵으로부터 여러 픽셀을 취해서 얻는값
이방성 필터링
PYRAMIDALQUAD 피라미드 형태로 4개 샘플을 취한 값 피라미드 쿼드
GAUSSIANQUAD 4개 샘플의 가우스 필터값 가우시안 쿼드

대부분의 권장사항을보면
LINEAR까지 설정 하는것을 권장하고 있습니다.

여담입니다만
1. LINEAR 이상부턴 유심히 보지 않는 이상 큰차이를 못느낍니다.
2. 요즘 컴퓨터 성능이 워낙좋아 어지간히 큰값이 아닌이상 ANISOTROPIC에 의한
프래임 하락은 그냥 웃어 넘기는것이 가능할정도의 세상이 되었습니다.

텍스쳐를 따로 출력하는 방법의 보충설명)_
에... 보충설명으로 예제를 보시다 시피
이미지가 총 5개가 떠있는것을 보실수 있습니다.

뭐 각 삼각형마다 다른 이미지를 띄우도록 한것인데
DrawIndexedPrimitive를 달리 설정하는 부분을
잘모르시는 분을 위해 인자 설명을 드리고자 합니다.

먼저 제공자의 소개에 의하면 다음과 같습이 정의 되어있습니다.

HRESULT DrawIndexedPrimitive(
D3DPRIMITIVETYPE Type,
INT BaseVertexIndex,
UINT MinIndex,
UINT NumVertices,
UINT StartIndex,
UINT PrimitiveCount
);

매우 직관적으로 써있는대요
MSDN번역을 보여드리면 다음과 같습니다.

Type
[in] D3DPRIMITIVETYPE 열거형의 멤버. 렌더링 하는 기본도형의 종류를 기술한다. D3DPT_POINTLIST 는 이 메서드에서는 지원하지 않는다. 「주의」를 참조할것.
BaseVertexIndex
[in] 인덱스 버퍼의 시작 지점으로부터 최초의 정점 인덱스까지의 오프셋(offset).
MinIndex
[in] 이 호출동안에 사용되는 정점군에 대한 최소의 정점 인덱스.
NumVertices
[in] 이 호출로 사용되는 정점의 수 (BaseVertexIndex + MinIndex 로부터 시작된다).
StartIndex
[in] 인덱스 배열 중(안)에서 정점의 읽기를 시작 하는 위치.
PrimitiveCount
[in] 렌더링 하는 기본도형의 수. 사용되는 정점의 수는, 기본도형 카운트의 기능과 기본도형의 종류이다. 기본도형의 허용 최대수는,D3DCAPS9 구조체의 MaxPrimitiveCount 멤버를 체크해 결정된다.

여기서 중요한건 3~5 번째 인자가 되겠습니다.
3번째 인자는 사용될만큼의 정점에 수이며
4번째 인자는 그리기 시작할 정점 버퍼의 순번 위치
5번째 인자는 그릴 도형(삼각형)의 숫자입니다.

이정도 설명이면 나머진 알아서
생각 하실수 있으리라고 생각합니다.

글을 맺으며 마지막으로
Vertexd에 nx, ny, nz에 관한겁니다만
광원도달점으로써 이는 광원을 설명드릴때
다시 설명드릴태니 일단 신경쓰지 않으셔도 됩니다.

'개발실 ◐ ━━ > DirectX' 카테고리의 다른 글

World Transformation(월드 변환)  (0) 2012.01.30
Rendering Pipeline 과정  (0) 2012.01.30
IndexBuffer를 이용한 Color Cube만들기  (0) 2012.01.26
다이렉트 초기화  (2) 2012.01.14