Original Post
I'm not sure whether this is the correct forum, but anyway. Okay, I've been ripping my hair out trying to get this working over the last few days. I'm trying to get a simple per pixel dot3 shader working for a point light (no attenuation at the moment), but I just can't get it to look right :-(. It SORT of works, as in I can see the diffuse component of the dot3 operation changing as the light moves around, but it doesn't look good at all (everything looks black as the light gets closer to the polygon, and the illumination angles seem all wrong). I have a feeling that its something to do with transforming the light direction vector into tangent space. Can someone have a look at my code and see if theres any obvious (or not so obvious) flaws? Oh yeah, I'm using DX8.1.... Here is the tangent vector generation code, taken from the NVSDK: Here is my vertex shader: And finally the pixel shader (no base coolour texture yet, just outputting the diffuse): Any help to regain my sanity is muchly appreciated :).
// Calculate the tangent vector for each vertex
for (uint32 iTri = 0; iTri < nNumTris; iTri++)
{
Vector edge01, edge02, cp;
uint16 TriIndex[3];
TriIndex[0] = pIndices[iTri];
TriIndex[1] = pIndices[iTri+1];
TriIndex[2] = pIndices[iTri+2];
assert((TriIndex[0] < nNumVertices) && (TriIndex[1] < nNumVertices) && (TriIndex[2] < nNumVertices));
Dot3Vertex& v0 = pVertices[TriIndex[0]];
Dot3Vertex& v1 = pVertices[TriIndex[1]];
Dot3Vertex& v2 = pVertices[TriIndex[2]];
// x, s, t
edge01 = Vector( v1.m_vPos.x - v0.m_vPos.x, v1.m_fU - v0.m_fU, v1.m_fV - v0.m_fV );
edge02 = Vector( v2.m_vPos.x - v0.m_vPos.x, v2.m_fU - v0.m_fU, v2.m_fV - v0.m_fV );
cp = edge01.Cross(edge02);
if ( fabs(cp.x) > SMALL_FLOAT )
{
v0.m_vTangent.x += -cp.z / cp.x;
v1.m_vTangent.x += -cp.z / cp.x;
v2.m_vTangent.x += -cp.z / cp.x;
}
// y, s, t
edge01 = Vector( v1.m_vPos.y - v0.m_vPos.y, v1.m_fU - v0.m_fU, v1.m_fV - v0.m_fV );
edge02 = Vector( v2.m_vPos.y - v0.m_vPos.y, v2.m_fU - v0.m_fU, v2.m_fV - v0.m_fV );
cp = edge01.Cross(edge02);
if ( fabs(cp.x) > SMALL_FLOAT )
{
v0.m_vTangent.y += -cp.z / cp.x;
v1.m_vTangent.y += -cp.z / cp.x;
v2.m_vTangent.y += -cp.z / cp.x;
}
// z, s, t
edge01 = Vector( v1.m_vPos.z - v0.m_vPos.z, v1.m_fU - v0.m_fU, v1.m_fV - v0.m_fV );
edge02 = Vector( v2.m_vPos.z - v0.m_vPos.z, v2.m_fU - v0.m_fU, v2.m_fV - v0.m_fV );
cp = edge01.Cross(edge02);
if ( fabs(cp.x) > SMALL_FLOAT )
{
v0.m_vTangent.z += -cp.z / cp.x;
v1.m_vTangent.z += -cp.z / cp.x;
v2.m_vTangent.z += -cp.z / cp.x;
}
}
// Normalize all the tangents
for (uint32 iVert = 0; iVert < nNumVertices; iVert++)
{
Dot3Vertex& v = pVertices[iVert];
v.m_vTangent = v.m_vTangent.Normalize();
}
vs.1.1
// c0-c3 - world*view*proj
// c8 - light position(In object space)
// c9 - 1 / lightRange
// c10 - view position
// v0 pos
// v1 normal
// v2 tangent
// v3 colour
// v4 uv
// r3 reserved for light dir
// r4 reserved for camera dir
// r5 reserved for half angle
// r6 reserved for binormal
def c30, 1,1,1,1
def c31, 0.5, 0.5, 0.5, 0.5
def c32, 0,0,0,1
// Get direction to the light and normalize
sub r3, c8, v0
dp3 r3.w, r3.xyz, r3.xyz
rsq r3.w, r3.w
mul r3.xyz, r3.xyz, r3.w
// Get the direction to the camera and normalize
sub r4, c10, v0
dp3 r4.w, r4.xyz, r4.xyz
rsq r4.w, r4.w
mul r4.xyz, r4.xyz, r4.w
// Generate the binormal S by cross product
mov r7, v2
mov r8, v1
mul r1,-r7.zxy,r8.yzx
mad r6,-r7.yzx,r8.zxy,-r1
// Transform the light vector
dp3 r10.x, r6, r3 // binormal
dp3 r10.y, v2, r3 // tangent
dp3 r10.z, v1, r3 // normal
mov r10.w, c30.w
mov r3, r10
// Multiply by a half to bias, then add half
//mad r3, r3, c31, c31
// Output everything
mov oT0, v4 // texture coord
mov oT1, v4
m4x4 oPos, v0, c0 // Position
mov oD0, r3 // light dir
ps.1.1
tex t0 // normal map
dp3 r0, t0_bx2, v0_bx2 // Dot(normal, light direction)