PDA

View Full Version : Tangent space and animation

paw
05-24-2003, 04:25 PM
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

jwatte
05-24-2003, 07:58 PM
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.

paw
05-25-2003, 02:28 AM
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

jwatte
05-25-2003, 07:05 PM
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.

paw
05-26-2003, 02:07 AM
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

paw
05-26-2003, 04:02 AM
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

jwatte
05-26-2003, 08:19 AM
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?

SirKnight
05-26-2003, 10:43 AM
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

SirKnight
05-26-2003, 10:52 AM
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

paw
05-26-2003, 01:19 PM
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