Skip to content
Snippets Groups Projects
Commit 2dfaa0c8 authored by Shon Ferguson's avatar Shon Ferguson
Browse files

Added NiGeometry::NormalizeSkinWeights function to ensure all skin weights add up to one on export.

ComplexShape::Split now cuts out weights below 0.1 and normalizes the result.
Fixed a bug which could cause NiSkinInstance to try to call a function on a NiNode that was in the midst of destruction.
Removed some cout statements.
parent f4c57401
No related branches found
No related tags found
No related merge requests found
......@@ -92,6 +92,8 @@ public:
*/
void NiGeometry::ApplySkinOffset();
void NormalizeSkinWeights();
/*
* Used to determine whether this mesh is influenced by bones as a skin.
* \return true if this mesh is a skin, false otherwise.
......
......@@ -53,10 +53,12 @@ public:
uint GetBoneCount() const;
Matrix44 GetBoneTransform( uint bone_index ) const;
vector<SkinWeight> GetBoneWeights( uint bone_index ) const;
void SetBoneWeights( uint bone_index, const vector<SkinWeight> & n, Vector3 center, float radius );
void SetBoneWeights( uint bone_index, const vector<SkinWeight> & n, Vector3 center, float radius );
Ref<NiSkinPartition> GetSkinPartition() const;
void SetSkinPartition(Ref<NiSkinPartition> skinPartition);
void NormalizeWeights( unsigned numVertices );
Ref<NiSkinPartition> GetSkinPartition() const;
void SetSkinPartition(Ref<NiSkinPartition> skinPartition);
protected:
NI_SKIN_DATA_MEMBERS
......
......@@ -827,7 +827,7 @@ Ref<NiAVObject> ComplexShape::Split( Ref<NiNode> & parent, Matrix44 & transform,
SkinWeight sk;
for ( map<NiNodeRef, float>::iterator wt = cv->weights.begin(); wt != cv->weights.end(); ++wt ) {
//Only record influences that make a noticable contribution
if ( wt->second > 0.0f ) {
if ( wt->second > 0.1f ) {
sk.index = vert_index;
sk.weight = wt->second;
if ( shapeWeights.find( wt->first ) == shapeWeights.end() ) {
......@@ -871,6 +871,8 @@ Ref<NiAVObject> ComplexShape::Split( Ref<NiNode> & parent, Matrix44 & transform,
shapes[shape_num]->SetBoneWeights( inf, shapeWeights[ shapeInfluences[inf] ] );
}
shapes[shape_num]->NormalizeSkinWeights();
if ( max_bones_per_partition > 0 ) {
shapes[shape_num]->GenHardwareSkinInfo( max_bones_per_partition );
}
......
......@@ -199,7 +199,6 @@ void NiGeometry::ApplySkinOffset() {
continue;
}
if ( below_root ) {
cout << "Propogating transform of " << *it << endl;
(*it)->PropagateTransform();
}
}
......@@ -214,6 +213,20 @@ void NiGeometry::ApplySkinOffset() {
skinInstance->GetSkinData()->ResetOffsets( this );
}
void NiGeometry::NormalizeSkinWeights() {
if ( IsSkin() == false ) {
throw runtime_error( "NormalizeSkinWeights called on a mesh that is not a skin." );
}
NiSkinDataRef niSkinData = this->GetSkinInstance()->GetSkinData();
NiGeometryDataRef niGeomData = this->GetData();
if ( niGeomData == NULL ) {
throw runtime_error( "NormalizeSkinWeights called on a mesh with no geometry data." );
}
niSkinData->NormalizeWeights( niGeomData->GetVertexCount() );
}
bool NiGeometry::IsSkin() {
//Determine whether this is a skin by looking for a skin instance and
//skin data
......
......@@ -18,13 +18,13 @@ NiNode::NiNode() NI_NODE_CONSTRUCT {
}
NiNode::~NiNode() {
//Clear Children
ClearChildren();
//Unbind any attached skins
//Unbind any attached skins - must happen before children are cleared
for ( list<NiSkinInstance*>::iterator it = skins.begin(); it != skins.end(); ++it ) {
(*it)->SkeletonLost();
}
//Clear Children
ClearChildren();
}
void NiNode::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
......
......@@ -41,8 +41,10 @@ void NiObject::AddRef() const {
void NiObject::SubtractRef() const {
_ref_count--;
if ( _ref_count < 1 ) {
//cout << this->GetIDString() << " died." << endl;
//string id = this->GetIDString();
//cout << id << " is being destroyed." << endl;
delete this;
//cout << "Destruction of " << id << " complete." << endl;
}
}
......
......@@ -241,8 +241,6 @@ void NiPixelData::SetColors( const vector<Color4> & new_pixels, bool generate_mi
//Pack pixel data
for (uint i = 0; i < mipmaps.size(); ++i ) {
cout << "Width: " << mipmaps[i].width << " Height: " << mipmaps[i].height << " Offset: " << mipmaps[i].offset << endl;
if ( i > 0 ) {
//Allocate space to store re-sized image.
Color4 * resized = new Color4[ mipmaps[i].width * mipmaps[i].height ];
......@@ -250,7 +248,6 @@ void NiPixelData::SetColors( const vector<Color4> & new_pixels, bool generate_mi
//Visit every other pixel in each row and column of the previous image
for ( uint w = 0; w < mipmaps[i-1].width; w+=2 ) {
for ( uint h = 0; h < mipmaps[i-1].height; h+=2 ) {
//cout << "w: " << w << " h: " << h << endl;
Color4 & av = resized[(h/2) * mipmaps[i].width + (w/2)];
//Start with the value of the current pixel
......
......@@ -83,6 +83,42 @@ NiSkinData::NiSkinData( const Ref<NiGeometry> & owner ) NI_SKIN_DATA_CONSTRUCT {
ResetOffsets( owner );
}
void NiSkinData::NormalizeWeights( unsigned numVertices ) {
vector<float> totals(numVertices);
vector<int> counts(numVertices);
//Set all totals to 1.0 and all counts to 0
for ( unsigned v = 0; v < numVertices; ++v ) {
totals[v] = 1.0f;
counts[v] = 0;
}
//Calculate the total error for each vertex by subtracting the weight from
//each bone from the starting total of 1.0
//Also count the number of bones affecting each vertex
for ( unsigned b = 0; b < boneList.size(); ++b ) {
for ( unsigned w = 0; w < boneList[b].vertexWeights.size(); ++w ) {
SkinWeight & sw = boneList[b].vertexWeights[w];
totals[sw.index] -= sw.weight;
counts[sw.index]++;
}
}
//Divide all error amounts by the number of bones affecting that vertex to
//get the amount of error that should be distributed to each bone.
for ( unsigned v = 0; v < numVertices; ++v ) {
totals[v] = totals[v] / float(counts[v]);
}
//Distribute the calculated error to each weight
for ( unsigned b = 0; b < boneList.size(); ++b ) {
for ( unsigned w = 0; w < boneList[b].vertexWeights.size(); ++w ) {
SkinWeight & sw = boneList[b].vertexWeights[w];
sw.weight += totals[sw.index];
}
}
}
void NiSkinData::ResetOffsets( const Ref<NiGeometry> & owner ) {
//Get skin instance
......
......@@ -47,17 +47,15 @@ NiSkinInstance::NiSkinInstance( Ref<NiNode> skeleton_root, vector< Ref<NiNode> >
}
NiSkinInstance::~NiSkinInstance() {
//Probably not necessary, and not very safe
////Unflag any bones that were part of this skin instance
//for ( uint i = 0; i < bones.size(); ++i ) {
// cout << "Bone " << i << ":";
// cout << bones[i]->GetIDString() << endl;
// bones[i]->SetSkinFlag(false);
//}
//Unflag any bones that were part of this skin instance
for ( uint i = 0; i < bones.size(); ++i ) {
bones[i]->SetSkinFlag(false);
}
//Inform Skeleton Root of detatchment and clear it.
if ( skeletonRoot != NULL ) {
skeletonRoot->RemoveSkin( this );
skeletonRoot = NULL;
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment