Every tutorial on the net appears to forget that it’s a coding technique, and instead chooses to describe it in wierd symbols which are lost on me.
Basically, I have the model set up and rendering, mapped correctly(I.e normal map matching the texture) with dot3 etc.
And for each vertex I have,
the vector from vertex to light source,
light position.
Vertex Normal X,Y
Vertex U,V(Texture map coords)
Could someone please, just describe in code(C++/Basic, anything but ‘The T is the derivite of the P over the magnitude of The l’ I will shoot you. (j/k, it’s just frustrating ))
I have the transforms set up already, for the tangent matrix,
so I really just need the code/help for the bit that fills/computes the tangent matrix.
On a 4x4 matrix,
The rest I have done, it’s just this one bit.
I have read every tutorial and am now using my final life-line to ask you guys here. Any help will be rewarded with instant karma and riches beyond your wildest imagination. Or maybe just a thank you and a smile
Here’s the code as in, using Blitz3D, with a custom gl engine I wrote eventually but I just want to get it up and running before I make the switch(I.e so i know it’s not a fault of my c++ code, which is much harder to debug)
The vector trasnforms etc are the ATI vector lib converted over.
tmx = the tanget matrix, this needs filling on a per vert basis I think.
Local tmx#[16]
tmx[0]=1
tmx[1]=0
tmx[2]=0
tmx[3]=0
tmx[4]=0
tmx[5]=-1
tmx[6]=0
tmx[7]=0
tmx[8]=0
tmx[9]=0
tmx[10]=1
tmx[11]=0
tmx[12]=0
tmx[13]=0
tmx[14]=0
tmx[15]=1
Local lpES#[3]; // light position in Eye space
Local lpOS#[3]; // light position in Object space
Local lv#[3]; // vector from vertex to light
Local lv_ts#[3]; // light vector in tangent space
Local modelViewMatrix#[16];
Local modelViewMatrixInverse#[16]
For b.bump=Each bump
sc=CountSurfaces( b\mesh)
For s=1 To sc
srf=GetSurface( b\mesh,s)
vc=CountVertices(srf)
For v=0 To vc-1
vx#=VertexX(srf,v)
vy#=VertexY(srf,v)
vz#=VertexZ(srf,v)
It used the dreaded ‘Where $$ = the unit of’…and suddenly it made as much sense as a drunk sailor, collapsed on the floor mumbling something about moby dick.
Not a lot
So please guys, in return I’ll be more than happy to help in other areas, like provide you with a rag-doll/hitman 2 type engine as a .dll (ultra fast, vertlet sys)
Here is a function I wrote a few years ago now that computes the tangent, binormal and normal to use with tangent space perpixel lighting/bumpmapping. The parameter list is rather nasty looking but it gets the job done.
// Make a normal based on the tangent and binormal b/c it may be different than the poly’s
// normal, this normal being computed here is better
normal = CrossProduct( tangent, binormal );
Normalize( normal );
// Make tangent space vectors orthogonal by recomputing the binormal with the corrected
// tangent space normal.
binormal = CrossProduct( tangent, normal );
Normalize( binormal );
// Check the generated normal from the tangent and binormal vectors against the polygon normal
if( DotProduct( normal, polynormal ) < 0.0f )
{
normal.x = -normal.x;
normal.y = -normal.y;
normal.z = -normal.z;
}
}
This was based off a similar function I think Cass of nvidia wrote in one of those glh headers. I looked at the nvidia function to make the one I orginially wrote a bit faster.
-SirKnight
[This message has been edited by SirKnight (edited 01-18-2004).]
SirKnight, Once it fills the tanget,bi-normal,and normal (The last three pars)
I assume I load these into the tangent matrix with which I transform the vector?
In what order though?
I mean,
row 1=
Row =2 =TAgnet vector
Row =3 Bi normal
row 4=?
But thanks for the function, should be a big help in coming to terms with my inability to grasp simple maths
Great tutorial, it is so much more…english…than the rest.
Doesn’t explain how to actually generate the tangents though unless I’m missing something, but the function sirKnight provided does that, so it’s not a prob.
Unfortunately, every online tutorial, presentation, and piece of sample code I’ve ever seen for calculating tangent vectors is just plain wrong. Please do not use the Nvidia method because it will not work correctly for all cases (and it’s slow). If you really want to understand how to calculate tangents correctly for arbitrary geometry, please read Mathematics for 3D Game Programming and Computer Graphics, Section 6.8.3:
You will find that the method described there is very elegant. It’s derivation is straightforward and doesn’t make use of calculus. Here’s the actual implementation that I use:
for (long a = 0; a < vertexCount; a++)
{
const Vector3D& n = normal[a];
const Vector3D& t = tan1[a];
tangent[a] = (t - n * (n * t)).Normalize();
tangent[a].w = (n % t * tan2[a] < 0.0F) ? -1.0F : 1.0F;
}
delete[] tan1;
}
As described in the book, the w-coordinate of the tangent represents the handedness of the basis set at each vertex. The normal direction is not modified, but a quick Gram-Schmidt step makes sure that the tangent and normal are orthogonal.
[This message has been edited by Eric Lengyel (edited 01-18-2004).]
I second that. At first I “fought” through the NVMeshMender code to make it compatible. After some tweaking I got it to work, but some triangles had zero tangents and binormals.
After taking your code and adapting it, everything works fine!!
In one of the NV whitepapers they wrote about some issues like texture mirroring & co. Any ideas wether I should care about this with your code? I have indeed some mirrored texture coordinates…
Omg that NVMeshMender thing was such a pain in the arse to get going. I spent so long hacking at it to not only compile wihtout a million errors, but to get the results I needed. I never really used it a whole lot, the last time I did I was just beginning into perpixel lighting and still wasn’t 100% on what I was doing. I finally just used that old function I posted above for everything. Now that I have this new code thanks to Eric, which is a MUCH better solution to finding tangents for meshes, that old code is now useless to me.
ScottManDeath, you say you do have some mirrored texture coordinates, have you not tested the code to see if it handles them correctly?
That’s interesting, as everybody i’ve been fighting with the tangent space generation algorithm for quite some time now, tried 3 or 4 versions, all different, found on the web, and none working in 100% of the cases. I’ll be sure to try that one when i’ll have some time. Sounds quite simple compared to the others. But does it handle mirrored UVs?
One thing I should add: I am using triangles, the converting to trianglestrips will be done later, so it could be then when I have to blend vertices and tangent spaces that mirrored texcoords make some problems when they zero out themeselves. But with I guess now that all tangent spaces are orientated proper, this should lead to no problem.
ScottManDeath : maybe you meant cross rather than dot ?
I strongly recommend Eric’s book, that is very short in explanations, but very clear. You have to read it slowly sevral times, but after, you completely understand everything on the topic. And this is true for almost all topics (Eric, now please send me your second edition for free )
(% is cross product, * is dot product) sets the w-coordinate of the tangent vector to 1 if B = N x T, and to -1 if B = -N x T. So, just send the 3D vector N and the 4D vector T to your vertex program and calculate
B = (N x T) * T.w,
ignoring the w-coordinates for the cross product.
ScottManDeath: The line
tangent[a] = (t - n * (n * t)).Normalize();
is the Gram-Schmidt step that makes sure the tangent is orthogonal to the normal. (The n * t is a dot product, and the n * () is a vector-scalar multiplication.)
I know I could change my code because of the rules for the cross product. But as I calculate my binormals on the host, that doesn’t matter. And I figured out the meaning of % and *; some time ago, one of my vector classes used also % for cross.
Thanks for the detailed explanation.
nv_meshmender has needed a fix for a long time! We’ve finally done it. I want to thank Eric for his math which I’m using in the new version of nv_meshmender.
I’ve also modified the interface so it should be much easier to use now, and hopefully should handle all the corner cases.
I’ve been testing with a few developers over the last couple of weeks privately working kinks out, and will be posting it to the nvidia website very soon.
Eric, one thing I would have found helpful in your book when going over this again, would have been an explicit discussion on triangles that were degenerate, both in texture and in real space. And how to smooth them properly. I have the first edition though, maybe you’ve updated it in the second edition?