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

Tried to implement GoToSkeletonBindPosition but it doesn't work.

parent d6dff93f
No related branches found
No related tags found
No related merge requests found
......@@ -217,6 +217,46 @@ Matrix44::Matrix44( const Vector3 & t, const Matrix33 & r, float scale ) {
*this = s * rt;
}
Matrix33 Matrix44::GetRotation() const {
const Matrix44 & t = *this;
Matrix33 m( t[0][0], t[0][1], t[0][2],
t[1][0], t[1][1], t[1][2],
t[2][0], t[2][1], t[2][2]
);
//--Extract Scale from first 3 rows--//
float scale[3];
for (int r = 0; r < 3; ++r) {
//Get scale for this row
scale[r] = sqrt(m[r][0] * m[r][0] + m[r][1] * m[r][1] + m[r][2] * m[r][2]);
//Normalize the row by dividing each factor by scale
m[r][0] /= scale[r];
m[r][1] /= scale[r];
m[r][2] /= scale[r];
}
//Return result
return m;
}
Vector3 Matrix44::GetScale() const {
const Matrix44 & m = *this;
float scale[3];
for (int r = 0; r < 3; ++r) {
//Get scale for this row
scale[r] = sqrt(m[r][0] * m[r][0] + m[r][1] * m[r][1] + m[r][2] * m[r][2]);
}
return Vector3( scale[0], scale[1], scale[2] );
}
Vector3 Matrix44::GetTranslation() const {
const Matrix44 & m = *this;
return Vector3( m[3][0], m[3][1], m[3][2] );
}
Matrix44 Matrix44::operator*( const Matrix44 & rh ) const {
return Matrix44(*this) *= rh;
}
......
......@@ -729,7 +729,11 @@ struct Matrix44 {
*/
NIFLIB_API float Adjunct( int skip_r, int skip_c ) const;
//undocumented
NIFLIB_API Matrix33 GetRotation() const;
NIFLIB_API Vector3 GetScale() const;
NIFLIB_API Vector3 GetTranslation() const;
//undocumented, may be removed
NIFLIB_API void AsFloatArr( float out[4][4] ) {
out[0][0] = rows[0][0]; out[0][1] = rows[0][1]; out[0][2] = rows[0][2]; out[0][3] = rows[0][3];
out[1][0] = rows[1][0]; out[1][1] = rows[1][1]; out[1][2] = rows[1][2]; out[1][3] = rows[1][3];
......
......@@ -336,6 +336,14 @@ vector<NiObjectRef> ReadNifList( istream & in ) {
blocks[i]->FixLinks( blocks, link_stack, version, user_version );
}
//TODO: Make this an optional step?
for (uint i = 0; i < blocks.size(); ++i) {
NiNodeRef node = DynamicCast<NiNode>(blocks[i]);
if ( node != NULL && node->IsSkeletonRoot() ) {
node->GoToSkeletonBindPosition();
}
}
//TODO: No longer necessary?
////Build up the bind pose matricies into their world-space equivalents
//NiAVObjectRef av_root = DynamicCast<NiAVObject>( FindRoot(blocks) );
......
......@@ -5,6 +5,7 @@ All rights reserved. Please see niflib.h for licence. */
#include "NiAVObject.h"
#include "NiDynamicEffect.h"
#include "NiSkinInstance.h"
#include "NiSkinData.h"
//Definition of TYPE constant
const Type NiNode::TYPE("NiNode", &NI_NODE_PARENT::TYPE );
......@@ -14,6 +15,11 @@ NiNode::NiNode() NI_NODE_CONSTRUCT {}
NiNode::~NiNode() {
//Clear Children
ClearChildren();
//Unbind any attached skins
for ( list<NiSkinInstance*>::iterator it = skins.begin(); it != skins.end(); ++it ) {
(*it)->SkeletonLost();
}
}
void NiNode::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
......@@ -93,10 +99,6 @@ bool NiNode::IsSkinInfluence() const {
return ((flags & 8) == 0);
}
void NiNode::GoToSkeletonBindPosition() {
//TODO:: Implement GoToSkeletonBindPosition()
}
void NiNode::AddSkin( NiSkinInstance * skin_inst ) {
//Ensure that all bones are below this node on the scene graph
vector<NiNodeRef> bones = skin_inst->GetBones();
......@@ -151,4 +153,72 @@ void NiNode::SetSkinFlag( bool n ) {
//Requested value is different, flip bit
flags ^= 8;
}
}
void NiNode::GoToSkeletonBindPosition() {
map<NiNodeRef, Matrix44> world_positions;
//Loop through all attached skins, straightening the skeleton on each
for ( list<NiSkinInstance*>::iterator it = skins.begin(); it != skins.end(); ++it ) {
//Get Bone list and Skin Data
vector<NiNodeRef> bones = (*it)->GetBones();
NiSkinDataRef skin_data = (*it)->GetSkinData();
if ( skin_data == NULL ) {
//There's no skin data for this skin instance; skip it.
continue;
}
//Get bone data from NiSkinData class
vector<SkinData> bone_data = skin_data->GetBoneData();
//Make sure the counts match
if ( bones.size() != bone_data.size() ) {
throw runtime_error( "Bone counts in NiSkinInstance and attached NiSkinData must match" );
}
//Loop through all bones influing this skin
for ( uint i = 0; i < bones.size(); ++i ) {
//Get current offset Matrix for this bone
Matrix44 parent_offset( bone_data[i].translation,
bone_data[i].rotation,
bone_data[i].scale );
//Loop through all bones again, checking for any that have this bone as a parent
for ( uint j = 0; j < bones.size(); ++j ) {
if ( bones[j]->GetParent() == bones[i] ) {
//Node 2 has node 1 as a parent
//Get child offset Matrix33
Matrix44 child_offset( bone_data[j].translation,
bone_data[j].rotation,
bone_data[j].scale );
//Do calculation to get correct bone postion in relation to parent
Matrix44 inverse_co = child_offset.Inverse();
world_positions[bones[j]] = inverse_co * parent_offset;
}
}
}
}
//All the world positoins have been calculated, so use them to set the local
//positoins
//Put skeleton root into world positions if it's not already there
if ( world_positions.find( this ) == world_positions.end() ) {
world_positions[this] = GetWorldTransform();
}
//Now loop through all nodes in the world_positions map
for ( map< NiNodeRef, Matrix44>::iterator it = world_positions.begin(); it != world_positions.end(); ++it ) {
Matrix44 res_mat = world_positions[it->first] * world_positions[it->first->GetParent()].Inverse();
//Store result in node's local transforms
it->first->SetLocalRotation( res_mat.GetRotation() );
it->first->SetLocalTranslation( res_mat.GetTranslation());
Vector3 scale = res_mat.GetScale();
it->first->SetLocalScale( 1.0f );//scale.x + scale.y + scale.z / 3.0f );
}
}
\ No newline at end of file
......@@ -37,3 +37,21 @@ const Type & NiSkinData::GetType() const {
return TYPE;
};
void NiSkinData::SetBoneData( const vector<SkinData> & n ) {
boneList = n;
}
vector<SkinData> NiSkinData::GetBoneData() const {
return boneList;
}
void NiSkinData::SetOverallTransform( const Matrix44 & n ) {
translation = n.GetTranslation();
rotation = n.GetRotation();
Vector3 s = n.GetScale();
scale = s.x + s.y + s.z / 3.0f;
}
Matrix44 NiSkinData::GetOverallTransform() const {
return Matrix44( translation, rotation, scale );
}
\ No newline at end of file
......@@ -33,6 +33,12 @@ public:
virtual void FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version );
virtual list<NiObjectRef> GetRefs() const;
virtual const Type & GetType() const;
void SetOverallTransform( const Matrix44 & n );
Matrix44 GetOverallTransform() const;
void SetBoneData( const vector<SkinData> & n );
vector<SkinData> GetBoneData() const;
protected:
NI_SKIN_DATA_MEMBERS
};
......
......@@ -28,6 +28,11 @@ string NiSkinInstance::asString( bool verbose ) const {
void NiSkinInstance::FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
NI_SKIN_INSTANCE_FIXLINKS
//Inform newly fixed skeleton root of attachment
if ( skeletonRoot != NULL ) {
skeletonRoot->AddSkin( this );
}
}
list<NiObjectRef> NiSkinInstance::GetRefs() const {
......@@ -94,4 +99,15 @@ Ref<NiSkinPartition> NiSkinInstance::GetSkinPartition() const {
void NiSkinInstance::SetSkinPartition( const Ref<NiSkinPartition> & n ) {
skinPartition = n;
}
void NiSkinInstance::SkeletonLost() {
skeletonRoot = NULL;
//Clear bone list
bones.clear();
//Destroy skin data
data = NULL;
skinPartition = NULL;
}
\ No newline at end of file
......@@ -62,6 +62,12 @@ public:
Ref<NiSkinPartition> GetSkinPartition() const;
void SetSkinPartition( const Ref<NiSkinPartition> & n );
/*!
* Called by skeleton root NiNode when it self destructs to inform this skin
* instance that the skeleton has been lost. Should not be called directly.
*/
void SkeletonLost();
protected:
NI_SKIN_INSTANCE_MEMBERS
};
......
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