diff --git a/include/nif_math.h b/include/nif_math.h index fed4d26c0ec39536960c2a1f5bf87c9f1f063b03..2a2b7ce2d45f3bf99d1b09d601708c5f0169d079 100644 --- a/include/nif_math.h +++ b/include/nif_math.h @@ -651,6 +651,12 @@ struct Matrix44 { */ NIFLIB_API Matrix44( const Vector3 & translate, const Matrix33 & rotation, float scale ); + /*! This constructor allows a 4x4 transform matrix to be initalized from a + * a 3x3 rotation matrix. + * \param[in] rotation The 3x3 rotation matrix. + */ + NIFLIB_API Matrix44( const Matrix33 & rotation ); + /*! This function can be used to set all values in this matrix at the same time. * \param[in] m11 The value to set at row 1, column 1. * \param[in] m12 The value to set at row 1, column 2. diff --git a/include/obj/NiGeometry.h b/include/obj/NiGeometry.h index 65304f295b0ac4bf718862f6f1344e376d0963b9..c1929af1833262a3514cb509a2d466d4c1591b3e 100644 --- a/include/obj/NiGeometry.h +++ b/include/obj/NiGeometry.h @@ -69,7 +69,7 @@ public: string GetShader() const; void SetShader( const string & n ); - vector<Vector3> GetSkinInfluencedVertices() const; + void GetSkinDeformation( vector<Vector3> & vertices, vector<Vector3> & normals ) const; protected: list< Ref<NiNode> > ListAncestors( const Ref<NiNode> & leaf ) const; diff --git a/src/ComplexShape.cpp b/src/ComplexShape.cpp index a95d09caefed65a61aaeae4b491353d98128ab62..8f81dbe068108d5294d36ad474ccfab6f6b93831 100644 --- a/src/ComplexShape.cpp +++ b/src/ComplexShape.cpp @@ -234,15 +234,17 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) { //cout << "Get Data" << endl; //Get Data - vector<Vector3> shapeVerts; + vector<Vector3> shapeVerts; + vector<Vector3> shapeNorms; //If this is a skin influenced mesh, get vertices from niGeom if ( (*geom)->GetSkinInstance() != NULL ) { - shapeVerts = (*geom)->GetSkinInfluencedVertices(); + (*geom)->GetSkinDeformation( shapeVerts, shapeNorms ); } else { shapeVerts = geomData->GetVertices(); + shapeNorms = geomData->GetNormals(); } - vector<Vector3> shapeNorms = geomData->GetNormals(); + vector<Color4> shapeColors = geomData->GetColors(); vector< vector<TexCoord> > shapeUVs( geomData->GetUVSetCount() ); for ( unsigned i = 0; i < shapeUVs.size(); ++i ) { diff --git a/src/nif_math.cpp b/src/nif_math.cpp index 7ee458b2fb9b5c4547fd8008943209952ef2e120..699d57af3dd02aaad26be8239d4782cac4db541b 100644 --- a/src/nif_math.cpp +++ b/src/nif_math.cpp @@ -232,6 +232,15 @@ Matrix44::Matrix44() { *this = Matrix44::IDENTITY; } +Matrix44::Matrix44( const Matrix33 & r ) { + //Set this matrix with rotate and translate information + Matrix44 & m = *this; + m[0][0] = r[0][0]; m[0][1] = r[0][1]; m[0][2] = r[0][2]; m[0][3] = 0.0f; + m[1][0] = r[1][0]; m[1][1] = r[1][1]; m[1][2] = r[1][2]; m[1][3] = 0.0f; + m[2][0] = r[2][0]; m[2][1] = r[2][1]; m[2][2] = r[2][2]; m[2][3] = 0.0f; + m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f; +} + Matrix44::Matrix44( const Vector3 & t, const Matrix33 & r, float scale ) { //Set up a matrix with rotate and translate information Matrix44 rt; diff --git a/src/obj/NiGeometry.cpp b/src/obj/NiGeometry.cpp index e13997bf0acfb71f314227cf3a91dbe795d60f4a..ced04547db5de77d5363bc93ea8f3dacfc983243 100644 --- a/src/obj/NiGeometry.cpp +++ b/src/obj/NiGeometry.cpp @@ -211,7 +211,7 @@ void NiGeometry::UnbindSkin() { skinInstance = NULL; } -vector<Vector3> NiGeometry::GetSkinInfluencedVertices() const { +void NiGeometry::GetSkinDeformation( vector<Vector3> & vertices, vector<Vector3> & normals ) const{ //--Get required data & insure validity--// NiGeometryDataRef geom_data = GetData(); @@ -245,11 +245,14 @@ vector<Vector3> NiGeometry::GetSkinInfluencedVertices() const { } //Get the vertices & bone nodes - vector<Vector3> vertices = geom_data->GetVertices(); + vector<Vector3> in_verts = geom_data->GetVertices(); + vector<Vector3> in_norms = geom_data->GetNormals(); + vector<NiNodeRef> bone_nodes = skin_inst->GetBones(); - //Set up an aray to hold the transformed vertices - vector<Vector3> skin_verts( vertices.size()); + //Set up output arrays to hold the transformed vertices and normals + vertices.resize( in_verts.size() ); + normals.resize( in_norms.size() ); //Transform vertices into position based on skin data Matrix44 root_world = skel_root->GetWorldTransform(); @@ -259,19 +262,29 @@ vector<Vector3> NiGeometry::GetSkinInfluencedVertices() const { Matrix44 bone_offset = skin_data->GetBoneTransform(i); vector<SkinWeight> weights = skin_data->GetBoneWeights(i); Matrix44 vert_trans = bone_offset * bone_world; + Matrix44 norm_trans = Matrix44( vert_trans.GetRotation() ); for ( uint j = 0; j < weights.size(); ++j ) { uint index = weights[j].index; float weight = weights[j].weight; - skin_verts[index] += (vert_trans * vertices[index] ) * weight; + if ( index < vertices.size() ) { + vertices[index] += (vert_trans * in_verts[index] ) * weight; + } + if ( index < normals.size() ) { + normals[index] += (norm_trans * in_norms[index] ) * weight; + } } } //Transform all vertices to final position - for ( uint i = 0; i < skin_verts.size(); ++i ) { - skin_verts[i] = geom_world.Inverse() * skin_verts[i]; + Matrix44 geom_world_inv = geom_world.Inverse(); + Matrix44 geom_world_inv_rot = Matrix44( geom_world_inv.GetRotation() ); + for ( uint i = 0; i < vertices.size(); ++i ) { + vertices[i] = geom_world_inv * vertices[i]; + } + for ( uint i = 0; i < normals.size(); ++i ) { + normals[i] = geom_world_inv_rot * normals[i]; + //normals[i] = normals[i].Normalized(); } - - return skin_verts; } // Calculate bounding sphere using minimum-volume axis-align bounding box. Its fast but not a very good fit.