   MyComputeTangent() vs D3DXComputeTangent() error?
  Hi Everyone,  well I've been playing aroudn with computing my own tangent and binormal for use with bump mapping.Basically I used the info from the book: "mathematics for 3d game programming and computer graphics" p186 on computing the tangent.Also from:http://www.terathon.com/code/tangent.htmlNow after much fiddling with code...I'm pretty sure my code is right...but I've been comparing some values with the D3DXComputeTangent(..) API and seem to get very different results....is my algorithm right?  Is there a better way of doing it?Any ideas or further reading would be great :)The codes not very efficient, just interested in clarity, simplicity and most of all have it work :)Thanks for any ideas, help,Ben<code>/*struct MESH_VERTEX{D3DXVECTOR3 position; D3DXVECTOR3 normal; D3DXVECTOR2 tex0;// texture coordsD3DXVECTOR3 tangent;// tangent vector (basis vector s)D3DXVECTOR3 binormal;// binormal vector (basis vector t)};*/void CalculateTangents( MESH_VERTEX *pVertex,int   nVertices, const WORD *pTriangle,int   nTriangles){    D3DXVECTOR3 *tan = new D3DXVECTOR3[nVertices];    D3DXVECTOR3 *bin = new D3DXVECTOR3[nVertices];memset(tan, 0, sizeof(D3DXVECTOR3) * nVertices);memset(bin, 0, sizeof(D3DXVECTOR3) * nVertices);    for (long a = 0; a < nTriangles; a++)    {   long i1 = pTriangle[0];   long i2 = pTriangle[1];   long i3 = pTriangle[2];   D3DXVECTOR3 v1 = pVertex[i1].position;   D3DXVECTOR3 v2 = pVertex[i2].position;D3DXVECTOR3 v3 = pVertex[i3].position;   D3DXVECTOR2 w1 = pVertex[i1].tex0;D3DXVECTOR2 w2 = pVertex[i2].tex0;   D3DXVECTOR2 w3 = pVertex[i3].tex0; float x1 = v2.x - v1.x;float y1 = v2.y - v1.y;float z1 = v2.z - v1.z;   float x2 = v3.x - v1.x;   float y2 = v3.y - v1.y;   float z2 = v3.z - v1.z; float s1 = w2.x - w1.x;float t1 = w2.y - w1.y;   float s2 = w3.x - w1.x;   float t2 = w3.y - w1.y; float r = 1.0f / (s1 * t2 - s2 * t1);   D3DXVECTOR3 sdir((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,(t2 * z1 - t1 * z2) * r);   D3DXVECTOR3 tdir((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,(s1 * z2 - s2 * z1) * r);D3DXVec3Normalize(&sdir, &sdir);D3DXVec3Normalize(&tdir, &tdir);   tan[i1] += sdir;   tan[i2] += sdir;   tan[i3] += sdir; bin[i1] += tdir;   bin[i2] += tdir;   bin[i3] += tdir;// Save our tangent and binormalpVertex[i1].tangent  = sdir;pVertex[i2].tangent  = sdir;pVertex[i3].tangent  = sdir;pVertex[i1].binormal = tdir;pVertex[i2].binormal = tdir;pVertex[i3].binormal = tdir;   pTriangle+=3;    }  delete[] tan;    delete[] bin;}</code>   
Quote:Original post by bkenwrightHi Everyone,  well I've been playing aroudn with computing my own tangent and binormal for use with bump mapping.Basically I used the info from the book: "mathematics for 3d game programming and computer graphics" p186 on computing the tangent.Also from:http://www.terathon.com/code/tangent.htmlNow after much fiddling with code...I'm pretty sure my code is right...but I've been comparing some values with the D3DXComputeTangent(..) API and seem to get very different results....is my algorithm right?  Is there a better way of doing it?In a nutshell, D3DXCOmputeTangent does alot more complex things involving averaging neighboring triangles - including determining singularity groups and trying to do the best possible thing. Computing the Tangent frame for a triangle is a different thing then figuring it out for a vertex.;  Your code is correct, but you should add a normalization step after you've iterated over all of the triangles. Right now, your final tangents won't be unit length. The normalization in your loop isn't necessary and could actually make the tangents worse because you're no longer getting area-weighting.The DX code has a lot of options that can make it behave differently. I'm sure I read somewhere that DX doesn't perform the multiplication by 1.0f / (s1 * t2 - s2 * t1), which will result in bad tangents unless your texture handedness is what they expect everywhere.;  Actually, I just noticed that you're writing over the tangents for each vertex at the end of your loop. This will result in each vertex tangent being the tangent corresponding to the last triangle that uses it instead of the average. You need to run through a loop over all vertices after the loop over all triangles to move the added tangents from the tan and bin arrays to the pVertex array (and normalize at the same time). Don't write to pVertex inside the triangle loop.;  So the code look something like this with Eric's suggestions?struct MESH_VERTEX{    D3DXVECTOR3 position;    D3DXVECTOR3 normal;    D3DXVECTOR2 tex0;  // texture coords    D3DXVECTOR3 tangent;    // tangent vector (basis vector s)    D3DXVECTOR3 binormal;   // binormal vector (basis vector t)};void CalculateTangents(MESH_VERTEX *pVertex, int nVertices, const WORD *pTriangle, int nTriangles){    D3DXVECTOR3 *tan = new D3DXVECTOR3[nVertices];    D3DXVECTOR3 *bin = new D3DXVECTOR3[nVertices];    memset(tan, 0, sizeof(D3DXVECTOR3) * nVertices);    memset(bin, 0, sizeof(D3DXVECTOR3) * nVertices);    // Calculate tangents and binormals.    for (int i = 0; i    ;  Sorry the last post was by me...please disregard...dunno what happened.Anyway should the modified code with Eric's suggestions look something like this?<code>struct MESH_VERTEX{    D3DXVECTOR3 position;    D3DXVECTOR3 normal;    D3DXVECTOR2 tex0;  // texture coords    D3DXVECTOR3 tangent;    // tangent vector (basis vector s)    D3DXVECTOR3 binormal;   // binormal vector (basis vector t)};void CalculateTangents(MESH_VERTEX *pVertex, int nVertices, const WORD *pTriangle, int nTriangles){    D3DXVECTOR3 *tan = new D3DXVECTOR3[nVertices];    D3DXVECTOR3 *bin = new D3DXVECTOR3[nVertices];    memset(tan, 0, sizeof(D3DXVECTOR3) * nVertices);    memset(bin, 0, sizeof(D3DXVECTOR3) * nVertices);    // Calculate tangents and binormals.    for (int i = 0; i < nTriangles; ++i)    {   int i1 = pTriangle;<br>   int i2 = pTriangle;<br>   int i3 = pTriangle;<br><br>   D3DXVECTOR3 v1 = pVertex[i1].position;<br>   D3DXVECTOR3 v2 = pVertex[i2].position;<br>   D3DXVECTOR3 v3 = pVertex[i3].position;<br><br>   D3DXVECTOR2 w1 = pVertex[i1].tex0;<br>   D3DXVECTOR2 w2 = pVertex[i2].tex0;<br>   D3DXVECTOR2 w3 = pVertex[i3].tex0;<br><br>   float x1 = v2.x - v1.x;<br>   float y1 = v2.y - v1.y;<br>   float z1 = v2.z - v1.z;<br>   float x2 = v3.x - v1.x;<br>   float y2 = v3.y - v1.y;<br>   float z2 = v3.z - v1.z;<br><br>   float s1 = w2.x - w1.x;<br>   float t1 = w2.y - w1.y;<br>   float s2 = w3.x - w1.x;<br>   float t2 = w3.y - w1.y;<br><br>   float r = 1.0f / (s1 * t2 - s2 * t1);<br><br>   D3DXVECTOR3 sdir((t2 * x1 - t1 * x2) * r,<br>  (t2 * y1 - t1 * y2) * r,<br>  (t2 * z1 - t1 * z2) * r);<br><br>   D3DXVECTOR3 tdir((s1 * x2 - s2 * x1) * r,<br>  (s1 * y2 - s2 * y1) * r,<br>  (s1 * z2 - s2 * z1) * r);<br><br>   tan[i1] += sdir;<br>   tan[i2] += sdir;<br>   tan[i3] += sdir;<br><br>   bin[i1] += tdir;<br>   bin[i2] += tdir;<br>   bin[i3] += tdir;<br>    }<br><br>    // Save our tangents and binormals.<br>    for (int i = 0; i &lt; nTriangles; ++i)<br>    {<br>   int i1 = pTriangle;<br>   int i2 = pTriangle;<br>   int i3 = pTriangle;<br><br>   D3DXVec3Normalize(&tan[i1], &tan[i1]);<br>   D3DXVec3Normalize(&tan[i2], &tan[i2]);<br>   D3DXVec3Normalize(&tan[i3], &tan[i3]);<br><br>   pVertex[i1].tangent = tan[i1];<br>   pVertex[i2].tangent = tan[i2];<br>   pVertex[i3].tangent = tan[i3];<br><br>   D3DXVec3Normalize(&bin[i1], &bin[i1]);<br>   D3DXVec3Normalize(&bin[i2], &bin[i2]);<br>   D3DXVec3Normalize(&bin[i3], &bin[i3]);<br><br>   pVertex[i1].binormal = bin[i1];<br>   pVertex[i2].binormal = bin[i2];<br>   pVertex[i3].binormal = bin[i3];<br>    }<br><br>    delete[] tan;<br>    delete[] bin;<br>}<br>&lt;/code&gt;;Quote:Original post by dpoonAnyway should the modified code with Eric's suggestions look something like this?The second loop should be over the vertices, not the triangles:void CalculateTangents( MESH_VERTEX *pVertex,    int nVertices,    const WORD *pTriangle,    int nTriangles){    D3DXVECTOR3 *tan = new D3DXVECTOR3[nVertices];    D3DXVECTOR3 *bin = new D3DXVECTOR3[nVertices];    memset(tan, 0, sizeof(D3DXVECTOR3) * nVertices);    memset(bin, 0, sizeof(D3DXVECTOR3) * nVertices);    for (long a = 0; a < nTriangles; a++)    {   long i1 = pTriangle[0];   long i2 = pTriangle[1];   long i3 = pTriangle[2];   D3DXVECTOR3 v1 = pVertex[i1].position;   D3DXVECTOR3 v2 = pVertex[i2].position;   D3DXVECTOR3 v3 = pVertex[i3].position;   D3DXVECTOR2 w1 = pVertex[i1].tex0;   D3DXVECTOR2 w2 = pVertex[i2].tex0;   D3DXVECTOR2 w3 = pVertex[i3].tex0;   float x1 = v2.x - v1.x;   float y1 = v2.y - v1.y;   float z1 = v2.z - v1.z;   float x2 = v3.x - v1.x;   float y2 = v3.y - v1.y;   float z2 = v3.z - v1.z;   float s1 = w2.x - w1.x;   float t1 = w2.y - w1.y;   float s2 = w3.x - w1.x;   float t2 = w3.y - w1.y;   float r = 1.0f / (s1 * t2 - s2 * t1);   D3DXVECTOR3 sdir( (t2 * x1 - t1 * x2) * r,   (t2 * y1 - t1 * y2) * r,   (t2 * z1 - t1 * z2) * r);   D3DXVECTOR3 tdir( (s1 * x2 - s2 * x1) * r,   (s1 * y2 - s2 * y1) * r,   (s1 * z2 - s2 * z1) * r);   tan[i1] += sdir;   tan[i2] += sdir;   tan[i3] += sdir;   bin[i1] += tdir;   bin[i2] += tdir;   bin[i3] += tdir;   pTriangle+=3;    }   for (long a = 0; a < nVertices; a++)    {   D3DXVec3Normalize(&pVertex[a].tangent, &tan[a]);   D3DXVec3Normalize(&pVertex[a].binormal, &bin[a]);    }   delete[] tan;    delete[] bin;}