I use the D3DXComputeTangentFrame() function on a mesh loaded from a x-file. Then I create another finer mesh by using the first meshs' vertices and additional intermediate vertices. The new vertices use averaged normals and tex coords from the original mesh. The vertex order remains the same (CW). When I now do the D3DXComputeTangentFrame() on the new mesh, I get swapped binormal and tangent vectors in comparison to the original mesh. Does anybody have any inside about how that comes Thanks!
Two screenshots from the meshes saved to x-files and opened with the dx viewer:
Nico

D3DXComputeTangentFrame() question
mcrfanatic
I had this problem recently. D3DXCleanMesh() doesn't seem to solve all the cases that D3DXComputeTangentFrameEx() complains about.
In my case I just came up with a very simple option - remove the index buffer and clone all vertices. In my case this is acceptable as I'm dealing with only a few meshes and a relatively fill-rate bound setup (thus extra vertex transformations don't seem to matter) - but I'd be surprised if this were actually a good solution to use generically.
The mathematics behind computing a tangent frame for a given triangle isn't amazingly complex - I can't find them now, but I have seen it described online. Might well be worth implementing it yourself such that you can then identify (programmatically) which vertices need to be split.
hth
Jack
Mebo
Perhaps you misunderstood when I described the differences in the way adjacency is calculated. One method looks at the index buffer, and if two triangles have an edge with the same vertex id, then those triangles are adjacent across that edge. This is what is done by ConvertPointRepsToAdjacency when you pass in a NULL point rep.
The other method is to first look at the positions of the vertices, and vertices that are within a certain distance of each other are put in the same point rep. Then it calls ConvertPointRepsToAdjacency with that, this is what GenerateAdjacency does.
The reason that the second method is a bad default, is if you have a mesh where two triangles are physically connected but have different material properties (and likely a different parameterization), you may not want the tangent frame from one triangle to affect the tangent frame of the other triangle's vertices. What you want in this case is a crease, and this is what the default will give you. If your mesh is well constructed, with vertices duplicated only when necessary, then this will be okay. If not, then you'll have to generate adjacency the other way and possibly clean it up, adding creases where necessary.
So while it's true that there is one correct adjacency for a given mesh, it's not true that any single method that will generate the adjacency you need, and that's why we allow you to pass in an adjacency.
Gavin G. WANG
Well, ok, so the adjacency computed by ComputeTangentFrame() is wrong/incomplete
I'm a little confused. :)
cj74
Ed Phips
Thanks a lot for the explanation! Now it's clearer to me.
Nico
azouz
DarrellMe
It does compute it itself, but it uses the data in the index buffer to decide if vertices are the same (if it's the same vertex id, then it's the same), whereas GenerateAdjacency uses the position of the vertex to decide if it's the same.
When it generates the adjacency that way, apparently you're not always using the same vertex in adjacent triangles, and it thinks you've got bowties. Incidentally you can create the same adjacency that ComputeTangentFrame will by calling ConvertPointRepsToAdjacency with a NULL point rep.
Nutty
>> For this situation it's apparently not the adjacency you want, that doesn't mean it's wrong.
A mesh has only one unique adjaceny. So there cannot be two different adjacencies that are both correct. ;-)
theFaze
I just saw in teh debug output that the first tangent frame computation was not su’ccessful because a bowty was found. The output also tells me to use D3DXCleanMesh to remove the bowty. I tried, but D3DXComputeTangentFrame() still gives me the same error.
This is what I do:
DWORD* pAdjacency =
new DWORD[m_pMesh->GetNumFaces() * 3];m_pMesh->GenerateAdjacency(0.0, pAdjacency);
ID3DXMesh* cleanedMesh;
hr = D3DXCleanMesh( D3DXCLEAN_BOWTIES, m_pMesh, pAdjacency, &cleanedMesh, pAdjacency, NULL );
m_pMesh->Release();
m_pMesh = cleanedMesh;
hr = D3DXComputeTangentFrame( m_pMesh, NULL ); //get the error here
Does anybody have an idea how to solve this Thanks.
Nico
Chris Nahr
In the code snippet you posted, I noticed you're spending all of this time calculating your adjacency, but not passing it into ComputeTangentFrame.
You're going to need to call ComputeTangentFrameEx, which, admittedly is a formiddable function to call, with no less than 16 arguments. The documentation for ComputeTangentFrame, however, gives you all of the arguments that it passes into ComputeTangentFrameEx (click on show example in the remarks section), so you should be able to get reasonable behavior out of it. Otherwise if you don't do this, then it will keep complaining about bowties in your input mesh. This function also will split only the vertices that need to be split, and will return a new mesh, if that's what you want.
Sandy_MS
Priyaranjan
It works now, but I don't need to call CleanMesh at all. I just need to call D3DXComputeTangentFrameEx with the parameters of D3DXComputeTangentFrame plus the adjacency info I generated from the mesh. I think this behaviour is a little confusing. Why doesn't D3DXComputeTangentFrameEx computes the adjaceny info itself Also why does it tell me I should use CleanMesh to split vertices to remove bowties when I don't actually have to Also strange is that there is actually no bowtie in my mesh.