From f4c57401f16f876b0d7dbd0b1f50cb48f37ffe18 Mon Sep 17 00:00:00 2001 From: Shon Ferguson <shonferg@users.sourceforge.net> Date: Fri, 29 Sep 2006 16:10:40 +0000 Subject: [PATCH] BindSkin no longer automatically clears transforms between the mesh and the root. Instead this can be done with the ApplySkinOffset function after all the shapes are in place. --- include/obj/NiGeometry.h | 15 ++++++++++ include/obj/NiSkinData.h | 2 ++ src/obj/NiGeometry.cpp | 60 ++++++++++++++++++++++++++++++++++------ src/obj/NiSkinData.cpp | 11 +++++++- 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/include/obj/NiGeometry.h b/include/obj/NiGeometry.h index a1042b24..54ae3313 100644 --- a/include/obj/NiGeometry.h +++ b/include/obj/NiGeometry.h @@ -50,7 +50,9 @@ public: * ancestor in the scenegraph. This becomes the skeleton root. */ 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 @@ -83,6 +85,19 @@ public: */ void ApplyTransforms(); + /* + * Propogates the transforms between this skin and the skeleton root, + * and then applies them to the verticies of this skin. Sets the overall + * skin data transform to the identity. + */ + void NiGeometry::ApplySkinOffset(); + + /* + * Used to determine whether this mesh is influenced by bones as a skin. + * \return true if this mesh is a skin, false otherwise. + */ + bool IsSkin(); + protected: list< Ref<NiNode> > ListAncestors( const Ref<NiNode> & leaf ) const; NI_GEOMETRY_MEMBERS diff --git a/include/obj/NiSkinData.h b/include/obj/NiSkinData.h index 5a061aa7..247f26f0 100644 --- a/include/obj/NiSkinData.h +++ b/include/obj/NiSkinData.h @@ -47,7 +47,9 @@ public: virtual list<NiObjectRef> GetRefs() const; virtual const Type & GetType() const; + void ResetOffsets( const Ref<NiGeometry> & owner ); Matrix44 GetOverallTransform() const; + void SetOverallTransform( const Matrix44 & transform ); uint GetBoneCount() const; Matrix44 GetBoneTransform( uint bone_index ) const; vector<SkinWeight> GetBoneWeights( uint bone_index ) const; diff --git a/src/obj/NiGeometry.cpp b/src/obj/NiGeometry.cpp index 8ffc6b4d..244df793 100644 --- a/src/obj/NiGeometry.cpp +++ b/src/obj/NiGeometry.cpp @@ -166,15 +166,6 @@ void NiGeometry::BindSkin( vector< Ref<NiNode> > bone_nodes ) { throw runtime_error("Failed to find suitable skeleton root."); } - //Ancestors[bone_nodes.size()] should now hold all nodes between (but not including) the - //skeleton root and this mesh. Cycle through and propogate their transforms - for ( list<NiNodeRef>::iterator it = ancestors[bone_nodes.size()].begin(); it != ancestors[bone_nodes.size()].end(); ++it ) { - (*it)->PropagateTransform(); - } - - //Now apply the transforms to the vertices and normals of this mesh - this->ApplyTransforms(); - //Create a skin instance using the bone and root data skinInstance = new NiSkinInstance( skeleton_root, bone_nodes ); @@ -182,6 +173,57 @@ void NiGeometry::BindSkin( vector< Ref<NiNode> > bone_nodes ) { skinInstance->SetSkinData( new NiSkinData( this ) ); }; +void NiGeometry::ApplySkinOffset() { + if ( GetParent() == NULL ) { + throw runtime_error("Attempted to apply skin transforms on a shape with no parent."); + } + + if ( skinInstance == NULL ) { + throw runtime_error("Attempted to apply skin transforms on a shape with no skin instance."); + } + + if ( skinInstance->GetSkinData() == NULL ) { + throw runtime_error("Attempted to apply skin transforms on a shape with no skin data."); + } + + //Get ancestors + list<NiNodeRef> ancestors; + ancestors = ListAncestors( GetParent() ); + + //Propogate transforms on ancestors below skeleton root + bool below_root = false; + + for ( list<NiNodeRef>::iterator it = ancestors.begin(); it != ancestors.end(); ++it ) { + if ( *it == skinInstance->GetSkeletonRoot() ) { + below_root = true; + continue; + } + if ( below_root ) { + cout << "Propogating transform of " << *it << endl; + (*it)->PropagateTransform(); + } + } + + //Now apply the transforms to the vertices and normals of this mesh + this->ApplyTransforms(); + + //Set the skin overall transform to the identity + skinInstance->GetSkinData()->SetOverallTransform( Matrix44::IDENTITY ); + + //Reset skin offsets + skinInstance->GetSkinData()->ResetOffsets( this ); +} + +bool NiGeometry::IsSkin() { + //Determine whether this is a skin by looking for a skin instance and + //skin data + if ( skinInstance != NULL && skinInstance->GetSkinData() != NULL ) { + return true; + } else { + return false; + } +} + list< Ref<NiNode> > NiGeometry::ListAncestors( const Ref<NiNode> & leaf ) const { if ( leaf == NULL ) { throw runtime_error("ListAncestors called with a NULL leaf NiNode Ref"); diff --git a/src/obj/NiSkinData.cpp b/src/obj/NiSkinData.cpp index 0187143b..a684e3fa 100644 --- a/src/obj/NiSkinData.cpp +++ b/src/obj/NiSkinData.cpp @@ -75,7 +75,16 @@ Matrix44 NiSkinData::GetOverallTransform() const { return Matrix44( translation, rotation, scale ); } +void NiSkinData::SetOverallTransform( const Matrix44 & transform ) { + transform.Decompose( translation, rotation, scale ); +} + NiSkinData::NiSkinData( const Ref<NiGeometry> & owner ) NI_SKIN_DATA_CONSTRUCT { + ResetOffsets( owner ); +} + +void NiSkinData::ResetOffsets( const Ref<NiGeometry> & owner ) { + //Get skin instance NiSkinInstanceRef skinInst = owner->GetSkinInstance(); @@ -85,7 +94,7 @@ NiSkinData::NiSkinData( const Ref<NiGeometry> & owner ) NI_SKIN_DATA_CONSTRUCT { boneList.resize( skinInst->GetBoneCount() ); vector< Ref<NiNode> > bone_nodes = skinInst->GetBones(); - + //--Calculate Overall Offset--// //Get TriBasedGeom world transform -- GitLab