Advertisement Jump to content
Sign in to follow this  
AquaMacker

D3DXComputeTangentFrameEx problem

This topic is 1759 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 ~

 

D3DXComputeTangentFrameEx() is hard to use.

 

I use Full Vertex Model.

 

Let's see source...

 

D3DXCleanMesh()... hr = S_OK

D3DXValidMesh()... hr = S_OK

 

HRESULT hr = 

D3DXComputeTangentFrameEx( pMeshClean,
                                                       D3DDECLUSAGE_TEXCOORD, 0,
                                                       D3DDECLUSAGE_BINORMAL, 0,
                                                       D3DDECLUSAGE_TANGENT, 0,
                                                       0, 0,
                                                       D3DXTANGENT_GENERATE_IN_PLACE,
                                                       pAdjacencyClean,
                                                       0.01f, 0.25f, 0.01f,
                                                       &pMeshAfter,
                                                       0 );
hr is S_FALSE;

So...
 
I don't use "D3DXTANGENT_GENERATE_IN_PLACE" of option is hr = S_OK.
But vertex data is changed.
ex) -9.776716,0.000000,-9.890399 > 0.000000, -1.000000, 000000
 
How do I use exactly ?
 

Share this post


Link to post
Share on other sites
Advertisement

Just noting the hr != S_OK isn't enough information. Are you compiling with DEBUG? What errors are you getting? In the dx control panel, set the error reporting to maximum.

 

If D3DXTANGENT_GENERATE_IN_PLACE doesn't work, it's likely that the data generated won't fit in the input mesh. So, don't use that option! Generate the new mesh, release the old mesh and use the new one.

Edited by Buckeye

Share this post


Link to post
Share on other sites

while i don't use d3dx libs, I'll give this a shot based on this doc.

 

Your U and V are in the wrong order, and should be swapped. dwUPartialOutSemantic [in] should be tangent, while dwVPartialOutSemantic [in] should be binormal. Also push both tangent and normal and binormal to the same index.

 

if your vertex format is something like this position, normal, tangent, bitangent, texcoords. then your call to compute tangent frame ex should reflect that. the indices should reflect the offset from the start of the vertex to the semantic location. you are using 0, so everything is overwrighting the position data. I would assume that indices should be 8 for tangent, 12 for bitangent, and 16 for normal based on the vertex format i described above. Read the doc I linked above and try to understand the meaning of each of the functions inputs.

Share this post


Link to post
Share on other sites

then your call to compute tangent frame ex should reflect that. the indices should reflect the offset from the start of the vertex to the semantic location.

That's not correct.

 

Be careful, Burnt_Fyr. That parameter is NOT the vertex declaration offset, it is the SEMANTIC index. If he has a single D3DDECLUSAGE_TANGENT, then the index is 0.

 

However, you're likely correct about the common usage order.

 

The examples I've seen (and used) are, in order in the D3DXComputeTangentFrameEx call:

 

D3DDECLUSAGE_TEXCOORD, 0,

D3DDECLUSAGE_TANGENT, 0,

D3DDECLUSAGE_BINORMAL, 0,

D3DDECLUSAGE_NORMAL, 0

 

EDIT: @AquaMacker - if you have the June 2010 SDK, take a look at the D3D9 examples LocalDeformablePRT and ParallaxOcclusionMapping for using D3DXComputeTangentFrameEx.

Edited by Buckeye

Share this post


Link to post
Share on other sites

 


then your call to compute tangent frame ex should reflect that. the indices should reflect the offset from the start of the vertex to the semantic location.

That's not correct.

 

Be careful, Burnt_Fyr. That parameter is NOT the vertex declaration offset, it is the SEMANTIC index. If he has a single D3DDECLUSAGE_TANGENT, then the index is 0.

 

However, you're likely correct about the common usage order.

 

Good call, this is why I should not attempt to help anyone before morning coffee.

Share this post


Link to post
Share on other sites
D3DXComputeTangentFrameEx( pMesh,
                                           D3DDECLUSAGE_TEXCOORD, 0,
                                           D3DDECLUSAGE_TANGENT, 0,
                                           D3DDECLUSAGE_BINORMAL, 0,
                                           D3DDECLUSAGE_NORMAL, 0,
                                           0,
                                           pAdjacency,
                                           -1.01f,-0.01f,-1.01f,
                                           &pMeshAfter,
                                           0 );
this method DONE.

And
Vertex data error is my fault. ??;
 
But
ComputeTangent is well done but tangent value is not confirm yet.
Edited by AquaMacker

Share this post


Link to post
Share on other sites

Hi.

Not sure if you still have the problem, but here's my use case (Which works including tangents :))

 

1. load the mesh using D3DXLoadMeshFromX

2. create temporary mesh and optimize loaded mesh to it

3. swap meshes, release temporary mesh

 

4. check for existance of normals, binormals and tangents in the mesh

(by getting the vertexdeclaration from the loaded mesh)

5. if no binormals or tangents are there, generate them as followed:

 

A. create temporary mesh

B. clone loaded/ optimized mesh to temporary mesh

Important note: this is needed using your wanted vertex declaration, including binormals and tangents

(the declaration from the loaded mesh won't work because it has no declarations for binormals and tangents)

C. compute tangentframe using temporary/ cloned mesh

D. swap the temporary with the target mesh

E. release temporary mesh

 

Here's my code:

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,
								 &mNumMaterials,
								 &mMesh))) return false;
	
	LPD3DXMESH tempMesh;
	if(FAILED(mMesh->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)mAdjacencyBuffer->GetBufferPointer(), (DWORD*)mAdjacencyBuffer->GetBufferPointer(), NULL, NULL, &tempMesh)))	
		return false;

	mMesh = tempMesh;
	tempMesh->Release();

	/** 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;
}

/**************************************************************************************/
/***							CALCULATE TANGENT FRAME								***/
/*** ==> usage: when a mesh doesn't contain tangents and binormals					***/
/*** ==> creates the tangentframe, resulting in a new mesh, same D3DXMESH member	***/
/**************************************************************************************/

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,
										NULL,
										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
    LPD3DXMESH tempMesh;
    if(FAILED(mMesh->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)mAdjacencyBuffer->GetBufferPointer(), (DWORD*)mAdjacencyBuffer->GetBufferPointer(), NULL, NULL, &tempMesh)))    
        return false;

    mMesh = tempMesh;
    tempMesh->Release();

@cozzie: Do you get memory leaks with that code? I'm curious because you keep releasing the temporary meshes you've just created and don't seem to release the original mMesh.

 

E.g.,

mMesh->Optimize(..., &tmpMesh)  creates tmpMesh as the optimized mesh. The sequence after that call should be:

mMesh->Release(); // get rid of the old mesh
mMesh = tmpMesh; // keep the newly created mesh
Edited by Buckeye

Share this post


Link to post
Share on other sites
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!