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

Added a SetBoneWeights function to NiTriBasedGeom which automatically...

Added a SetBoneWeights function to NiTriBasedGeom which automatically calculates the correct bone center and radius.
The NiSkinData::SetBoneWeights function now requires the radius and center as arguments.
parent 34a49abd
No related branches found
No related tags found
No related merge requests found
......@@ -447,17 +447,21 @@ Ref<NiAVObject> ComplexShape::Split( Ref<NiNode> & parent ) const {
shapes[shape_num]->BindSkin( shapeInfluences );
NiSkinInstanceRef skinInst = shapes[shape_num]->GetSkinInstance();
for ( unsigned int inf = 0; inf < shapeInfluences.size(); ++inf ) {
shapes[shape_num]->SetBoneWeights( inf, shapeWeights[ shapeInfluences[inf] ] );
}
if ( skinInst != NULL ) {
NiSkinDataRef skinData = skinInst->GetSkinData();
//NiSkinInstanceRef skinInst = shapes[shape_num]->GetSkinInstance();
if ( skinData != NULL ) {
for ( unsigned int inf = 0; inf < shapeInfluences.size(); ++inf ) {
skinData->SetBoneWeights( inf, shapeWeights[ shapeInfluences[inf] ] );
}
}
}
//if ( skinInst != NULL ) {
// NiSkinDataRef skinData = skinInst->GetSkinData();
// if ( skinData != NULL ) {
// for ( unsigned int inf = 0; inf < shapeInfluences.size(); ++inf ) {
// skinData->SetBoneWeights( inf, shapeWeights[ shapeInfluences[inf] ] );
// }
// }
//}
}
//Next Shape
......
......@@ -61,12 +61,16 @@ vector<SkinWeight> NiSkinData::GetBoneWeights( uint bone_index ) const {
return boneList[bone_index].vertexWeights;
}
void NiSkinData::SetBoneWeights( uint bone_index, const vector<SkinWeight> & n ) {
void NiSkinData::SetBoneWeights( uint bone_index, const vector<SkinWeight> & n, Vector3 center, float radius ) {
if ( bone_index > boneList.size() ) {
throw runtime_error( "The specified bone index was larger than the number of bones in this NiSkinData." );
}
boneList[bone_index].vertexWeights = n;
boneList[bone_index].unknown4Floats[0] = center.x;
boneList[bone_index].unknown4Floats[1] = center.y;
boneList[bone_index].unknown4Floats[2] = center.z;
boneList[bone_index].unknown4Floats[3] = radius;
}
Matrix44 NiSkinData::GetOverallTransform() const {
......
......@@ -51,7 +51,7 @@ 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 );
void SetBoneWeights( uint bone_index, const vector<SkinWeight> & n, Vector3 center, float radius );
protected:
NI_SKIN_DATA_MEMBERS
......
......@@ -259,4 +259,74 @@ vector<Vector3> NiTriBasedGeom::GetSkinInfluencedVertices() const {
}
return skin_verts;
}
void NiTriBasedGeom::SetBoneWeights( uint bone_index, const vector<SkinWeight> & n ) {
if ( n.size() == 0 ) {
throw runtime_error( "You must specify at least one weight value." );
}
NiSkinInstanceRef skinInst = GetSkinInstance();
if ( skinInst == NULL ) {
throw runtime_error( "You must bind a skin before setting vertex weights. No NiSkinInstance found." );
}
NiSkinDataRef skinData = skinInst->GetSkinData();
if ( skinData == NULL ) {
throw runtime_error( "You must bind a skin before setting vertex weights. No NiSkinData found." );
}
NiTriBasedGeomDataRef geomData = GetData();
if ( geomData == NULL ) {
throw runtime_error( "Attempted to set weights on a mesh with no geometry data." );
}
//Get vertex array
vector<Vector3> vertices = geomData->GetVertices();
//--Calculate center & radius--//
//Set lows and highs to first vertex
Vector3 lows = vertices[ n[0].index ];
Vector3 highs = vertices[ n[0].index ];
//Iterate through the vertices, adjusting the stored values
//if a vertex with lower or higher values is found
for ( unsigned int i = 0; i < n.size(); ++i ) {
const Vector3 & v = vertices[ n[i].index ];
if ( v.x > highs.x ) highs.x = v.x;
else if ( v.x < lows.x ) lows.x = v.x;
if ( v.y > highs.y ) highs.y = v.y;
else if ( v.y < lows.y ) lows.y = v.y;
if ( v.z > highs.z ) highs.z = v.z;
else if ( v.z < lows.z ) lows.z = v.z;
}
//Now we know the extent of the shape, so the center will be the average
//of the lows and highs
Vector3 center = highs + lows / 2.0f;
//The radius will be the largest distance from the center
Vector3 diff;
float dist2(0.0f), maxdist2(0.0f);
for ( unsigned int i = 0; i < n.size(); ++i ) {
const Vector3 & v = vertices[ n[i].index ];
diff = center - v;
dist2 = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
if ( dist2 > maxdist2 ) maxdist2 = dist2;
};
float radius = sqrt(maxdist2);
//Translate center by bone matrix
center = skinData->GetBoneTransform( bone_index ) * center;
skinData->SetBoneWeights( bone_index, n, center, radius );
}
\ No newline at end of file
......@@ -48,6 +48,13 @@ public:
*/
void BindSkin( vector< Ref<NiNode> > bone_nodes );
void UnbindSkin();
/*!
* Sets the skin weights in the attached NiSkinData object.
* The version on this class calculates the center and radius of
* each set of affected vertices automatically.
*/
void SetBoneWeights( uint bone_index, const vector<SkinWeight> & n );
Ref<NiSkinInstance> GetSkinInstance() const;
Ref<NiTriBasedGeomData> GetData() const;
......
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