Пример #1
0
// Deform the vertex array according to the links contained in the mesh and the skinning type.
void fbxLoader2::ComputeSkinDeformation(FbxAMatrix& pGlobalPosition, FbxMesh* pMesh, FbxTime& pTime, FbxPose* pPose, int frame)
{
	FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(0, FbxDeformer::eSkin);
	FbxSkin::EType lSkinningType = lSkinDeformer->GetSkinningType();

	if(lSkinningType == FbxSkin::eLinear || lSkinningType == FbxSkin::eRigid)
	{
		ComputeLinearDeformation(pGlobalPosition, pMesh, pTime, pPose, frame);
	}
	else if(lSkinningType == FbxSkin::eDualQuaternion)
	{
		int i = 0;
		ComputeDualQuaternionDeformation(pGlobalPosition, pMesh, pTime, pPose, frame);
	}
	else if(lSkinningType == FbxSkin::eBlend)
	{
		int lVertexCount = pMesh->GetControlPointsCount();

		FbxVector4* lVertexArrayLinear = new FbxVector4[lVertexCount];
		memcpy(lVertexArrayLinear, pMesh->GetControlPoints(), lVertexCount * sizeof(FbxVector4));

		FbxVector4* lVertexArrayDQ = new FbxVector4[lVertexCount];
		memcpy(lVertexArrayDQ, pMesh->GetControlPoints(), lVertexCount * sizeof(FbxVector4));

		ComputeLinearDeformation(pGlobalPosition, pMesh, pTime, pPose, frame);
		ComputeDualQuaternionDeformation(pGlobalPosition, pMesh, pTime, pPose, frame);
	}
}
Пример #2
0
void FBXSceneEncoder::loadSkin(FbxMesh* fbxMesh, Model* model)
{
    const int deformerCount = fbxMesh->GetDeformerCount();
    for (int i = 0; i < deformerCount; ++i)
    {
        FbxDeformer* deformer = fbxMesh->GetDeformer(i);
        if (deformer->GetDeformerType() == FbxDeformer::eSkin)
        {
            FbxSkin* fbxSkin = FbxCast<FbxSkin>(deformer);

            MeshSkin* skin = new MeshSkin();

            vector<string> jointNames;
            vector<Node*> joints;
            vector<Matrix> bindPoses;

            const int clusterCount = fbxSkin->GetClusterCount();
            for (int j = 0; j < clusterCount; ++j)
            {
                FbxCluster* cluster = fbxSkin->GetCluster(j);
                assert(cluster);
                FbxNode* linkedNode = cluster->GetLink();
                if (linkedNode && linkedNode->GetSkeleton())
                {
                    const char* jointName = linkedNode->GetName();
                    assert(jointName);
                    jointNames.push_back(jointName);
                    Node* joint = loadNode(linkedNode);
                    assert(joint);
                    joints.push_back(joint);

                    FbxAMatrix matrix;
                    cluster->GetTransformLinkMatrix(matrix);
                    Matrix m;
                    copyMatrix(matrix.Inverse(), m);
                    bindPoses.push_back(m);
                }
            }
            skin->setJointNames(jointNames);
            skin->setJoints(joints);
            skin->setBindPoses(bindPoses);
            model->setSkin(skin);
            break;
        }
    }
}
Пример #3
0
void fbxLoader2::setBindPoseCluster(FbxNode *node)
{
	if( node->GetNodeAttribute())
	{
		switch(node->GetNodeAttribute()->GetAttributeType())
		{
		case FbxNodeAttribute::eMesh: 
			FbxMesh *mesh = node->GetMesh();

			for (int j = 0; j<mesh->GetDeformerCount(); j++)
			{
				FbxSkin *skin = (FbxSkin*) mesh->GetDeformer(j,FbxDeformer::eSkin);
				int clusters = skin->GetClusterCount();
				for(int k = 0; k<clusters; k++)
				{
					FbxCluster* cluster = skin->GetCluster(k);
					FbxNode* boneLink = cluster->GetLink();

					if(boneLink)
					{
						std::string nameLink = boneLink->GetName();
						FbxAMatrix translationM;
						FbxAMatrix invert;
						cluster->GetTransformLinkMatrix(translationM);
						cluster->GetTransformMatrix(invert);

						translationM = translationM * invert.Inverse();

						D3DXMATRIX mat = D3DXMATRIX((float)translationM.mData[0].mData[0], (float)translationM.mData[0].mData[1], (float)translationM.mData[0].mData[2], (float)translationM.mData[3].mData[0],
													(float)translationM.mData[1].mData[0], (float)translationM.mData[1].mData[1], (float)translationM.mData[1].mData[2], (float)translationM.mData[3].mData[1],
													(float)translationM.mData[2].mData[0], (float)translationM.mData[2].mData[1], (float)translationM.mData[2].mData[2], (float)translationM.mData[3].mData[2],
													0,0,0,1);

						skeleton->GetBone(skeleton->GetBoneByName(nameLink))->SetTransformation(mat);
					}
				}
			}
			break;
		}
	}
	for (int i = 0; i<node->GetChildCount(); i++)
	{
		FbxNode* child = node->GetChild(i);
		setBindPoseCluster(child);
	}
}
Пример #4
0
bool loadBlendWeights(FbxMesh* fbxMesh, vector<vector<Vector2> >& weights)
{
    assert(fbxMesh);
    const int vertexCount = fbxMesh->GetControlPointsCount();

    FbxSkin* fbxSkin = NULL;
    const int deformerCount = fbxMesh->GetDeformerCount();
    for (int i = 0; i < deformerCount; ++i)
    {
        FbxDeformer* deformer = fbxMesh->GetDeformer(i);
        if (deformer->GetDeformerType() == FbxDeformer::eSkin)
        {
            fbxSkin = FbxCast<FbxSkin>(deformer);
            weights.resize(vertexCount);

            const int clusterCount = fbxSkin->GetClusterCount();
            for (int j = 0; j < clusterCount; ++j)
            {
                FbxCluster* cluster = fbxSkin->GetCluster(j);
                assert(cluster);
                const int vertexIndexCount = cluster->GetControlPointIndicesCount();
                for (int k = 0; k < vertexIndexCount; ++k)
                {
                    int index = cluster->GetControlPointIndices()[k];
                    if (index >= vertexCount)
                    {
                        continue;
                    }

                    double weight = cluster->GetControlPointWeights()[k];
                    if (weight == 0.0)
                    {
                        continue;
                    }
                    weights[index].push_back(Vector2((float)j, (float)weight));
                }
            }
            // Only the first skin deformer will be loaded.
            // There probably won't be more than one.
            break;
        }
    }
    return fbxSkin != NULL;
}
Пример #5
0
// Deform the vertex array according to the links contained in the mesh and the skinning type.
void compute_skin_deformation(FbxAMatrix& pGlobalPosition,
                              FbxMesh* pMesh,
                              FbxTime& pTime,
                              FbxVector4* pVertexArray,
                              FbxPose* pPose)
{
  FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(0, FbxDeformer::eSkin);
  FbxSkin::EType lSkinningType = lSkinDeformer->GetSkinningType();

  if(lSkinningType == FbxSkin::eLinear || lSkinningType == FbxSkin::eRigid) {
    compute_linear_deformation(pGlobalPosition, pMesh, pTime, pVertexArray, pPose);
  } else if(lSkinningType == FbxSkin::eDualQuaternion) {
    compute_dual_quaternion_deformation(pGlobalPosition, pMesh, pTime, pVertexArray, pPose);
  } else if(lSkinningType == FbxSkin::eBlend) {
    int lVertexCount = pMesh->GetControlPointsCount();

    FbxVector4* lVertexArrayLinear = new FbxVector4[lVertexCount];
    memcpy(lVertexArrayLinear, pMesh->GetControlPoints(), lVertexCount * sizeof(FbxVector4));

    FbxVector4* lVertexArrayDQ = new FbxVector4[lVertexCount];
    memcpy(lVertexArrayDQ, pMesh->GetControlPoints(), lVertexCount * sizeof(FbxVector4));

    compute_linear_deformation(pGlobalPosition, pMesh, pTime, lVertexArrayLinear, pPose);
    compute_dual_quaternion_deformation(pGlobalPosition, pMesh, pTime, lVertexArrayDQ, pPose);

    // To blend the skinning according to the blend weights
    // Final vertex = DQSVertex * blend weight + LinearVertex * (1- blend weight)
    // DQSVertex: vertex that is deformed by dual quaternion skinning method;
    // LinearVertex: vertex that is deformed by classic linear skinning method;
    int lBlendWeightsCount = lSkinDeformer->GetControlPointIndicesCount();

    for(int lBWIndex = 0; lBWIndex<lBlendWeightsCount; ++lBWIndex) {
      double lBlendWeight = lSkinDeformer->GetControlPointBlendWeights()[lBWIndex];
      pVertexArray[lBWIndex] = lVertexArrayDQ[lBWIndex] * lBlendWeight + lVertexArrayLinear[lBWIndex] * (1 - lBlendWeight);
    }
  }
}
Пример #6
0
// Deform the vertex array in classic linear way.
void compute_linear_deformation(FbxAMatrix& pGlobalPosition,
                                FbxMesh* pMesh,
                                FbxTime& pTime,
                                FbxVector4* pVertexArray,
                                FbxPose* pPose)
{
  // All the links must have the same link mode.
  FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode();

  int lVertexCount = pMesh->GetControlPointsCount();
  FbxAMatrix* lClusterDeformation = new FbxAMatrix[lVertexCount];
  memset(lClusterDeformation, 0, lVertexCount * sizeof(FbxAMatrix));

  double* lClusterWeight = new double[lVertexCount];
  memset(lClusterWeight, 0, lVertexCount * sizeof(double));

  if(lClusterMode == FbxCluster::eAdditive) {
    for(int i = 0; i < lVertexCount; ++i) {
      lClusterDeformation[i].SetIdentity();
    }
  }

  // For all skins and all clusters, accumulate their deformation and weight
  // on each vertices and store them in lClusterDeformation and lClusterWeight.
  int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);

  for(int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex) {
    FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin);

    int lClusterCount = lSkinDeformer->GetClusterCount();

    for(int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex) {
      FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex);

      if(!lCluster->GetLink()) {
        continue;
      }

      FbxAMatrix lVertexTransformMatrix;
      compute_cluster_deformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose);

      int lVertexIndexCount = lCluster->GetControlPointIndicesCount();

      for(int k = 0; k < lVertexIndexCount; ++k) {
        int lIndex = lCluster->GetControlPointIndices()[k];

        // Sometimes, the mesh can have less points than at the time of the skinning
        // because a smooth operator was active when skinning but has been deactivated during export.
        if(lIndex >= lVertexCount) {
          continue;
        }

        double lWeight = lCluster->GetControlPointWeights()[k];

        if(lWeight == 0.0) {
          continue;
        }

        // Compute the influence of the link on the vertex.
        FbxAMatrix lInfluence = lVertexTransformMatrix;
        matrix_scale(lInfluence, lWeight);

        if(lClusterMode == FbxCluster::eAdditive) {
          // Multiply with the product of the deformations on the vertex.
          matrix_add_to_diagonal(lInfluence, 1.0 - lWeight);
          lClusterDeformation[lIndex] = lInfluence * lClusterDeformation[lIndex];

          // Set the link to 1.0 just to know this vertex is influenced by a link.
          lClusterWeight[lIndex] = 1.0;
        } else { // lLinkMode == FbxCluster::eNormalize || lLinkMode == FbxCluster::eTotalOne
          // Add to the sum of the deformations on the vertex.
          matrix_add(lClusterDeformation[lIndex], lInfluence);

          // Add to the sum of weights to either normalize or complete the vertex.
          lClusterWeight[lIndex] += lWeight;
        }
      }//For each vertex
    }//lClusterCount
  }

  //Actually deform each vertices here by information stored in lClusterDeformation and lClusterWeight
  for(int i = 0; i < lVertexCount; i++) {

    FbxVector4 lSrcVertex = pVertexArray[i];
    FbxVector4& lDstVertex = pVertexArray[i];
    double lWeight = lClusterWeight[i];

    // Deform the vertex if there was at least a link with an influence on the vertex,
    if(lWeight != 0.0) {
      lDstVertex = lClusterDeformation[i].MultT(lSrcVertex);

      if(lClusterMode == FbxCluster::eNormalize) {
        // In the normalized link mode, a vertex is always totally influenced by the links.
        lDstVertex /= lWeight;
      } else if(lClusterMode == FbxCluster::eTotalOne) {
        // In the total 1 link mode, a vertex can be partially influenced by the links.
        lSrcVertex *= (1.0 - lWeight);
        lDstVertex += lSrcVertex;
      }
    }
  }

  delete [] lClusterDeformation;
  delete [] lClusterWeight;
}
void MeshImporter::LoadWeight(FbxMesh* fbxMesh, MeshEntry* mesh)
{
	int numSkin = fbxMesh->GetDeformerCount(FbxDeformer::eSkin);
	
	if (numSkin == 0)
	{
		return;
	}

	assert(numSkin == 1);

	// Assume only one deformer
	FbxSkin* fbxSkin = static_cast<FbxSkin*>(fbxMesh->GetDeformer(0, FbxDeformer::eSkin));
	int numCluster = fbxSkin->GetClusterCount();
	int numControlPoints = fbxMesh->GetControlPointsCount();
	vector<VertexWeight> tmpWeightList(numControlPoints);

	for (int i = 0; i < numCluster; i++)
	{
		FbxCluster* fbxCluster = fbxSkin->GetCluster(i);

		if (!fbxCluster->GetLink())
		{
			continue;
		}

		unsigned int boneIndex = model->skeleton->bones.size();

		assert(fbxCluster->GetLinkMode() == FbxCluster::eNormalize);

		// Read skeleton bones data (transformation matrix of each bone)
		string boneName(fbxCluster->GetLink()->GetName());

		if (!model->skeleton->FindBoneByName(boneName))
		{
			if (boneIndex >= MAXBONE)
			{
				PrintTab("Too many bones to load!!");
			}
			else
			{
				// Read weights of each vertex
				int numIndexInCluster = fbxCluster->GetControlPointIndicesCount();
				int* indicesInCluster = fbxCluster->GetControlPointIndices();
				double* weights = fbxCluster->GetControlPointWeights();

				for (int j = 0; j < numIndexInCluster; j++)
				{
					tmpWeightList[indicesInCluster[j]].AddBoneData(boneIndex, weights[j]);
				}

				// Normalize weights
				/*for (int inVert = 0; inVert < tmpWeightList.size(); inVert++)
				{
					tmpWeightList[inVert].Normalize();
				}*/

				// Read animation bone matrix
				FbxAMatrix fbxGlobalBoneBaseMatrix;// = fbxCluster->GetLink()->EvaluateGlobalTransform().Inverse().Transpose();

				FbxAMatrix referenceGlobalInitPosition;
				FbxAMatrix clusterGlobalInitPosition;

				fbxCluster->GetTransformMatrix(referenceGlobalInitPosition);
				fbxCluster->GetTransformLinkMatrix(clusterGlobalInitPosition);

				fbxGlobalBoneBaseMatrix = clusterGlobalInitPosition.Inverse() * referenceGlobalInitPosition;

				// To be considered when importing Maya fbx model
				//FbxAMatrix geoMatrix = GetTransformMatrix(fbxCluster->GetLink());

				Bone bone;
				bone.name = boneName;
				bone.boneIndex = boneIndex;
				bone.fbxNode = fbxCluster->GetLink();
				bone.globalBindposeInverseMatrix = fbxGlobalBoneBaseMatrix;

				model->skeleton->bones.push_back(bone);
			}
		}
	}

	// Deployed in the index
	for (unsigned int i = 0; i < mesh->numVertices; i++)
	{
		mesh->vertices[i].boneIndices.x = tmpWeightList[mesh->indices[i]].boneWeight[0].first;
		mesh->vertices[i].boneIndices.y = tmpWeightList[mesh->indices[i]].boneWeight[1].first;
		mesh->vertices[i].boneIndices.z = tmpWeightList[mesh->indices[i]].boneWeight[2].first;
		mesh->vertices[i].boneIndices.w = tmpWeightList[mesh->indices[i]].boneWeight[3].first;

		mesh->vertices[i].weights.x = tmpWeightList[mesh->indices[i]].boneWeight[0].second;
		mesh->vertices[i].weights.y = tmpWeightList[mesh->indices[i]].boneWeight[1].second;
		mesh->vertices[i].weights.z = tmpWeightList[mesh->indices[i]].boneWeight[2].second;
		mesh->vertices[i].weights.w = tmpWeightList[mesh->indices[i]].boneWeight[3].second;
	}
}
Пример #8
0
void FBXConverter::processAnimations( FbxNode* node , std::vector<JointData> &skeleton , std::vector<VertexData> &verts , std::vector<IndexData> &indices )
{
	FbxMesh* theMesh = node->GetMesh();

	FbxAnimStack* animationStack = node->GetScene()->GetSrcObject<FbxAnimStack>();
	FbxAnimLayer* animationLayer = animationStack->GetMember<FbxAnimLayer>();
	std::vector<FbxTime> frames;
	for ( int curveNodeIndex = 0; curveNodeIndex < animationLayer->GetMemberCount(); ++curveNodeIndex )
	{
		FbxAnimCurveNode* currentCurve = animationLayer->GetMember<FbxAnimCurveNode>( curveNodeIndex );

		for ( unsigned int channelIndex = 0; channelIndex < currentCurve->GetChannelsCount(); ++channelIndex )
		{
			for ( int curve = 0; curve < currentCurve->GetCurveCount( channelIndex ); ++curve )
			{
				FbxAnimCurve* theCurveVictim = currentCurve->GetCurve( channelIndex , curve );
				for ( int keyIndex = 0; keyIndex < theCurveVictim->KeyGetCount(); ++keyIndex )
				{
					bool alreadyIn = false;
					for ( unsigned int frameIndex = 0; frameIndex < frames.size(); ++frameIndex )
					{
						if ( ( unsigned int ) frames[frameIndex].GetFrameCount() == ( unsigned int ) theCurveVictim->KeyGet( keyIndex ).GetTime().GetFrameCount() )
						{
							alreadyIn = true;
							//std::cout << frames[frameIndex].GetFrameCount() << " " << theCurveVictim->KeyGet( keyIndex ).GetTime().GetFrameCount() << " " << alreadyIn << std::endl;
							break;
						}
					}
					std::cout << theCurveVictim->KeyGet( keyIndex ).GetTime().GetFrameCount() << " " << alreadyIn << std::endl;
					if(!alreadyIn) frames.push_back(theCurveVictim->KeyGet( keyIndex ).GetTime());
				}
			}
		}
	}
	
	std::sort( frames.begin() , frames.end() , frameCompare );

	FbxAMatrix geoTransform( node->GetGeometricTranslation( FbxNode::eSourcePivot ) , node->GetGeometricRotation( FbxNode::eSourcePivot ) , node->GetGeometricScaling( FbxNode::eSourcePivot ) );


	for ( int i = 0; i < theMesh->GetDeformerCount(); ++i )
	{
		FbxSkin* theSkin = reinterpret_cast< FbxSkin* >( theMesh->GetDeformer( i , FbxDeformer::eSkin ) );
		if ( !theSkin ) continue;

		for ( int j = 0; j < theSkin->GetClusterCount(); ++j )
		{
			FbxCluster* cluster = theSkin->GetCluster( j );
			std::string jointName = cluster->GetLink()->GetName();
			int currentJointIndex = -1;
			for ( unsigned int k = 0; k < skeleton.size(); ++k )
			{
				if ( !skeleton[k].name.compare( jointName ) )
				{
					currentJointIndex = k;
					break;
				}
			}
			if ( currentJointIndex < 0 )
			{
				std::cout << "wrong bone" << std::endl;
				continue;
			}

			FbxAMatrix transformMatrix, transformLinkMatrix, offsetMatrix;
			cluster->GetTransformMatrix( transformMatrix );
			cluster->GetTransformLinkMatrix( transformLinkMatrix );
			//offsetMatrix = transformLinkMatrix.Inverse() * transformMatrix * geoTransform;

			FbxMatrix realMatrix( transformLinkMatrix.Inverse() * transformMatrix );
			
			for ( unsigned int row = 0; row < 4; ++row )
			{
				for ( unsigned int column = 0; column < 4; ++column )
				{
					skeleton[currentJointIndex].offsetMatrix[row][column] = (float)realMatrix.Get( row , column );
				}
			}

			for ( int k = 0; k < cluster->GetControlPointIndicesCount(); ++k )
			{
				BlendingIndexWeightPair weightPair;
				weightPair.blendingIndex = currentJointIndex;
				weightPair.blendingWeight = (float)cluster->GetControlPointWeights()[k];
				unsigned int controlPoint = cluster->GetControlPointIndices()[k];
				for ( unsigned int z = 0; z < indices.size(); ++z )
				{
					if ( indices[z].oldControlPoint == controlPoint )
					{
						if ( verts[indices[z].index].blendingInfo.size() > 4 )
						{
							std::cout << "Warning: vert has more than 4 bones connected, ignoring additional bone." << std::endl;
						}
						//else verts[indices[z].index].blendingInfo.push_back( weightPair );
						bool found = false;
						for ( unsigned int omg = 0; omg < verts[indices[z].index].blendingInfo.size(); ++omg )
						{
							if ( verts[indices[z].index].blendingInfo[omg].blendingIndex == weightPair.blendingIndex )
							{
								found = true;
								break;
							}
						}
						if ( !found ) verts[indices[z].index].blendingInfo.push_back( weightPair );
					}
				}
			}

			for ( unsigned int frameIndex = 0; frameIndex < frames.size(); ++frameIndex )
			{
				FbxVector4 translation = cluster->GetLink()->EvaluateLocalTranslation( frames[frameIndex] );
				FbxVector4 rotation = cluster->GetLink()->EvaluateLocalRotation( frames[frameIndex] );
				FbxVector4 scale = cluster->GetLink()->EvaluateLocalScaling( frames[frameIndex] );
				AnimationData animData;
				animData.frame = (int)frames[frameIndex].GetFrameCount();
				animData.translation = glm::vec3(translation[0],translation[1],translation[2]);
				animData.rotation = glm::angleAxis( glm::radians( (float)rotation[2] ), glm::vec3(0,0,1)) * glm::angleAxis(glm::radians((float) rotation[1]), glm::vec3(0,1,0)) * glm::angleAxis(glm::radians((float)rotation[0]), glm::vec3(1,0,0));
				animData.scale = glm::vec3(scale[0],scale[1],scale[2]);
				skeleton[currentJointIndex].animation.push_back( animData );
			}
		}
	}
}
/**
 * Adds Fbx Clusters necessary to skin a skeletal mesh to the bones in the BoneNodes list
 */
void FFbxExporter::BindMeshToSkeleton(const USkeletalMesh* SkelMesh, FbxNode* MeshRootNode, TArray<FbxNode*>& BoneNodes)
{
	const FSkeletalMeshResource* SkelMeshResource = SkelMesh->GetImportedResource();
	const FStaticLODModel& SourceModel = SkelMeshResource->LODModels[0];
	const int32 VertexCount = SourceModel.NumVertices;

	FbxAMatrix MeshMatrix;

	FbxScene* lScene = MeshRootNode->GetScene();
	if( lScene ) 
	{
		MeshMatrix = MeshRootNode->EvaluateGlobalTransform();
	}
	
	FbxGeometry* MeshAttribute = (FbxGeometry*) MeshRootNode->GetNodeAttribute();
	FbxSkin* Skin = FbxSkin::Create(Scene, "");
	
	const int32 BoneCount = BoneNodes.Num();
	for(int32 BoneIndex = 0; BoneIndex < BoneCount; ++BoneIndex)
	{
		FbxNode* BoneNode = BoneNodes[BoneIndex];

		// Create the deforming cluster
		FbxCluster *CurrentCluster = FbxCluster::Create(Scene,"");
		CurrentCluster->SetLink(BoneNode);
		CurrentCluster->SetLinkMode(FbxCluster::eTotalOne);

		// Add all the vertices that are weighted to the current skeletal bone to the cluster
		// NOTE: the bone influence indices contained in the vertex data are based on a per-chunk
		// list of verts.  The convert the chunk bone index to the mesh bone index, the chunk's
		// boneMap is needed
		int32 VertIndex = 0;
		const int32 SectionCount = SourceModel.Sections.Num();
		for(int32 SectionIndex = 0; SectionIndex < SectionCount; ++SectionIndex)
		{
			const FSkelMeshSection& Section = SourceModel.Sections[SectionIndex];

			for(int32 SoftIndex = 0; SoftIndex < Section.SoftVertices.Num(); ++SoftIndex)
			{
				const FSoftSkinVertex& Vert = Section.SoftVertices[SoftIndex];

				for(int32 InfluenceIndex = 0; InfluenceIndex < MAX_TOTAL_INFLUENCES; ++InfluenceIndex)
				{
					int32 InfluenceBone		= Section.BoneMap[ Vert.InfluenceBones[InfluenceIndex] ];
					float InfluenceWeight	= Vert.InfluenceWeights[InfluenceIndex] / 255.f;

					if(InfluenceBone == BoneIndex && InfluenceWeight > 0.f)
					{
						CurrentCluster->AddControlPointIndex(VertIndex, InfluenceWeight);
					}
				}

				++VertIndex;
			}
		}

		// Now we have the Patch and the skeleton correctly positioned,
		// set the Transform and TransformLink matrix accordingly.
		CurrentCluster->SetTransformMatrix(MeshMatrix);

		FbxAMatrix LinkMatrix;
		if( lScene )
		{
			LinkMatrix = BoneNode->EvaluateGlobalTransform();
		}

		CurrentCluster->SetTransformLinkMatrix(LinkMatrix);

		// Add the clusters to the mesh by creating a skin and adding those clusters to that skin.
		Skin->AddCluster(CurrentCluster);
	}

	// Add the skin to the mesh after the clusters have been added
	MeshAttribute->AddDeformer(Skin);
}
Пример #10
0
int main(int argc, char **argv)
{
#ifndef _DEBUG
	if (argc != 2)
	{
		printf("invalid arg");
		return 0;
	}
	const char* filename = argv[1];
#else
	const char* filename = "*****@*****.**";
#endif
	
	output.open("output.txt", ios::out | ios::trunc);
	output2.open("output2.txt", ios::out | ios::trunc);
	output3.open("output3.txt", ios::out | ios::trunc);
	if (!output.is_open())
	{
		exit(1);
	}
	FbxManager* fm = FbxManager::Create();
	FbxIOSettings *ios = FbxIOSettings::Create(fm, IOSROOT);
	//ios->SetBoolProp(EXP_FBX_ANIMATION, false);
	ios->SetIntProp(EXP_FBX_COMPRESS_LEVEL, 9);
	
	ios->SetAllObjectFlags(true);
	fm->SetIOSettings(ios);

	FbxImporter* importer = FbxImporter::Create(fm, "");
	if (!importer->Initialize(filename, -1, fm->GetIOSettings()))
	{
		printf("error returned : %s\n", importer->GetStatus().GetErrorString());
		exit(-1);
	}

	FbxScene* scene = FbxScene::Create(fm, "myscene");

	importer->Import(scene);
	importer->Destroy();
	output << "some\n";
	output << "charcnt : " << scene->GetCharacterCount() << endl << "node cnt : " << scene->GetNodeCount() << endl;
	int animstackcnt = scene->GetSrcObjectCount<FbxAnimStack>();
	output << "animstackcnt : " << animstackcnt << endl;

	output << "------------" << endl;
	vector<FbxNode*> removableNodes;

	for (int i = 0; i < scene->GetNodeCount(); i++)
	{
		FbxNode* node = scene->GetNode(i);
		output << "scene's node " << i << " : " << node->GetName() << ", childcnt : " << node->GetChildCount();
		if (node->GetNodeAttribute())
		{
			output <<", att type : " << node->GetNodeAttribute()->GetAttributeType();
			if (node->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::EType::eMesh)
			{
				FbxMesh* mesh = node->GetMesh();

				output << ", mem usage : " << mesh->MemoryUsage() << ", deformer cnt : " << mesh->GetDeformerCount(FbxDeformer::EDeformerType::eSkin) << endl;
				collapseMesh(mesh);
				FbxSkin* skin = (FbxSkin*) (mesh->GetDeformer(0, FbxDeformer::EDeformerType::eSkin));
				if (skin)
				{
					
					for (int cli = 0; cli < skin->GetClusterCount(); cli++)
					{
						FbxCluster* cluster = skin->GetCluster(cli);
						output << "\tcluster no." << cli << " has " << cluster->GetControlPointIndicesCount() << " connected verts" << endl;
						if (cluster->GetControlPointIndicesCount() == 0)
							removableNodes.push_back( cluster->GetLink() );
						
						//cluster->
						//skin->RemoveCluster(cluster);효과없음
					}

					
					
				}
				if (mesh->IsTriangleMesh())
				{
					output << "\tit's triangle mesh" << endl;
					
				}
				//mesh->RemoveDeformer(0);효과없음
			}
			else
				output << endl;
		}
		else
		{
			output << ", att type : none" << endl;
		}
	}

	for (int rni = 0; rni < removableNodes.size(); rni++)
	{
		FbxNode* rnd = removableNodes[rni];
		if (rnd && rnd->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::EType::eSkeleton)
		{
			output3 << rnd->GetName() << " node with no vert attached's curve : " << rnd->GetSrcObjectCount<FbxAnimCurve>() << "," << rnd->GetSrcObjectCount<FbxAnimCurveNode>() << endl;
		}
	}

	output << "-----------animinfo" << endl;
	int cubic = 0, linear = 0, cons = 0;
	for (int si = 0; si < animstackcnt; si++)
	{
		FbxAnimStack* stack = scene->GetSrcObject<FbxAnimStack>(si);
		for (int i = 0; i < stack->GetMemberCount<FbxAnimLayer>(); i++)
		{
			FbxAnimLayer* layer = stack->GetMember<FbxAnimLayer>(i);
			int curvenodecnt = layer->GetMemberCount<FbxAnimCurveNode>();
			int compositcnt = 0;
			for (int j = 0; j < curvenodecnt; j++)
			{
				FbxAnimCurveNode* cnode = layer->GetMember<FbxAnimCurveNode>(j);
				compositcnt += (cnode->IsComposite() ? 1 : 0);
			}
			output << "\tanimstack's layer " << i << " : " << layer->GetName() << ", curve node cnt : " << curvenodecnt << ", composit node cnt : " << compositcnt << endl;
			vector<FbxAnimCurveNode*> nodes2del;
			
			for (int j = 0; j < curvenodecnt; j++)
			{
				FbxAnimCurveNode* cnode = layer->GetMember<FbxAnimCurveNode>(j);
				output << "\t\tcurvenode " << j << " channel cnt : " << cnode->GetChannelsCount() << ", dst obj cnt " << cnode->GetDstObjectCount() << "(";
				for (int dsti = 0; dsti < cnode->GetDstObjectCount(); dsti++)
				{
					output << "," << cnode->GetDstObject(dsti)->GetName();
					if (cnode->GetDstObject(dsti)->GetSrcObjectCount() > 0)
						output << "<" << cnode->GetDstObject(dsti)->GetSrcObjectCount<FbxSkeleton>() << ">";
				}
				output << ")";
				FbxTimeSpan interval;
				if (cnode->GetAnimationInterval(interval))
				{
					output << ", start : " << interval.GetStart().GetTimeString() << ", end : " << interval.GetStop().GetTimeString() << endl;
				}
				else
				{
					nodes2del.push_back(cnode);
					output << ", no interval" << endl;
				}

				for (int chi = 0; chi < cnode->GetChannelsCount(); chi++)
				{
					
					int curvecnt = cnode->GetCurveCount(chi);
					output << "\t\t\tchannel." << chi << " curvecnt : " << curvecnt << endl;
					for (int ci = 0; ci < curvecnt; ci++)
					{
						FbxAnimCurve* curve = cnode->GetCurve(chi, ci);
						int keycnt = curve->KeyGetCount();
						output << "\t\t\t\tcurve no." << ci << " : key count : " << keycnt;
						output2 << "curve  " << ci << endl;
						
						vector<int> keys2Remove;
						for (int cki = 0; cki < keycnt; cki++)
						{
							FbxAnimCurveKey prevkey, currkey, nextkey;

							if (cki == 0 || cki == keycnt - 1)
								continue;
							
							currkey = curve->KeyGet(cki);
							prevkey = curve->KeyGet(cki-1);
							nextkey = curve->KeyGet(cki + 1);
							
							bool keepit = true;

							output2 << ci << "-" << cki;

//							keepit = keepTestHorizon(curve, prevkey, currkey, nextkey);
	//						if (keepit)
	//							keepit = slopkeepTest(curve, prevkey, currkey, nextkey);

							if (!keepit)
							{
								if (!(currkey.GetInterpolation() == FbxAnimCurveDef::EInterpolationType::eInterpolationConstant && nextkey.GetInterpolation() != FbxAnimCurveDef::EInterpolationType::eInterpolationConstant))
									keys2Remove.push_back(cki);
							}
						}
						for (int kri = keys2Remove.size() - 1; kri >= 0; kri--)
						{
							
							//curve->KeyRemove(keys2Remove[kri]);
						}
						output2 << endl;
						//output << ", cubic:linear:const : " << cubic << ":" << linear << ":" << cons << endl;
						if (keys2Remove.size() > 0)
							output << ", " << keys2Remove.size() << " keys removed";

						keycnt = curve->KeyGetCount();
						
					}

				}
			}
			//이부분은 별로 효과없음
			/*
			for (int di = 0; di < nodes2del.size(); di++)
			{
				layer->RemoveMember(nodes2del[di]);
			}
			*/
			
		}
	}
	output << "cubic:linear:const  " << cubic << ":" << linear << ":" << cons << endl;
	FbxExporter* exporter = FbxExporter::Create(fm, "");
	const char* outFBXName = "after.fbx";

	bool exportstatus = exporter->Initialize(outFBXName, -1, fm->GetIOSettings());
	if (exportstatus == false)
	{
		puts("err export fail");
	}
	exporter->Export(scene);
	exporter->Destroy();
	scene->Destroy();
	
	ios->Destroy();
	fm->Destroy();
	output.close();
	output2.close();
	output3.close();
	return 0;
}
Пример #11
0
// Deform the vertex array in classic linear way.
void fbxLoader2::ComputeLinearDeformation(FbxAMatrix& pGlobalPosition, FbxMesh* pMesh,  FbxTime& pTime, FbxPose* pPose, int frame)
{
	// All the links must have the same link mode.
	FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode();

	int lVertexCount = pMesh->GetControlPointsCount();
	FbxAMatrix* lClusterDeformation = new FbxAMatrix[lVertexCount];
	memset(lClusterDeformation, 0, lVertexCount * sizeof(FbxAMatrix));

	double* lClusterWeight = new double[lVertexCount];
	memset(lClusterWeight, 0, lVertexCount * sizeof(double));

	if (lClusterMode == FbxCluster::eAdditive)
	{
		for (int i = 0; i < lVertexCount; ++i)
		{
			lClusterDeformation[i].SetIdentity();
		}
	}

	// For all skins and all clusters, accumulate their deformation and weight
	// on each vertices and store them in lClusterDeformation and lClusterWeight.
	int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);
	for ( int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex)
	{
		FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin);
		
		int lClusterCount = lSkinDeformer->GetClusterCount();
		for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex)
		{
			FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex);
			if (!lCluster->GetLink())
				continue;

			FbxAMatrix lVertexTransformMatrix;

			ComputeClusterDeformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose, frame);

			//lVertexTransformMatrix.Transpose();
			FbxAMatrix identityM;
			identityM.SetIdentity();

			FbxVector4 rotation = lVertexTransformMatrix.GetROnly();
			FbxVector4 translation = lVertexTransformMatrix.GetT();
			FbxVector4 scaling = lVertexTransformMatrix.GetS();

			//rotation = FbxVector4(rotation.mData[0], rotation.mData[1], rotation.mData[2], rotation.mData[3]);
			//translation = FbxVector4 (translation.mData[0], translation.mData[1], translation.mData[2], translation.mData[3]);
			//scaling = FbxVector4 (scaling.mData[0], scaling.mData[1], scaling.mData[2], scaling.mData[3]);

			//lVertexTransformMatrix = FbxAMatrix(translation, rotation, scaling);			
			//lVertexTransformMatrix = FbxAMatrix(translation, rotation, scaling);	


			identityM = lVertexTransformMatrix * identityM;

			D3DXMATRIX convert = D3DXMATRIX(1,0,0,0,
											0,0,1,0,
											0,1,0,0,
											0,0,0,1);

			D3DXMATRIX setMatrix = D3DXMATRIX(	(float)identityM.mData[0].mData[0], (float)identityM.mData[1].mData[0], (float)identityM.mData[2].mData[0], (float)identityM.mData[3].mData[0],
												(float)identityM.mData[0].mData[1], (float)identityM.mData[1].mData[1], (float)identityM.mData[2].mData[1], (float)identityM.mData[3].mData[1],
												(float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[2],
												(float)identityM.mData[0].mData[3], (float)identityM.mData[1].mData[3], (float)identityM.mData[2].mData[3],1);

			//setMatrix *=0.5f;

			setMatrix = D3DXMATRIX(	(float)identityM.mData[0].mData[0], (float)identityM.mData[1].mData[0], (float)identityM.mData[2].mData[0], (float)identityM.mData[3].mData[0],
									(float)identityM.mData[0].mData[1], (float)identityM.mData[1].mData[1], (float)identityM.mData[2].mData[1], (float)identityM.mData[3].mData[1],
									//(float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[1],
									(float)identityM.mData[0].mData[2], (float)identityM.mData[1].mData[2], (float)identityM.mData[2].mData[2], (float)identityM.mData[3].mData[2],
									(float)identityM.mData[0].mData[3], (float)identityM.mData[1].mData[3], (float)identityM.mData[2].mData[3], 1);

			//setMatrix = setMatrix*convert;

			///////// juz prawie dziala. sprawdz jeszcze te addytywne itp.
			/// generalnie dodaj to do włosów i dorzuć poprzednią macierz, żeby liczyć przesunięcia.


			//setMatrix /= 2.54f; //skala jedna jest w cm, druga w inchach, nieważne czy zmieniam system skali ręcznie... bzdurka fbxa
			

			std::string nametype = lCluster->GetLink()->GetName();	

			animationStructure->GetSkeleton(frame)->GetBone(animationStructure->GetSkeleton(frame)->GetBoneByName(lCluster->GetLink()->GetName()))->SetTransformation(setMatrix);
		}//lClusterCount
	}

	delete [] lClusterDeformation;
	delete [] lClusterWeight;
}
Пример #12
0
// Deform the vertex array in classic linear way.
void ComputeLinearDeformation(FbxAMatrix& pGlobalPosition, 
								FbxMesh* pMesh,  
								FbxVector4* someWeights,
								FbxVectorTemplate4<int>* someBones,
								AnimationData* aAnimation)
{
	aAnimation;
	pGlobalPosition;
	// All the links must have the same link mode.
	FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode();
	lClusterMode;

	int lVertexCount = pMesh->GetControlPointsCount();
	for(int i = 0;i < lVertexCount;++i)
	{
		someBones[i][0] = -1;
		someBones[i][1] = -1;
		someBones[i][2] = -1;
		someBones[i][3] = -1;

		someWeights[i][0] = 0.0;
		someWeights[i][1] = 0.0;
		someWeights[i][2] = 0.0;
		someWeights[i][3] = 0.0;
	}

	// For all skins and all clusters, accumulate their deformation and weight
	// on each vertices and store them in lClusterDeformation and lClusterWeight.
	int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);
	for ( int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex)
	{
		FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin);
		
		int lClusterCount = lSkinDeformer->GetClusterCount();
		for ( int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex)
		{
			FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex);
			if (!lCluster->GetLink())
				continue;

			std::string boneName = lCluster->GetLink()->GetName();

			int boneId = (int)lCluster->GetLink()->GetUserDataPtr();
			FbxAMatrix lVertexTransformMatrix;

			int lVertexIndexCount = lCluster->GetControlPointIndicesCount();
			for (int k = 0; k < lVertexIndexCount; ++k) 
			{            
				int lIndex = lCluster->GetControlPointIndices()[k];
					
				// Sometimes, the mesh can have less points than at the time of the skinning
				// because a smooth operator was active when skinning but has been deactivated during export.
				if (lIndex >= lVertexCount)
					continue;

				double lWeight = lCluster->GetControlPointWeights()[k];

				if (lWeight == 0.0)
				{
					continue;
				}

				bool foundSpot = false;
				for(int spot = 0;spot < 4;++spot)
				{
					if(someBones[lIndex][spot] == -1)
					{
						someBones[lIndex][spot] = boneId;
						someWeights[lIndex][spot] = lWeight;
						foundSpot = true;
						break;
					}
				}

				/*if (lClusterMode == FbxCluster::eAdditive)
				{    

					// Set the link to 1.0 just to know this vertex is influenced by a link.
					lClusterWeight[lIndex] = 1.0;
				}
				else // lLinkMode == FbxCluster::eNormalize || lLinkMode == FbxCluster::eTotalOne
				{
					// Add to the sum of weights to either normalize or complete the vertex.
					lClusterWeight[lIndex] += lWeight;
				}*/
			}//For each vertex			
		}//lClusterCount
	}

	/*for(int i = 0;i < lVertexCount;++i)
	{
		if(someBones[i][0] == -1)
		{
			someBones[i][0] = 0;
		}
		if(someBones[i][1] == -1)
		{
			someBones[i][1] = 0;
		}
		if(someBones[i][2] == -1)
		{
			someBones[i][2] = 0;
		}
		if(someBones[i][3] == -1)
		{
			someBones[i][3] = 0;
		}

	}*/

	//Actually deform each vertices here by information stored in lClusterDeformation and lClusterWeight
	/*for (int i = 0; i < lVertexCount; i++) 
	{
		FbxVector4 lSrcVertex = pVertexArray[i];
		FbxVector4& lDstVertex = pVertexArray[i];
		double lWeight = lClusterWeight[i];

		// Deform the vertex if there was at least a link with an influence on the vertex,
		if (lWeight != 0.0) 
		{
			lDstVertex = lClusterDeformation[i].MultT(lSrcVertex);
			if (lClusterMode == FbxCluster::eNormalize)
			{
				// In the normalized link mode, a vertex is always totally influenced by the links. 
				lDstVertex /= lWeight;
			}
			else if (lClusterMode == FbxCluster::eTotalOne)
			{
				// In the total 1 link mode, a vertex can be partially influenced by the links. 
				lSrcVertex *= (1.0 - lWeight);
				lDstVertex += lSrcVertex;
			}
		} 
	}

	delete [] lClusterDeformation;
	delete [] lClusterWeight;*/
}
Пример #13
0
void ExportFbxMesh(const Value& obj)
{
	string name = obj["Name"].GetString();

	FbxNode* pNode = FbxNode::Create(pManager, name.c_str());
	FbxMesh* pMesh = FbxMesh::Create(pManager, name.c_str());
	pNode->AddNodeAttribute(pMesh);
	pScene->GetRootNode()->AddChild(pNode);

	int numVertex = obj["NumVertex"].GetInt();
	
	{
		pMesh->InitControlPoints(numVertex);
		FbxVector4* lControlPoints = pMesh->GetControlPoints();
		const Value& pos = obj["Position"];
		for (int i = 0; i < numVertex; i++)
		{
			double x = pos[i * 3 + 0].GetDouble();
			x = -x;
			double y = pos[i * 3 + 1].GetDouble();
			double z = pos[i * 3 + 2].GetDouble();
			lControlPoints[i] = FbxVector4(x, y, z);
		}
	}

	{
		FbxGeometryElementNormal* lGeometryElementNormal = pMesh->CreateElementNormal();
		lGeometryElementNormal->SetMappingMode(FbxGeometryElement::eByControlPoint);
		lGeometryElementNormal->SetReferenceMode(FbxGeometryElement::eDirect);
		FbxLayerElementArrayTemplate<FbxVector4>& array = lGeometryElementNormal->GetDirectArray();

		const Value& normal = obj["Normal"];
		for (int i = 0; i < numVertex; i++)
		{
			double x = normal[i * 3 + 0].GetDouble();
			x = -x;
			double y = normal[i * 3 + 1].GetDouble();
			double z = normal[i * 3 + 2].GetDouble();
			array.Add(FbxVector4(x, y, z));
		}
	}

	{
		FbxGeometryElementUV* lUVDiffuseElement = pMesh->CreateElementUV("DiffuseUV");
		FBX_ASSERT(lUVDiffuseElement != NULL);
		lUVDiffuseElement->SetMappingMode(FbxGeometryElement::eByControlPoint);
		lUVDiffuseElement->SetReferenceMode(FbxGeometryElement::eDirect);
		FbxLayerElementArrayTemplate<FbxVector2>& array = lUVDiffuseElement->GetDirectArray();

		const Value& v = obj["UV0"];
		for (int i = 0; i < numVertex; i++)
		{
			double x = v[i * 2 + 0].GetDouble();
			double y = v[i * 2 + 1].GetDouble();
			array.Add(FbxVector2(x, y));
		}
	}

	{
		const Value& color = obj["Color"];
		if (!color.IsNull())
		{
			FbxGeometryElementVertexColor* pColorElement = pMesh->CreateElementVertexColor();
			FBX_ASSERT(pColorElement != NULL);
			pColorElement->SetMappingMode(FbxGeometryElement::eByControlPoint);
			pColorElement->SetReferenceMode(FbxGeometryElement::eDirect);
			FbxLayerElementArrayTemplate<FbxColor>& array = pColorElement->GetDirectArray();

			for (int i = 0; i < numVertex; i++)
			{
				double r = color[i * 4 + 0].GetDouble();
				double g = color[i * 4 + 1].GetDouble();
				double b = color[i * 4 + 2].GetDouble();
				double a = color[i * 4 + 3].GetDouble();
				array.Add(FbxColor(r, g, b, a));
			}
		}
	}

	{
		const Value& Indeices = obj["Indeices"];

		for (uint32_t subMesh = 0; subMesh < Indeices.Size(); subMesh++)
		{
			const Value& index0 = Indeices[subMesh];
			int numIndex = index0.Size();
			printf("index %d\n", numIndex);
			for (int i = 0; i < numIndex / 3; i++)
			{
				pMesh->BeginPolygon(-1, -1, subMesh);
				int index[3] = {
					index0[i * 3 + 0].GetInt(),
					index0[i * 3 + 1].GetInt(),
					index0[i * 3 + 2].GetInt(),
				};

				pMesh->AddPolygon(index[0]);
				pMesh->AddPolygon(index[2]);
				pMesh->AddPolygon(index[1]);
				pMesh->EndPolygon();
			}
		}
	}

	//////////////////////////////////////////////////////////////////////////

	// export skin
	const Value& boneIndex = obj["BoneIndex"];

	if (!boneIndex.IsNull())
	{
		if (fbxBones.empty())
		{
			printf("no bones, can not export skin");
			return;
		}

		const Value& boneWeight = obj["BoneWeight"];
		vector<FbxCluster*> clusters(fbxBones.size(), NULL);
		for (uint32_t i = 0; i < fbxBones.size(); i++) {
			FbxCluster* pCluster = FbxCluster::Create(pScene, "");
			pCluster->SetLink(fbxBones[i]);
			pCluster->SetLinkMode(FbxCluster::eTotalOne);
			clusters[i] = pCluster;
		}

		for (int i = 0; i < numVertex; i++) {
			for (int j = 0; j < 4; j++) {
				int bone = boneIndex[i * 4 + j].GetInt();
				double weight = boneWeight[i * 4 + j].GetDouble();
				clusters[bone]->AddControlPointIndex(i, weight);
			}
		}

		FbxSkin* lSkin = FbxSkin::Create(pScene, "");

		FbxScene* p = pNode->GetScene();
		FbxAMatrix modelMatrix = pNode->EvaluateGlobalTransform();
		for (uint32_t i = 0; i < clusters.size(); i++) {
			clusters[i]->SetTransformMatrix(modelMatrix);
			FbxAMatrix boneMatrix = fbxBones[i]->EvaluateGlobalTransform();
			clusters[i]->SetTransformLinkMatrix(boneMatrix);
			lSkin->AddCluster(clusters[i]);
		}

		pMesh->AddDeformer(lSkin);
	}

}
Пример #14
0
// Deform the vertex array in Dual Quaternion Skinning way.
void compute_dual_quaternion_deformation(FbxAMatrix& pGlobalPosition,
    FbxMesh* pMesh,
    FbxTime& pTime,
    FbxVector4* pVertexArray,
    FbxPose* pPose)
{
  // All the links must have the same link mode.
  FbxCluster::ELinkMode lClusterMode = ((FbxSkin*)pMesh->GetDeformer(0, FbxDeformer::eSkin))->GetCluster(0)->GetLinkMode();

  int lVertexCount = pMesh->GetControlPointsCount();
  int lSkinCount = pMesh->GetDeformerCount(FbxDeformer::eSkin);

  FbxDualQuaternion* lDQClusterDeformation = new FbxDualQuaternion[lVertexCount];
  memset(lDQClusterDeformation, 0, lVertexCount * sizeof(FbxDualQuaternion));

  double* lClusterWeight = new double[lVertexCount];
  memset(lClusterWeight, 0, lVertexCount * sizeof(double));

  // For all skins and all clusters, accumulate their deformation and weight
  // on each vertices and store them in lClusterDeformation and lClusterWeight.
  for(int lSkinIndex=0; lSkinIndex<lSkinCount; ++lSkinIndex) {
    FbxSkin * lSkinDeformer = (FbxSkin *)pMesh->GetDeformer(lSkinIndex, FbxDeformer::eSkin);
    int lClusterCount = lSkinDeformer->GetClusterCount();

    for(int lClusterIndex=0; lClusterIndex<lClusterCount; ++lClusterIndex) {
      FbxCluster* lCluster = lSkinDeformer->GetCluster(lClusterIndex);

      if(!lCluster->GetLink()) {
        continue;
      }

      FbxAMatrix lVertexTransformMatrix;
      compute_cluster_deformation(pGlobalPosition, pMesh, lCluster, lVertexTransformMatrix, pTime, pPose);

      FbxQuaternion lQ = lVertexTransformMatrix.GetQ();
      FbxVector4 lT = lVertexTransformMatrix.GetT();
      FbxDualQuaternion lDualQuaternion(lQ, lT);

      int lVertexIndexCount = lCluster->GetControlPointIndicesCount();

      for(int k = 0; k < lVertexIndexCount; ++k) {
        int lIndex = lCluster->GetControlPointIndices()[k];

        // Sometimes, the mesh can have less points than at the time of the skinning
        // because a smooth operator was active when skinning but has been deactivated during export.
        if(lIndex >= lVertexCount) {
          continue;
        }

        double lWeight = lCluster->GetControlPointWeights()[k];

        if(lWeight == 0.0) {
          continue;
        }

        // Compute the influence of the link on the vertex.
        FbxDualQuaternion lInfluence = lDualQuaternion * lWeight;

        if(lClusterMode == FbxCluster::eAdditive) {
          // Simply influenced by the dual quaternion.
          lDQClusterDeformation[lIndex] = lInfluence;

          // Set the link to 1.0 just to know this vertex is influenced by a link.
          lClusterWeight[lIndex] = 1.0;
        } else { // lLinkMode == FbxCluster::eNormalize || lLinkMode == FbxCluster::eTotalOne
          if(lClusterIndex == 0) {
            lDQClusterDeformation[lIndex] = lInfluence;
          } else {
            // Add to the sum of the deformations on the vertex.
            // Make sure the deformation is accumulated in the same rotation direction.
            // Use dot product to judge the sign.
            double lSign = lDQClusterDeformation[lIndex].GetFirstQuaternion().DotProduct(lDualQuaternion.GetFirstQuaternion());

            if(lSign >= 0.0) {
              lDQClusterDeformation[lIndex] += lInfluence;
            } else {
              lDQClusterDeformation[lIndex] -= lInfluence;
            }
          }

          // Add to the sum of weights to either normalize or complete the vertex.
          lClusterWeight[lIndex] += lWeight;
        }
      }//For each vertex
    }//lClusterCount
  }

  //Actually deform each vertices here by information stored in lClusterDeformation and lClusterWeight
  for(int i = 0; i < lVertexCount; i++) {
    FbxVector4 lSrcVertex = pVertexArray[i];
    FbxVector4& lDstVertex = pVertexArray[i];
    double lWeightSum = lClusterWeight[i];

    // Deform the vertex if there was at least a link with an influence on the vertex,
    if(lWeightSum != 0.0) {
      lDQClusterDeformation[i].Normalize();
      lDstVertex = lDQClusterDeformation[i].Deform(lDstVertex);

      if(lClusterMode == FbxCluster::eNormalize) {
        // In the normalized link mode, a vertex is always totally influenced by the links.
        lDstVertex /= lWeightSum;
      } else if(lClusterMode == FbxCluster::eTotalOne) {
        // In the total 1 link mode, a vertex can be partially influenced by the links.
        lSrcVertex *= (1.0 - lWeightSum);
        lDstVertex += lSrcVertex;
      }
    }
  }

  delete [] lDQClusterDeformation;
  delete [] lClusterWeight;
}
Пример #15
0
Bone::Bone(FbxScene& scene) {
  //construct hierarchy
  *this = Bone { *(scene.GetRootNode()) };

  std::map<std::string, std::pair<unsigned int, scm::math::mat4f> > bone_info{}
  ;
  unsigned num_bones = 0;
  for (unsigned int i = 0; i < scene.GetGeometryCount(); i++) {
    FbxGeometry* geo = scene.GetGeometry(i);
    if (geo->GetAttributeType() == FbxNodeAttribute::eMesh) {

      //check for skinning, use first skin deformer
      FbxSkin* skin;
      for (unsigned i = 0; i < geo->GetDeformerCount(); ++i) {
        FbxDeformer* defPtr = { geo->GetDeformer(i) };
        if (defPtr->GetDeformerType() == FbxDeformer::eSkin) {
          skin = static_cast<FbxSkin*>(defPtr);
          break;
        }
      }

      if (!skin) {
        Logger::LOG_ERROR << "Mesh does not contain skin deformer" << std::endl;
        assert(false);
      }

      //one cluster corresponds to one bone
      for (unsigned i = 0; i < skin->GetClusterCount(); ++i) {
        FbxCluster* cluster = skin->GetCluster(i);
        FbxNode* node = cluster->GetLink();

        if (!node) {
          Logger::LOG_ERROR << "associated node does not exist!" << std::endl;
          assert(false);
        }

        std::string bone_name(node->GetName());
        //helper to check for matrix magnitude
        auto magnitude = [](scm::math::mat4f const & mat)->float {
          float mag = 0.0f;
          for (unsigned i = 0; i < 16; ++i) {
            mag += mat[i] * mat[i];
          }
          return mag;
        }
        ;

        //reference pose of bone
        FbxAMatrix bind_transform;
        cluster->GetTransformLinkMatrix(bind_transform);
        //check if the clusters have an extra transformation
        FbxAMatrix cluster_transform;
        cluster->GetTransformMatrix(cluster_transform);
        if (magnitude(to_gua::mat4f(cluster_transform) -
                      scm::math::mat4f::identity()) > 0.000000001f) {
          Logger::LOG_WARNING
              << "weight cluster of bone '" << bone_name
              << "' has transformation, animation will be skewed" << std::endl;
        }
        //add bone to list if it is not already included
        if (bone_info.find(bone_name) == bone_info.end()) {
          bone_info[bone_name] = std::make_pair(
              num_bones,
              to_gua::mat4f(bind_transform.Inverse() * cluster_transform));
          ++num_bones;
        }
      }

      // traverse hierarchy and set accumulated values in the bone
      this->set_properties(bone_info);
    }
  }
}
Пример #16
0
//===============================================================================================================================
void FBXLoader::LoadJointsAndAnimation(FbxNode* inNode)
{
	// This is how each subset gets its bone/joint for animation
	FBXSubsets* subset = mSubsets[iCurrentSubset];
	
	FbxMesh* mesh = inNode->GetMesh();
	
	uint32 numOfDeformers = mesh->GetDeformerCount();
	
	FbxAMatrix geomTrans = ZShadeSandboxMesh::FBXHelper::GetGeometryTransformation(inNode);
	
	// A deformer contains clusters.
	// A cluster contains a link, which is a joint.
	// Normally, There is only one deformer in a mesh but Maya has many types.
	for (uint32 deformerIndex = 0; deformerIndex < numOfDeformers; ++deformerIndex)
	{
		// Lets see if this deformer is a skin
		FbxSkin* skin = reinterpret_cast<FbxSkin*>(mesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
		
		if (!skin) continue;
		
		uint32 numOfClusters = skin->GetClusterCount();
		
		for (uint32 clusterIndex = 0; clusterIndex < numOfClusters; ++clusterIndex)
		{
			FbxCluster* cluster = skin->GetCluster(clusterIndex);
			
			string jointName = cluster->GetLink()->GetName();
			uint32 jointIndex = FindJointIndexUsingName(jointName);
			
			subset->mJoints.push_back(jointIndex);
			
			FbxAMatrix transform;
			FbxAMatrix transformLink;
			FbxAMatrix globalBindposeInverse;
			
			// The transformation of the mesh at binding time
			cluster->GetTransformMatrix(transform);
			
			// The transformation of the cluster (joint) at binding time from joint space to world space
			cluster->GetTransformLinkMatrix(transformLink);
			
			globalBindposeInverse = transformLink.Inverse() * transform * geomTrans;
			
			
			// Update skeletal information
			mSkeleton.joints[jointIndex].globalBindposeInverse = globalBindposeInverse;
			mSkeleton.joints[jointIndex].node = cluster->GetLink();
			
			// Associate each joint with the control points it affects
			uint32 numOfIndices = cluster->GetControlPointIndicesCount();
			
			for (uint32 i = 0; i < numOfIndices; ++i)
			{
				ZShadeSandboxMesh::BlendingIndexWeightPair currBlendingIndexWeightPair;
				currBlendingIndexWeightPair.blendingIndex = jointIndex;
				currBlendingIndexWeightPair.blendingWeight = cluster->GetControlPointWeights()[i];
				mControlPoints[cluster->GetControlPointIndices()[i]]->blendingInfo.push_back(currBlendingIndexWeightPair);
			}
			
			// Animation information
			FbxAnimStack* animStack = m_pFbxScene->GetSrcObject<FbxAnimStack>(0);
			FbxString animStackName = animStack->GetName();
			mAnimationName = animStackName.Buffer();
			FbxTakeInfo* takeInfo = m_pFbxScene->GetTakeInfo(animStackName);
			FbxTime start = takeInfo->mLocalTimeSpan.GetStart();
			FbxTime end = takeInfo->mLocalTimeSpan.GetStop();
			mAnimationLength = end.GetFrameCount(FbxTime::eFrames24) - start.GetFrameCount(FbxTime::eFrames24) + 1;
			FBXKeyframe** anim = &mSkeleton.joints[jointIndex].animation;
			
			for (FbxLongLong i = start.GetFrameCount(FbxTime::eFrames24); i <= end.GetFrameCount(FbxTime::eFrames24); ++i)
			{
				FbxTime time;
				time.SetFrame(i, FbxTime::eFrames24);
				*anim = new FBXKeyframe();
				(*anim)->frameNum = i;
				FbxAMatrix currentTransformOffset = inNode->EvaluateGlobalTransform(time) * geomTrans;
				(*anim)->globalTransform = currentTransformOffset.Inverse() * cluster->GetLink()->EvaluateGlobalTransform(time);
				anim = &((*anim)->next);
			}
		}
	}
	
	// Some control points have less than 4 joints
	// For a normal renderer, there are usually 4 joints
	ZShadeSandboxMesh::BlendingIndexWeightPair currBlendingIndexWeightPair;
	currBlendingIndexWeightPair.blendingIndex = 0;
	currBlendingIndexWeightPair.blendingWeight = 0;
	for (auto itr = mControlPoints.begin(); itr != mControlPoints.end(); ++itr)
	{
		for (unsigned int i = itr->second->blendingInfo.size(); i <= 4; ++i)
		{
			itr->second->blendingInfo.push_back(currBlendingIndexWeightPair);
		}
	}
}
Пример #17
0
		void FbxLoader::ProcessBoneAndAnimation(FbxNode* node, Node& meshNode)
		{
			auto currMesh = node->GetMesh();
			if(!currMesh) return;

			FbxVector4 lT = node->GetGeometricTranslation(FbxNode::eSourcePivot);
			FbxVector4 lR = node->GetGeometricRotation(FbxNode::eSourcePivot);
			FbxVector4 lS = node->GetGeometricScaling(FbxNode::eSourcePivot);

			FbxAMatrix geometryTransform = FbxAMatrix(lT, lR, lS);

			FbxSkin* skin = nullptr;
			const int deformerCnt = currMesh->GetDeformerCount();
			for(int deformerIndex = 0; deformerIndex < deformerCnt; ++deformerIndex) {
				skin = (FbxSkin*)(currMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
				if(skin) break;
			}
			if(!skin) return;

			meshNode.useSkinnedMesh = true;
			const size_t nClusters = skin->GetClusterCount();
			if(nClusters < 1) return;

			for(auto& clip : animationClips)
				clip.second->transformCurves.resize(nClusters);

			meshNode.bones.resize(nClusters);
			const int animCount = scene->GetSrcObjectCount<FbxAnimStack>();

			float time = 0;
			for(int ci = 0; ci < nClusters; ++ci) {
				FbxCluster* cluster = skin->GetCluster(ci);
				auto elink = cluster->GetLinkMode();
				std::string boneName = cluster->GetLink()->GetName();

				FbxAMatrix transformMatrix, transformLinkMatrix, globalBindposeInverse;
				cluster->GetTransformMatrix(transformMatrix);
				cluster->GetTransformLinkMatrix(transformLinkMatrix);
				globalBindposeInverse = transformLinkMatrix.Inverse() * geometryTransform * transformMatrix;

				FbxNode* boneNode = cluster->GetLink();
				Bone& bone = meshNode.bones[ci];
				bone.name = boneName;
				bone.index = ci;

				auto T = globalBindposeInverse.GetT() * factor;
				
				if(axismode == eLeftHanded) {
					auto R = globalBindposeInverse.GetR();
					T[0] *= -1; R[1] *= -1; R[2] *= -1;
					globalBindposeInverse.SetR(R);
				}
				globalBindposeInverse.SetT(T);

				ConvertMatrix(bone.bindPoseInverse, globalBindposeInverse);

				const int nCtrl = cluster->GetControlPointIndicesCount();

				for(int ctrlIndex = 0; ctrlIndex < nCtrl; ++ctrlIndex) {
					BlendWeightPair pair;
					pair.boneIndex = ci;
					pair.weight = (float)cluster->GetControlPointWeights()[ctrlIndex];
					meshNode.controlPoints[cluster->GetControlPointIndices()[ctrlIndex]].blendWeigths.push_back(pair);
				}

				FbxAMatrix preRot;
				auto preR = boneNode->GetPreRotation(FbxNode::eSourcePivot);
				preRot.SetR(preR);

				for(int ai = 0; ai < animCount; ++ai) {
					auto animStack = scene->GetSrcObject<FbxAnimStack>(ai);
					scene->SetCurrentAnimationStack(animStack);
					std::string animName = animStack->GetName();
					auto& clip = animationClips[animName];
					auto& transformCurve = clip->transformCurves[ci];
					transformCurve.boneName = boneName;
					transformCurve.begin = 0;

					auto animLayer = animStack->GetMember<FbxAnimLayer>(0);
					FbxAnimCurve* fbxTCurves[3];
					FbxAnimCurve* fbxRCurves[3];
					FbxAnimCurve* fbxSCurves[3];

					fbxTCurves[0] = boneNode->LclTranslation.GetCurve(animLayer, "X");

					if(!fbxTCurves[0])
						continue;
					
					fbxTCurves[1] = boneNode->LclTranslation.GetCurve(animLayer, "Y");
					fbxTCurves[2] = boneNode->LclTranslation.GetCurve(animLayer, "Z");

					fbxRCurves[0] = boneNode->LclRotation.GetCurve(animLayer, "X");
					fbxRCurves[1] = boneNode->LclRotation.GetCurve(animLayer, "Y");
					fbxRCurves[2] = boneNode->LclRotation.GetCurve(animLayer, "Z");

					fbxSCurves[0] = boneNode->LclScaling.GetCurve(animLayer, "X");
					fbxSCurves[1] = boneNode->LclScaling.GetCurve(animLayer, "Y");
					fbxSCurves[2] = boneNode->LclScaling.GetCurve(animLayer, "Z");

					// set & apply filter
					FbxAnimCurveFilterKeyReducer keyReducer;
					keyReducer.SetKeySync(false);
					keyReducer.Apply(fbxTCurves, 3);
					keyReducer.Apply(fbxSCurves, 3);
					keyReducer.SetKeySync(true);
					keyReducer.Apply(fbxRCurves, 3);

					FbxAnimCurveFilterUnroll unroll;
					unroll.SetForceAutoTangents(true);
					unroll.Apply(fbxRCurves, 3);

					FbxAnimCurveFilterTSS tss;
					FbxTime tt;
					tt.SetSecondDouble(-fbxTCurves[0]->KeyGetTime(0).GetSecondDouble());
					tss.SetShift(tt);
					tss.Apply(fbxTCurves, 3);
					tss.Apply(fbxRCurves, 3);
					tss.Apply(fbxSCurves, 3);
					//

					// process curves
					if(fbxTCurves[0]->KeyGetCount() > 0) {
						ProcessAnimCurveT(fbxTCurves, transformCurve);
						ProcessAnimCurveS(fbxSCurves, transformCurve);
						ProcessAnimCurveR(fbxRCurves, transformCurve, preRot);

						//clamping by reduced keyframes
						clip->startTime = 0;
						clip->lengthInSeconds = transformCurve.end;
						clip->lengthInFrames = (int)(1.5f + (transformCurve.end / (1 / 30.0f)));
					}
				} // animations loop
			} // cluster loop
		}
Пример #18
0
void fbxLoader2::readAnimationWeigths(FbxMesh* mesh)
{
	if(!animationStructure)
	{
		animationStructure = new AnimationData();
	}

	int numSkins = mesh->GetDeformerCount(FbxDeformer::eSkin);

	weightsNumber = 0;

	for (int l = 0; l<this->vertexMaxCount; l++)
	{
		for(int p = 0; p<4; p++)
		{
			this->vertexArray[l].weights[p].boneID = 0;
			this->vertexArray[l].weights[p].weight = 0.0f;
		}
	}

	int next = 0;
	int numindicestest = 0;

	for(int i = 0; i < numSkins; i++)
	{
		FbxSkin* skin = (FbxSkin*) mesh->GetDeformer(i, FbxDeformer::eSkin);

		int clusterCount = skin->GetClusterCount();
		if( clusterCount == 0 ) continue;

		for (int j = 0; j < clusterCount; j++)
		{
			FbxCluster* cluster = skin->GetCluster(j);///trzeba jakoś zrobić wszystkie linki... edit, have no idea what i meant xD
			FbxNode* bone = cluster->GetLink();

			if( !bone )
			{
				continue;
			}

			int numInfluencedVertices = cluster->GetControlPointIndicesCount();

			int* pIndexArray = cluster->GetControlPointIndices();
			numindicestest += cluster->GetControlPointIndicesCount();
			
			double *pWeightArray = cluster->GetControlPointWeights();


			for(int iControlPoint = 0; iControlPoint < numInfluencedVertices; iControlPoint++)
			{
				/*int iControlPointIndex = pIndexArray[iControlPoint];
				////////////muszę poprawić indeksy wierzchołków. teraz odwoluje sie do vertow afaik
				int boneIndex = skeleton->GetBoneByName(bone->GetName());
				int boneI = skeleton->GetBoneIndex(boneIndex);
				//boneIndices[iControlPointIndex] = iCluster;
				double weightAdd = pWeightArray[iControlPoint];

				weightsStructure* added = new weightsStructure(boneI, iControlPointIndex, weightAdd);

				this->weights[next] = added;
				next++;*/

				int iControlPointIndex = pIndexArray[iControlPoint];

				int boneIndex = skeleton->GetBoneByName(bone->GetName());
				int k = 0;

				if(vertexArray[iControlPointIndex].weights[0].weight == 0.0f)
				{
					vertexArray[iControlPointIndex].weights[0].boneID = skeleton->GetBoneIndex(boneIndex);
					vertexArray[iControlPointIndex].weights[0].weight = pWeightArray[iControlPoint];
					vertexArray[iControlPointIndex].weightsNum = 1;
				}
				else
				{
					while (k < 3 && vertexArray[iControlPointIndex].weights[k].weight != 0.0f)
					{
						k++;
					}
					vertexArray[iControlPointIndex].weights[k].boneID = skeleton->GetBoneIndex(boneIndex);
					vertexArray[iControlPointIndex].weights[k].weight = pWeightArray[iControlPoint];
					vertexArray[iControlPointIndex].weightsNum++;
				}
			}
		}
	}
}
Пример #19
0
    //-----------------------------------------------------------------------------------
    static void GetSkinWeights(SceneImport* import, std::vector<SkinWeight>& skinWeights, const FbxMesh* mesh, std::map<int, FbxNode*>& nodeToJointIndex)
    {
        int controlPointCount = mesh->GetControlPointsCount();
        skinWeights.resize(controlPointCount);
        for (size_t i = 0; i < skinWeights.size(); ++i) 
        {
            skinWeights[i].indices = Vector4Int(0, 0, 0, 0);
            skinWeights[i].weights = Vector4(0.0f, 0.0f, 0.0f, 0.0f);
        }
        int deformerCount = mesh->GetDeformerCount((FbxDeformer::eSkin));
        ASSERT_OR_DIE(deformerCount == 1, "Deformer count wasn't 1");

        for (int deformerIndex = 0; deformerIndex < deformerCount; ++deformerIndex)
        {
            FbxSkin* skin = (FbxSkin*)mesh->GetDeformer(deformerIndex, FbxDeformer::eSkin);

            if (skin == nullptr)
            {
                continue;
            }

            //Clusters are a link between this skin object, bones, and the verts that bone affects.
            int clusterCount = skin->GetClusterCount();
            for (int clusterIndex = 0; clusterIndex < clusterCount; ++clusterIndex)
            {
                FbxCluster* cluster = skin->GetCluster(clusterIndex);
                const FbxNode* linkNode = cluster->GetLink();

                //Not associated with a bone? Ignore it, we don't care about it
                if (linkNode == nullptr)
                {
                    continue;
                }

                int jointIndex = Skeleton::INVALID_JOINT_INDEX;
                for (auto iter = nodeToJointIndex.begin(); iter != nodeToJointIndex.end(); ++iter)
                {
                    if (iter->second == linkNode)
                    {
                        jointIndex = iter->first;
                        break;
                    }
                }

                if (jointIndex == Skeleton::INVALID_JOINT_INDEX)
                {
                    continue;
                }

                int* controlPointIndices = cluster->GetControlPointIndices();
                int indexCount = cluster->GetControlPointIndicesCount();
                double* weights = cluster->GetControlPointWeights();

                for (int i = 0; i < indexCount; ++i)
                {
                    int controlIndex = controlPointIndices[i];
                    double weight = weights[i];

                    SkinWeight* skinWeight = &skinWeights[controlIndex];
                    AddHighestWeightWhileKickingTheLowestWeightOut(skinWeight, jointIndex, (float)weight);
                }
            }
        }

        for (SkinWeight& sw : skinWeights)
        {
            //Renormalize all the skin weights
            //Be sure to set weights such that all weights add up to 1
            //All weights should add up to 1, so things that were all zeroes add up to 1
            //If skin-weights were never added, make sure you set it to 1, 0, 0, 0
            float totalWeight = sw.weights.x + sw.weights.y + sw.weights.z + sw.weights.w;
            if(totalWeight > 0.0f)
            {
                sw.weights /= totalWeight;
            }
            else
            {
                sw.weights = { 1.0f, 0.0f, 0.0f, 0.0f };
            }
        }
    }