D3DXCreateMeshFVF 사용


1) 버텍스 구조체 및 타입 선언 
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;

구조체도 클래스처럼 생성자를 가질 수 있다. 또, "Vertex"의 크기를 검사해보면, 24바이트가 나올것이다.
28바이트가 나와야 하지만, static으로 선언한 변수는 구조체의 크기에 포함되지 않는다.

음, 저렇게 하면 보기가 좋겠꾼....

2)메시 버퍼의 초기화

메시를 만들어서 사용 방법은 다음과 같다.

-빈 메시 만들기
-메시를 버텍스를 채운다.
-메시의 서브셋을 지정한다.
-메시의 인접 정보를 만든다.
-메시를 최적화 한다
-메시를 렌드링 한다.
 

bool RenderInit()
{
	HRESULT hr = 0;

	hr = D3DXCreateMeshFVF(
		12,
		24,
		D3DXMESH_MANAGED,
		Vertex::FVF,
		g_d3d_Device,
		&g_pMesh);

	if(FAILED(hr))
		return false;

	Vertex* v = 0;
	g_pMesh->LockVertexBuffer(0, (void**)&v);

	// fill in the front face vertex data
	v[0] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
	v[1] = Vertex(-1.0f,  1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
	v[2] = Vertex( 1.0f,  1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
	v[3] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);

	// fill in the back face vertex data
	v[4] = Vertex(-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
	v[5] = Vertex( 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
	v[6] = Vertex( 1.0f,  1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f);
	v[7] = Vertex(-1.0f,  1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f);

	// fill in the top face vertex data
	v[8]  = Vertex(-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
	v[9]  = Vertex(-1.0f, 1.0f,  1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
	v[10] = Vertex( 1.0f, 1.0f,  1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f);
	v[11] = Vertex( 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);

	// fill in the bottom face vertex data
	v[12] = Vertex(-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f);
	v[13] = Vertex( 1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f);
	v[14] = Vertex( 1.0f, -1.0f,  1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f);
	v[15] = Vertex(-1.0f, -1.0f,  1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);

	// fill in the left face vertex data
	v[16] = Vertex(-1.0f, -1.0f,  1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
	v[17] = Vertex(-1.0f,  1.0f,  1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
	v[18] = Vertex(-1.0f,  1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
	v[19] = Vertex(-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);

	// fill in the right face vertex data
	v[20] = Vertex( 1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
	v[21] = Vertex( 1.0f,  1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
	v[22] = Vertex( 1.0f,  1.0f,  1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);
	v[23] = Vertex( 1.0f, -1.0f,  1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);

	g_pMesh->UnlockVertexBuffer();

	//
	// Define the triangles of the box
	//
	WORD* i = 0;
	g_pMesh->LockIndexBuffer(0, (void**)&i);

	// fill in the front face index data
	i[0] = 0; i[1] = 1; i[2] = 2;     
	i[3] = 0; i[4] = 2; i[5] = 3;

	// fill in the back face index data
	i[6] = 4; i[7]  = 5; i[8]  = 6;
	i[9] = 4; i[10] = 6; i[11] = 7;

	// fill in the top face index data
	i[12] = 8; i[13] =  9; i[14] = 10;
	i[15] = 8; i[16] = 10; i[17] = 11;

	// fill in the bottom face index data
	i[18] = 12; i[19] = 13; i[20] = 14;
	i[21] = 12; i[22] = 14; i[23] = 15;

	// fill in the left face index data
	i[24] = 16; i[25] = 17; i[26] = 18;
	i[27] = 16; i[28] = 18; i[29] = 19;

	// fill in the right face index data
	i[30] = 20; i[31] = 21; i[32] = 22;
	i[33] = 20; i[34] = 22; i[35] = 23;

	g_pMesh->UnlockIndexBuffer();


	DWORD* attributeBuffer = 0;
	g_pMesh->LockAttributeBuffer(0, &attributeBuffer);

	for(int a = 0; a < 4; a++)
		attributeBuffer[a] = 0;

	for(int b = 4; b < 8; b++)
		attributeBuffer[b] = 1;

	for(int c = 8; c < 12; c++)
		attributeBuffer[c] = 2;

	g_pMesh->UnlockAttributeBuffer();

	// Optimize the mesh to generate an attribute table.
	std::vector<DWORD> adjacencyBuffer(g_pMesh->GetNumFaces() * 3);
	g_pMesh->GenerateAdjacency(0.0f, &adjacencyBuffer[0]);

	hr = g_pMesh->OptimizeInplace(		
		D3DXMESHOPT_ATTRSORT |
		D3DXMESHOPT_COMPACT  |
		D3DXMESHOPT_VERTEXCACHE,
		&adjacencyBuffer[0],
		0, 0, 0);

	D3DXCreateTextureFromFile(g_d3d_Device, "brick0.jpg", &g_pTextures[0]);
	D3DXCreateTextureFromFile(g_d3d_Device, "brick1.jpg", &g_pTextures[1]);
	D3DXCreateTextureFromFile(g_d3d_Device, "checker.jpg", &g_pTextures[2]);

	g_d3d_Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
	g_d3d_Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
	g_d3d_Device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
	g_d3d_Device->SetRenderState(D3DRS_LIGHTING, false);

#ifdef _DEBUG
	//실행과는 무관하다.
	//subSet의 갯수를 파악하기 위해서 필요하다. 
	DWORD numSubsets = 0;
	g_pMesh->GetAttributeTable(0,  &numSubsets);
#endif
	return true;
}

-빈 메시 만들기
버텍싀 수이다. 앞의 두인자는 항상 0보다 커야 한다.

-메시를 버텍스를 채운다.
g_pMesh->LockVertexBuffer()와 g_pMesh->UnlockVertexBuffer() 사이에 버텍스를 채운다.

-메시의 서브셋을 지정한다.
g_pMesh->LockAttributeBuffer()와 g_pMesh->UnlockAttributeBuffer() 사이에 서브셋을 지정한다.
여기서는 0, 1, 2 총 3개의 서브셋을 사용하였다 0, 1만 지정하면 서브셋은 2개가 된다.

-메시의 인접 정보를 만든다.
OptimizeInplace()하기 위해 인접 정보를 만든다.

std::vector<DWORD> adjacencyBuffer(g_pMesh->GetNumFaces() * 3);
g_pMesh->GenerateAdjacency(0.0f, &adjacencyBuffer[0]);

-메시를 최적화 한다
g_pMesh->OptimizeInplace()

-메시를 렌드링 한다.
 

3)렌드링 

HRESULT Render3D (float timeDelta)
{
	HRESULT hr;
	D3DXMATRIX xRot;
	D3DXMatrixRotationX(&xRot, D3DX_PI * 0.2f);

	static float y = 0.0f;
	D3DXMATRIX yRot;
	D3DXMatrixRotationY(&yRot, y);
	y += timeDelta;

	if( y >= 6.28f )
		y = 0.0f;

	D3DXMATRIX world = xRot * yRot;
	g_d3d_Device->SetTransform(D3DTS_WORLD, &world);

    g_d3d_Device->Clear (0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB (0, 0, 0), 1.0f, 0);
    g_d3d_Device->BeginScene ();

	for(int i = 0; i < g_nNumSubsets; i++)
	{
		g_d3d_Device->SetTexture( 0, g_pTextures[i] );
		g_pMesh->DrawSubset( i );
	}

    g_d3d_Device->EndScene ();
    hr = g_d3d_Device->Present (NULL, NULL, NULL, NULL);
	return hr;
}

메트리얼 없이 텍스쳐만 사용하고 있다.
서브 셋이 3개이므로 SetTexture(), DrawSubset()세 번을 반복한다.

4)소멸 

void DestroyDirect3D8()
{
	_RELEASE_<ID3DXMesh*>(g_pMesh);
	_RELEASE_<IDirect3DTexture9*>(g_pTextures[0]);
	_RELEASE_<IDirect3DTexture9*>(g_pTextures[1]);
	_RELEASE_<IDirect3DTexture9*>(g_pTextures[2]);

	_RELEASE_<LPDIRECT3DDEVICE9>(g_d3d_Device);
	_RELEASE_<LPDIRECT3D9>(g_d3d);
}

g_pMesh와 g_pTextures[0], g_pTextures[1], g_pTextures[2]를 해제 한다.

 

etc)

DumpMesh()에서 Mesh 구조, 값등을 알기 위해서 Mesh Dump.txt 파일로 덤프키고 잇다.

[펌]
DirectX 9를 이용한 3D GAME 프로그래밍 입문 - 정보 문화사