Computing normals for weighted vertices (vertex skinning)

This topic is 4963 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hello, I'm wondering how to compute vertex normals when using vertex skinning? I would like to pre-compute normals from vertex weights in order to get final vertex normals like I get final vertices:
for( i = 0; i < _numVerts; ++i ) {
Vector3f finalVertex = kZeroVectorf;
Vector3f finalNormal = kZeroVectorf;

// Calculate final vertex to draw with weights
for( int j = 0; j < _verts->countWeight; ++j ) {
const Weight_t *pWeight = _weights[ _verts->startWeight + j ];
const Joint_t *pJoint = skel->getJoint( pWeight->joint );

// Calculate transformed vertex for this weight
Vector3f wv = pWeight->pos;
pJoint->orient.rotate( wv );

// The sum of all pWeight->bias should be 1.0
finalVertex += (pJoint->pos + wv) * pWeight->bias;

Vector3f wn = pWeight->norm;
pJoint->orient.rotate( wn );

finalNormal += wn * pWeight->bias;
}

_vertexArray[0] = finalVertex._x;
_vertexArray[1] = finalVertex._y;
_vertexArray[2] = finalVertex._z;

_normalArray[0] = finalNormal._x;
_normalArray[1] = finalNormal._y;
_normalArray[2] = finalNormal._z;
}

What I want is to compute pWeight->norm, which is the weighted normal associated to a weighted vertex, preferably at loading time. Perhaps I'm wrong and this is not a good idea... But then I would like to know how to compute these normals without having to rebuild all triangle normals at rendering time, then averaging them for vertices, etc.

Share on other sites
Hey V3rt3x,

I think you're going about it the wrong way. You only need to compute the normals for each vertex in its bind pose. When you multiple the normal by the bones final combined transformation it will transform the normal to the correct space.

So just use the models original normals with all the frames original transforms.

Share on other sites
The bind pose? is it that the bind pose?

I'm using the MD5 model format, but vertices have ”multiple positions” stored separately with the weight factor and joint index (in order to get access to quaternion orientation and joint's position).

struct Md5Vertex_t{  float st[2]; // Texture coordinates  int startWeight; // Start index weights  int countWeight; // Number of weights};struct Md5Weight_t{  int joint; // Joint index  float bias; // Weight factor  Vector3f pos;  Vector3f norm; // what I would like in my dreams (o_o)};

So if I want to compute normals I need to use a Skeleton because a vertex weights give a position depending on their joint...

I'm completely lost with theses weight positions... In books I have the position is the same but there are multiple transformation matrices (one for each bone). Here we have multiple positions and multiple matrices :(

Share on other sites
I got the solution at doom3world :-)

http://www.doom3world.org/phpbb2/viewtopic.php?p=100174#100020

Problem solved.

Share on other sites
Well, there are 2 good ways to do it.

You can apply the rotation of the different bones to the normal (not the translation!) and scale by the respective weights, BUT you're not going to have a unit-length normal after this step so you'll need to normalize.

Or, a lot of ps2 games do this:
Just transform the normal by the most heavily weighted bone. If there isn't scaling on the bone (which is true 99% of the time), you don't need to re-normalize the normal, so in many cases this is super cheap to do and there isn't significant visual difference. It's especially easy if you use the convention that the most heavily weighted bone is stored as the first weight/idx.

Share on other sites
I opted for the first method you have described.

• What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 15
• 9
• 11
• 9
• 9
• Forum Statistics

• Total Topics
634133
• Total Posts
3015747
×