Hi,
I have a bumpmapped model which uses tangent space to render the bumps. Now if I want to animate my model, do I have to recalculate tangent space for each frame? I guess the must be a faster way. Anyone know?
//Regards, Paw
Hi,
I have a bumpmapped model which uses tangent space to render the bumps. Now if I want to animate my model, do I have to recalculate tangent space for each frame? I guess the must be a faster way. Anyone know?
//Regards, Paw
Your tangent space basis would turn the normal into pre-animated space. You then have to skin the normal you get out of the normal map, just like you skin the position.
Because this is done per fragment, you could skin the tangent bases and interpolate and normalize each basis vector. This makes it no more expensive in the fragment shader, and only a little bit more expensive in the vertex shader.
Ok, so I have to do this for each vector in the tangent basis?
v.x += (b.rot[0] * w.x + b.rot[3] * w.y + b.rot[6] * w.z + b.pos[0]) * w.t;
v.z += (b.rot[1] * w.x + b.rot[4] * w.y + b.rot[7] * w.z + b.pos[1]) * w.t;
v.y += (b.rot[2] * w.x + b.rot[5] * w.y + b.rot[8] * w.z + b.pos[2]) * w.t;
-paw
Do not add the translation part of the matrices. Only use the rotational part.
Oh, and this won’t work right if you use shear or nonlinear scale in your matrix; if so, then you have to use the transpose of the inverse of the matrix instead.
Ok, you mean like this:
void CMD5::BuildVertices(CVector3 *tangents, CVector3 *normals)
{
for (int i = 0; i < m_nMeshes; i++)
{
Mesh& mesh = m_pMeshes[i];
for (int j = 0; j < mesh.nb_vertices; j++)
{
Vertex& v = mesh.vertices[j];
v.x = 0;
v.y = 0;
v.z = 0;
CVector3 &tan = tangents[j];
CVector3 &norm = normals[j];
for (int k = 0; k < v.weight_count; k++)
{
Weight& w = mesh.weights[v.weight_index + k];
Bone& b = m_Bones[w.bone];
v.x += (b.rot[0] * w.x + b.rot[3] * w.y + b.rot[6] * w.z + b.pos[0]) * w.t;
v.z += (b.rot[1] * w.x + b.rot[4] * w.y + b.rot[7] * w.z + b.pos[1]) * w.t;
v.y += (b.rot[2] * w.x + b.rot[5] * w.y + b.rot[8] * w.z + b.pos[2]) * w.t;
tan.m_vertex[0] += (b.rot[0] * tan.m_vertex[0] + b.rot[3] * tan.m_vertex[1] + b.rot[6] * tan.m_vertex[2]) * w.t;
tan.m_vertex[1] += (b.rot[1] * tan.m_vertex[0] + b.rot[4] * tan.m_vertex[1] + b.rot[7] * tan.m_vertex[2]) * w.t;
tan.m_vertex[2] += (b.rot[2] * tan.m_vertex[0] + b.rot[5] * tan.m_vertex[1] + b.rot[8] * tan.m_vertex[2]) * w.t;
norm.m_vertex[0] += (b.rot[0] * norm.m_vertex[0] + b.rot[3] * norm.m_vertex[1] + b.rot[6] * norm.m_vertex[2]) * w.t;
norm.m_vertex[1] += (b.rot[1] * norm.m_vertex[0] + b.rot[4] * norm.m_vertex[1] + b.rot[7] * norm.m_vertex[2]) * w.t;
norm.m_vertex[2] += (b.rot[2] * norm.m_vertex[0] + b.rot[5] * norm.m_vertex[1] + b.rot[8] * norm.m_vertex[2]) * w.t;
}
tan.Normalize();
norm.Normalize();
}
}
}
Something or wrong here.
-Paw
Sorry, I mean like this:
void CMD5::BuildVertices(CVector3 *tangents, CVector3 *normals)
{
for (int i = 0; i < m_nMeshes; i++)
{
Mesh& mesh = m_pMeshes[i];
for (int j = 0; j < mesh.nb_vertices; j++)
{
Vertex& v = mesh.vertices[j];
v.x = 0;
v.y = 0;
v.z = 0;
CVector3 &tang = tangents[j];
CVector3 &norm = normals[j];
CVector3 newNormal = CVector3(0, 0, 0);
CVector3 newTangent = CVector3(0, 0, 0);
for (int k = 0; k < v.weight_count; k++)
{
Weight& w = mesh.weights[v.weight_index + k];
Bone& b = m_Bones[w.bone];
v.x += (b.rot[0] * w.x + b.rot[3] * w.y + b.rot[6] * w.z + b.pos[0]) * w.t;
v.z += (b.rot[1] * w.x + b.rot[4] * w.y + b.rot[7] * w.z + b.pos[1]) * w.t;
v.y += (b.rot[2] * w.x + b.rot[5] * w.y + b.rot[8] * w.z + b.pos[2]) * w.t;
newTangent.m_vertex[0] += (b.rot[0] * tang.m_vertex[0] + b.rot[3] * tang.m_vertex[1] + b.rot[6] * tang.m_vertex[2]) * w.t;
newTangent.m_vertex[1] += (b.rot[1] * tang.m_vertex[0] + b.rot[4] * tang.m_vertex[1] + b.rot[7] * tang.m_vertex[2]) * w.t;
newTangent.m_vertex[2] += (b.rot[2] * tang.m_vertex[0] + b.rot[5] * tang.m_vertex[1] + b.rot[8] * tang.m_vertex[2]) * w.t;
newNormal.m_vertex[0] += (b.rot[0] * norm.m_vertex[0] + b.rot[3] * norm.m_vertex[1] + b.rot[6] * norm.m_vertex[2]) * w.t;
newNormal.m_vertex[1] += (b.rot[1] * norm.m_vertex[0] + b.rot[4] * norm.m_vertex[1] + b.rot[7] * norm.m_vertex[2]) * w.t;
newNormal.m_vertex[2] += (b.rot[2] * norm.m_vertex[0] + b.rot[5] * norm.m_vertex[1] + b.rot[8] * norm.m_vertex[2]) * w.t;
}
newNormal.Normalize();
newTangent.Normalize();
norm = newNormal;
tang = newTangent;
}
}
}
Do you see whats wrong here?
-paw
your variable v is set to a reference to the mesh position, and then cleared. Hopefully, the mesh position you clear is not also one you also use for input.
Also, I’m assuming “tangents” and “normals” are also part of the “mesh” struct?
I don’t understand why the “weight” has z, y and z parts that you use as input for position. Is that special to the file format you’re working on?
Originally posted by jwatte:
I don’t understand why the “weight” has z, y and z parts that you use as input for position. Is that special to the file format you’re working on?
This is the doom 3 md5 format.
-SirKnight
Here is a page I just found that may be usefull: http://www.gamasutra.com/features/20030325/fernando_05.shtml
Notice in the vertex program close to the bottom of the page where they do this:
netPosition += weight[i] * bonePosition;
netNormal += weight[i] * boneNormal;
This is the same technique you would use to also skin the tangent and binormal. So it would perhaps look something like this:
netPosition += weight[i] * bonePosition;
netNormal += weight[i] * boneNormal;
netTangent += weight[i] * boneTangent;
netBinormal += weight[i] * boneBinormal;
Of course you would have to compute boneTangent and boneBinormal just like boneNormal was done.
-SirKnight
netPosition += weight[i] * bonePosition;netNormal += weight[i] * boneNormal;netTangent += weight[i] * boneTangent;netBinormal += weight[i] * boneBinormal;
This is done in the code above. The w.t are the weight[i].
-paw