From e7b03ae5ca1674d43b42dd7b8dc51b36b221ae39 Mon Sep 17 00:00:00 2001 From: Shon Ferguson <shonferg@users.sourceforge.net> Date: Tue, 13 Jun 2006 21:38:17 +0000 Subject: [PATCH] Fixed Matrix44::Inverse. GoToSkeletonBindPosition also works now as well. --- nif_math.cpp | 14 +++++---- nif_math.h | 2 +- niflib.cpp | 18 ++++++----- obj/NiAVObject.cpp | 2 +- obj/NiNode.cpp | 78 ++++++++++++++++++++++++++++++++-------------- 5 files changed, 74 insertions(+), 40 deletions(-) diff --git a/nif_math.cpp b/nif_math.cpp index b14c294f..490268ed 100644 --- a/nif_math.cpp +++ b/nif_math.cpp @@ -229,7 +229,7 @@ Matrix33 Matrix44::GetRotation() const { 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]); + scale[r] = Vector3( m[r][0], m[r][1], m[r][2] ).Magnitude(); //Normalize the row by dividing each factor by scale m[r][0] /= scale[r]; @@ -246,7 +246,7 @@ Vector3 Matrix44::GetScale() const { 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]); + scale[r] = Vector3( m[r][0], m[r][1], m[r][2] ).Magnitude(); } return Vector3( scale[0], scale[1], scale[2] ); } @@ -331,10 +331,10 @@ Matrix33 Matrix44::Submatrix( int skip_r, int skip_c ) const { Matrix33 sub; int i = 0, j = 0; for (int r = 0; r < 4; r++) { - if (r == skip_c) + if (r == skip_r) continue; for (int c = 0; c < 4; c++) { - if (c == skip_r) + if (c == skip_c) continue; sub[i][j] = (*this)[r][c]; j++; @@ -345,7 +345,7 @@ Matrix33 Matrix44::Submatrix( int skip_r, int skip_c ) const { return sub; } -float Matrix44::Adjunct( int skip_r, int skip_c ) const { +float Matrix44::Adjoint( int skip_r, int skip_c ) const { Matrix33 sub = Submatrix( skip_r, skip_c ); return pow(-1.0f, float(skip_r + skip_c)) * sub.Determinant(); } @@ -354,9 +354,11 @@ Matrix44 Matrix44::Inverse() const { Matrix44 result; float det = Determinant(); + cout << "Determinant: " << det << endl; for (int r = 0; r < 4; r++) { for (int c = 0; c < 4; c++) { - result[r][c] = Adjunct(r, c) / det; + //cout << "Adjoint(" << r << "," << c << "): " << Adjunct(r, c) << endl; + result[c][r] = Adjoint(r, c) / det; } } diff --git a/nif_math.h b/nif_math.h index 75c530cc..dc194656 100644 --- a/nif_math.h +++ b/nif_math.h @@ -727,7 +727,7 @@ struct Matrix44 { * \param skip_c The colum to skip. Must be a value between 0 and 3. * \return The adjunct obtained by skipping the indicated row and column. */ - NIFLIB_API float Adjunct( int skip_r, int skip_c ) const; + NIFLIB_API float Adjoint( int skip_r, int skip_c ) const; NIFLIB_API Matrix33 GetRotation() const; NIFLIB_API Vector3 GetScale() const; diff --git a/niflib.cpp b/niflib.cpp index 6865c23d..154c544b 100644 --- a/niflib.cpp +++ b/niflib.cpp @@ -336,21 +336,23 @@ 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? + + ////TODO: Make this an optional step? ////Build up the bind pose matricies into their world-space equivalents //NiAVObjectRef av_root = DynamicCast<NiAVObject>( FindRoot(blocks) ); //if ( av_root != NULL ) { // BuildUpBindPositions( av_root ); //} + //Send all skeleton roots to bind position + for (uint i = 0; i < blocks.size(); ++i) { + NiNodeRef node = DynamicCast<NiNode>(blocks[i]); + if ( node != NULL && node->IsSkeletonRoot() ) { + node->GoToSkeletonBindPosition(); + } + } + //TODO: Evaluate this and see if it can be moved to NiTriBasedGeom::FixLinks() //// Re-position any TriShapes with a SkinInstance //for (uint i = 0; i < blocks.size(); ++i) { diff --git a/obj/NiAVObject.cpp b/obj/NiAVObject.cpp index aa364926..f986c097 100644 --- a/obj/NiAVObject.cpp +++ b/obj/NiAVObject.cpp @@ -143,4 +143,4 @@ Vector3 NiAVObject::GetVelocity() const { void NiAVObject::SetVelocity( const Vector3 & n ) { velocity = n; -} \ No newline at end of file +} diff --git a/obj/NiNode.cpp b/obj/NiNode.cpp index c9974b1c..fbb1fea0 100644 --- a/obj/NiNode.cpp +++ b/obj/NiNode.cpp @@ -156,7 +156,7 @@ void NiNode::SetSkinFlag( bool n ) { } void NiNode::GoToSkeletonBindPosition() { - map<NiNodeRef, Matrix44> world_positions; + //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 ) { @@ -177,26 +177,51 @@ void NiNode::GoToSkeletonBindPosition() { throw runtime_error( "Bone counts in NiSkinInstance and attached NiSkinData must match" ); } - //Loop through all bones influing this skin + //Loop through all bones influencing 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 ); + //Matrix44 parent_offset( bone_data[i].translation, + // bone_data[i].rotation, + // bone_data[i].scale ); + Matrix44 parent_offset( + bone_data[i].rotation[0][0], bone_data[i].rotation[0][1], bone_data[i].rotation[0][2], 0.0f, + bone_data[i].rotation[1][0], bone_data[i].rotation[1][1], bone_data[i].rotation[1][2], 0.0f, + bone_data[i].rotation[2][0], bone_data[i].rotation[2][1], bone_data[i].rotation[2][2], 0.0f, + bone_data[i].translation.x, bone_data[i].translation.y, bone_data[i].translation.z, 1.0f + ); //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] ) { + cout << "Bone " << bones[j] << " has bone " << bones[i] << " as parent." << endl; //Node 2 has node 1 as a parent //Get child offset Matrix33 - Matrix44 child_offset( bone_data[j].translation, + /*Matrix44 child_offset( bone_data[j].translation, bone_data[j].rotation, - bone_data[j].scale ); + bone_data[j].scale );*/ + Matrix44 child_offset( + bone_data[j].rotation[0][0], bone_data[j].rotation[0][1], bone_data[j].rotation[0][2], 0.0f, + bone_data[j].rotation[1][0], bone_data[j].rotation[1][1], bone_data[j].rotation[1][2], 0.0f, + bone_data[j].rotation[2][0], bone_data[j].rotation[2][1], bone_data[j].rotation[2][2], 0.0f, + bone_data[j].translation.x, bone_data[j].translation.y, bone_data[j].translation.z, 1.0f + ); //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; Matrix44 inverse_co = child_offset.Inverse(); - world_positions[bones[j]] = inverse_co * parent_offset; + Matrix44 child_pos = inverse_co * parent_offset; + + //bones[j]->SetWorldBindPos( child_pos ); + bones[j]->SetLocalRotation( child_pos.GetRotation() ); + bones[j]->SetLocalScale( 1.0f ); + bones[j]->SetLocalTranslation( child_pos.GetTranslation() ); + + //cout << "Matrix: " << cout << "Translation: " << world_positions[bones[j]] << endl; + //cout << "Translation: " << world_positions[bones[j]].GetTranslation() << endl; + //cout << "Rotation: " << world_positions[bones[j]].GetRotation() << endl; + //cout << "Scale: " << world_positions[bones[j]].GetScale() << endl; } } } @@ -205,20 +230,25 @@ void NiNode::GoToSkeletonBindPosition() { //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 ); - } - + ////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 ) { + // if ( world_positions.find(it->first->GetParent()) != world_positions.end() ) { + // Matrix44 res_mat = world_positions[it->first] * world_positions[it->first->GetParent()].Inverse(); + + // //Store result in node's local transforms + // it->first->SetLocalRotation( Matrix33( + // res_mat[0][0], res_mat[0][1], res_mat[0][2], + // res_mat[1][0], res_mat[1][1], res_mat[1][2], + // res_mat[2][0], res_mat[2][1], res_mat[2][2] + // ) ); + // it->first->SetLocalTranslation( Vector3( res_mat[3][0], res_mat[3][1], res_mat[3][2] ) ); + // //Vector3 scale = res_mat.GetScale(); + // it->first->SetLocalScale( 1.0f );//scale.x + scale.y + scale.z / 3.0f ); + // } + //} } \ No newline at end of file -- GitLab