Jump to content
  • Advertisement
Sign in to follow this  
cozzie

D3DXMesh: code share, generate tangents/binormals

This topic is 2082 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

I've read a lot of topics on this subject and spent some time solving this. So I thought, let's paste it, so people can reuse/ learn from it.

So if this is your situation:

 

- you're using Direct3D9, C++

- you're loading X file meshes using D3DX

- the mesh contains only normals, or even no normals

- you want to do normal mapping, but missing tangents and binormals

 

Have fun.

// vertex declaration
typedef struct TVERTEX
{ 
	D3DXVECTOR3	position;
	D3DXVECTOR3	normal;
	float    	tex[2];	
	D3DXVECTOR3 binormal;
	D3DXVECTOR3 tangent;
} TVERTEX;

const D3DVERTEXELEMENT9 vtxdecl[] =
{
	{0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
	{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
	{0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
	{0, 32, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0},
	{0, 44, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
	D3DDECL_END()
};

// load a X file mesh and check normals/binormals/tangents
bool CD3dmesh::LoadXFile(const std::string pXfilename)										   
{
	if(mD3ddev == NULL)
	{
		MessageBox(NULL, err_mesh_d3ddev.c_str(), err_windowtext.c_str(), MB_OK);
		return false;
	}

	if(FAILED(D3DXLoadMeshFromXA(pXfilename.c_str(), 
								 D3DXMESH_MANAGED, //SYSTEMMEM, // DYNAMIC??? SYSTEMMEM FOR DYNAMIC OBJECTS??
								 mD3ddev,
								 &mAdjacencyBuffer,
								 &mMaterialBuffer,
								 NULL,
								 &mSubMeshSize,
								 &mMesh))) return false;
	
	if(FAILED(mMesh->OptimizeInplace(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)mAdjacencyBuffer->GetBufferPointer(), (DWORD*)mAdjacencyBuffer->GetBufferPointer(), NULL, NULL)))	// 2nd adjac was NULL!!
		return false;

	/** check Mesh vertex declaration for normals, binormals & tangents **/
	/**
	/** Scenario 1: All there, proceed									**/
	/** Scenario 2: No normals, tangents and binormals					**/
	/** Scenario 3: No tangents and binormals							**/

	bool normals = false;
	bool tangents = false;
	bool binormals = false;

	D3DVERTEXELEMENT9 meshDecl[MAX_FVF_DECL_SIZE];
	mMesh->GetDeclaration(meshDecl);
	
	for(unsigned int index=0;index<D3DXGetDeclLength(meshDecl);++index)
	{
		if(meshDecl[index].Usage == D3DDECLUSAGE_NORMAL) normals = true;
		if(meshDecl[index].Usage == D3DDECLUSAGE_TANGENT) tangents = true;
		if(meshDecl[index].Usage == D3DDECLUSAGE_BINORMAL) binormals = true;
	}

	if(!normals) { 
		if(D3D_OK != D3DXComputeNormals(mMesh, NULL)) return false;	}

	if(!tangents || !binormals) CalculateTangentFrame();

	mTempMaterial = (D3DXMATERIAL*)mMaterialBuffer->GetBufferPointer();
	return true;
}

// the CalculateTangentFrame function
bool CD3dmesh::CalculateTangentFrame()
{
	#ifdef _DEBUG
	OutputDebugStringA("Warning: no tangents and/or binormals in mesh, calculating with D3DX!\n");
	#endif
	
	LPD3DXMESH tempMesh;
	mMesh->CloneMesh(D3DXMESH_32BIT | D3DXMESH_MANAGED, Crealysm_dxmath::vtxdecl, mD3ddev, &tempMesh);

	HRESULT hr = D3DXComputeTangentFrameEx(tempMesh,
		 								D3DDECLUSAGE_TEXCOORD, 0,
										D3DDECLUSAGE_BINORMAL, 0,
										D3DDECLUSAGE_TANGENT, 0,
										D3DDECLUSAGE_NORMAL, 0,
										D3DXTANGENT_GENERATE_IN_PLACE,
										(DWORD*)mAdjacencyBuffer->GetBufferPointer(),
										// 0.01f, 0.25f, 0.01f,
										-1.01f, -0.01f, -1.01f,
										&tempMesh,
										NULL);
	if(FAILED(hr))
	{
		#ifdef _DEBUG
		OutputDebugString(DXGetErrorString(hr));
		OutputDebugString(L", ");
		OutputDebugString(DXGetErrorDescription(hr));
		OutputDebugString(L"\n");
		#endif

		MessageBox(NULL, err_tangent_xfile.c_str(), err_windowtext.c_str(), MB_OK);
		return false;
	}
	mMesh = tempMesh;
	tempMesh->Release();
	return true;
}

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!