I have some problems animating a model. I don't even know what I am doing, I just tried whatever I thought could help and copied some code, but nothing fixed this problem and the FBX documentation sucks and I don't know what to try next to get this work. The problem is that this model should look like a human (it does when setting all of the bone matrices to identity or a fixed rotation or translation or whatever, but I want the human to move), but it looks like... whatever...
I don't know which part of the code causes this problem, but I think that it has something to do with the matrices set in the AnimatedModel::Animate() function.
animatedmodel.cpp:
void AnimatedModel::Animate(){
if (FrameCount == Animations[0].KeyFrameCount){
FrameCount = 0;
}
XMMATRIX rotateMatrixX, rotateMatrixY, rotateMatrixZ, translationMatrix, finalMatrix, scaleMatrix;
int i;
for (i = 0; i < BoneCount; i++){
scaleMatrix = XMMatrixScaling(Animations[0].KeyFrameArray[i][FrameCount].Scale.x, Animations[0].KeyFrameArray[i][FrameCount].Scale.y, Animations[0].KeyFrameArray[i][FrameCount].Scale.z);
rotateMatrixX = XMMatrixRotationX(Animations[0].KeyFrameArray[i][FrameCount].Rotate.x / 180.0f*M_PI);
rotateMatrixY = XMMatrixRotationY(Animations[0].KeyFrameArray[i][FrameCount].Rotate.y / 180.0f*M_PI);
rotateMatrixZ = XMMatrixRotationZ(Animations[0].KeyFrameArray[i][FrameCount].Rotate.z / 180.0f*M_PI);
translationMatrix = XMMatrixTranslation(Animations[0].KeyFrameArray[i][FrameCount].Translate.x, Animations[0].KeyFrameArray[i][FrameCount].Translate.y, Animations[0].KeyFrameArray[i][FrameCount].Translate.z);
finalMatrix = XMMatrixMultiply(scaleMatrix, rotateMatrixX);
finalMatrix = XMMatrixMultiply(finalMatrix, rotateMatrixY);
finalMatrix = XMMatrixMultiply(finalMatrix, rotateMatrixZ);
finalMatrix = XMMatrixMultiply(finalMatrix, translationMatrix);
finalMatrix = XMMatrixMultiply(BoneArray[i].GlobalBindposeInverse, finalMatrix);
finalMatrix = XMMatrixTranspose(finalMatrix);
XMStoreFloat4x4(&(BoneMatrixArray[0].Bonematrix[i]), finalMatrix);
}
FrameCount++;
}
fbxloader.h:
#ifndef _FBXLOADER_H_
#define _FBXLOADER_H_
#include <windows.h>
#include <fbxsdk.h>
#include "d3dclass.h"
#pragma comment(lib,"libfbxsdk-md.lib")
#define INDEX_ARRAY_SIZE 12582912 // max 4194304 (2^22) triangles
#define VERTEX_ARRAY_SIZE INDEX_ARRAY_SIZE //vertex count is always <= index count
class FbxLoader{
public:
struct VertexType{
XMFLOAT3 Position;
XMFLOAT3 Normal;
XMFLOAT2 Texture;
float Weights[4];
unsigned int BoneIDs[4];
};
struct KeyFrameType{
int FrameNumber;
XMFLOAT3 Rotate, Scale, Translate;
XMFLOAT4X4 GlobalTransform;
};
struct AnimationType{
char* Name;
KeyFrameType* KeyFrameArray;
int KeyFrameArrayCount;
};
struct BoneType{
BoneType** Children;
int ChildCount, ID;
unsigned long long UniqueID;
char* Name;
AnimationType* AnimationArray;
FbxAMatrix GlobalBindposeInverse;
};
struct ReturnType{
VertexType** VertexArray; //array of pointers to vertex arrays
int VertexArrayCount; // count of vertex and index arrays
unsigned int* VertexCountArray; // array of vertex counts of vertex arrays
unsigned int** IndexArray; //array of pointers to arrays of indices
unsigned int* IndexCountArray; //array of index counts
BoneType* RootBone;
FbxNode** MeshArray;
int AnimationCount, BoneCount;
};
struct WeightType{
float Weights[4];
unsigned int BoneID[4];
int CurrID;
};
static void Initialize();
static bool LoadModel(char* FileName, ReturnType* Result);
static void EndLoading();
private:
static void BeginLoading();
static void ProcessNode(FbxNode* Node, ReturnType* Result);
static void ProcessMesh(FbxNode* Node, ReturnType* Result);
static void FindFirstSkeletonNode(FbxNode* Node, ReturnType* Result);
static void ProcessSkeleton(FbxNode* Node, ReturnType* Result, BoneType** Bone);
static void CopyToNewString(char** Dest, const char* Src);
static FbxAMatrix GetGeometryTransformation(FbxNode* Node);
static void ProcessBonesAndAnimations(FbxNode* Node, FbxScene* Scene, ReturnType* Result);
static BoneType* FindBoneByID(unsigned long long ID, ReturnType* Result);
static WeightType* GetWeightArray(FbxNode* Node, ReturnType* Result);
static void SetWeight(WeightType* WeightPtr, float Weight, int BoneID);
//static void LoadAnimations(FbxScene* Scene, ReturnType* Result);
static FbxManager* SdkManager;
static unsigned int* IndexArray;
static VertexType* vertices;
static int BoneCount;
static WeightType** WeightArray;
};
#endif
fbxloader.cpp:
#include "fbxloader.h"
#include "macros.h"
#include <queue>
FbxManager* FbxLoader::SdkManager;
unsigned int* FbxLoader::IndexArray;
FbxLoader::VertexType* FbxLoader::vertices;
FbxLoader::WeightType** FbxLoader::WeightArray;
void FbxLoader::Initialize(){
SdkManager = 0;
IndexArray = 0;
vertices = 0;
WeightArray = 0;
}
void FbxLoader::BeginLoading(){
if (!SdkManager){
SdkManager = FbxManager::Create();
FbxIOSettings *ios = FbxIOSettings::Create(SdkManager, IOSROOT);
SdkManager->SetIOSettings(ios);
}
if (!IndexArray){
IndexArray = new unsigned int[INDEX_ARRAY_SIZE];
}
if (!vertices){
vertices = new VertexType[VERTEX_ARRAY_SIZE];
}
}
bool FbxLoader::LoadModel(char* FileName, ReturnType* Result){
if (Result==0){
return false;
}
BeginLoading();
Result->VertexArrayCount = 0;
Result->AnimationCount = 0;
Result->BoneCount = 0;
FbxIOSettings *ios = FbxIOSettings::Create(SdkManager, IOSROOT);
SdkManager->SetIOSettings(ios);
FbxImporter* Importer = FbxImporter::Create(SdkManager, "");
if (!Importer->Initialize(FileName, -1, SdkManager->GetIOSettings())) {
return false;
}
FbxScene* Scene = FbxScene::Create(SdkManager, "myScene");
Importer->Import(Scene);
Importer->Destroy();
FbxNode* Node=Scene->GetRootNode();
int NodeCount = Scene->GetNodeCount();
if (NodeCount == 0){
Scene->Destroy();
return false;
}
Result->IndexCountArray = new unsigned int[NodeCount];
Result->VertexCountArray = new unsigned int[NodeCount];
Result->MeshArray = new FbxNode*[NodeCount];
memset(Result->MeshArray, 0, sizeof(FbxNode*)*NodeCount);
Result->IndexArray = new unsigned int*[NodeCount];
Result->VertexArray = new VertexType*[NodeCount];
WeightArray = new WeightType*[NodeCount];
memset(WeightArray, 0, sizeof(WeightType*)*NodeCount);
FindFirstSkeletonNode(Node, Result);
int MeshCount = 0;
std::queue<FbxNode*> NodeQueue;
FbxNode* CurrNode = Node;
while (CurrNode){
FbxNodeAttribute* Attribute = CurrNode->GetNodeAttribute();
if (Attribute){
if (Attribute->GetAttributeType() == FbxNodeAttribute::EType::eMesh){
Result->MeshArray[MeshCount] = CurrNode;
WeightArray[MeshCount] = new WeightType[CurrNode->GetMesh()->GetControlPointsCount()];
memset(WeightArray[MeshCount], 0, sizeof(WeightType)*CurrNode->GetMesh()->GetControlPointsCount());
MeshCount++;
}
}
int j, ChildCount = CurrNode->GetChildCount();
for (j = 0; j < ChildCount; j++){
NodeQueue.push(CurrNode->GetChild(j));
}
if (!NodeQueue.empty()){
CurrNode = NodeQueue.front();
NodeQueue.pop();
}
else{
CurrNode = 0;
}
}
int i;
for (i = 0; i < MeshCount; i++){
ProcessBonesAndAnimations(Result->MeshArray[i], Scene, Result);
}
Result->VertexArrayCount = 0;
ProcessNode(Node, Result);
for (i = 0; i < NodeCount; i++){
SAFE_ARRAY_DELETE(WeightArray[i]);
}
SAFE_ARRAY_DELETE(WeightArray);
Scene->Destroy();
return true;
}
void FbxLoader::ProcessNode(FbxNode* Node, ReturnType* Result){
if (!Node){
return;
}
//Processing all child nodes
int i, ChildCount = Node->GetChildCount();
for (i = 0; i < ChildCount; i++){
ProcessNode(Node->GetChild(i), Result);
}
FbxNodeAttribute* Attribute = Node->GetNodeAttribute();
if (!Attribute){
return;
}
FbxNodeAttribute::EType Type = Attribute->GetAttributeType();
switch (Type){
case FbxNodeAttribute::EType::eMesh:
ProcessMesh(Node, Result);
break;
default:
break;
}
}
void FbxLoader::FindFirstSkeletonNode(FbxNode* Node, ReturnType* Result){
if (!Node){
return;
}
FbxNodeAttribute* Attribute = Node->GetNodeAttribute();
if (!Attribute){
//Processing all child nodes
int i, ChildCount = Node->GetChildCount();
for (i = 0; i < ChildCount; i++){
FindFirstSkeletonNode(Node->GetChild(i), Result);
}
}
else{
FbxNodeAttribute::EType Type = Attribute->GetAttributeType();
if (Type == FbxNodeAttribute::EType::eSkeleton){
ProcessSkeleton(Node, Result,&Result->RootBone);
}
else{
int i, ChildCount = Node->GetChildCount();
for (i = 0; i < ChildCount; i++){
FindFirstSkeletonNode(Node->GetChild(i), Result);
}
}
}
}
void FbxLoader::ProcessMesh(FbxNode* Node, ReturnType* Result){
int i, j, PolygonSize;
int index=0;
if (!Node){
return;
}
FbxMesh* Mesh = Node->GetMesh();
WeightType* Weights = GetWeightArray(Node, Result);
if (!Mesh){
return;
}
int ControlPointCount = Mesh->GetControlPointsCount();
int PolygonCount = Mesh->GetPolygonCount();
FbxGeometryElementNormal* Normal;
FbxGeometryElementUV* UV;
int index0, VertexCounter=0, ControlPointIndex;
int* VertexUsedArray = new int[ControlPointCount];
memset(VertexUsedArray, 0, sizeof(int)*ControlPointCount);
FbxVector4* ControlPoints = Mesh->GetControlPoints();
for (i = 0; i < PolygonCount; i++){ //TBD concave polygons
PolygonSize = Mesh->GetPolygonSize(i)-1;
for (j = 1; j < PolygonSize; j++){ //only works for convex polygons and some concave polygons
if (index == INDEX_ARRAY_SIZE){
goto IndexLoadingEnded;
}
IndexArray[index] = VertexCounter;
index++;
IndexArray[index] = VertexCounter + j;
index++;
IndexArray[index] = VertexCounter + j + 1;
index++;
}
for (j = 0; j <= PolygonSize; j++){
ControlPointIndex = Mesh->GetPolygonVertex(i, j);
vertices[VertexCounter].Position.x = static_cast<float>(ControlPoints[ControlPointIndex].mData[0]);
vertices[VertexCounter].Position.y = static_cast<float>(ControlPoints[ControlPointIndex].mData[1]);
vertices[VertexCounter].Position.z = static_cast<float>(ControlPoints[ControlPointIndex].mData[2]);
memcpy(vertices[VertexCounter].Weights, Weights[ControlPointIndex].Weights, sizeof(float) * 4);
memcpy(vertices[VertexCounter].BoneIDs, Weights[ControlPointIndex].BoneID, sizeof(unsigned int) * 4);
///////////////////////
/// LOADING NORMALS ///
///////////////////////
Normal = Mesh->GetElementNormal(0);
if (Normal){
switch (Normal->GetMappingMode())
{
case FbxGeometryElement::eByControlPoint:
switch (Normal->GetReferenceMode())
{
case FbxGeometryElement::eDirect:
{
vertices[VertexCounter].Normal.x = static_cast<float>(Normal->GetDirectArray().GetAt(ControlPointIndex).mData[0]);
vertices[VertexCounter].Normal.y = static_cast<float>(Normal->GetDirectArray().GetAt(ControlPointIndex).mData[1]);
vertices[VertexCounter].Normal.z = static_cast<float>(Normal->GetDirectArray().GetAt(ControlPointIndex).mData[2]);
}
break;
case FbxGeometryElement::eIndexToDirect:
{
index0 = Normal->GetIndexArray().GetAt(ControlPointIndex);
vertices[VertexCounter].Normal.x = static_cast<float>(Normal->GetDirectArray().GetAt(index0).mData[0]);
vertices[VertexCounter].Normal.y = static_cast<float>(Normal->GetDirectArray().GetAt(index0).mData[1]);
vertices[VertexCounter].Normal.z = static_cast<float>(Normal->GetDirectArray().GetAt(index0).mData[2]);
}
break;
default:
break; //TBD error
}
break;
case FbxGeometryElement::eByPolygonVertex:
switch (Normal->GetReferenceMode())
{
case FbxGeometryElement::eDirect:
{
vertices[VertexCounter].Normal.x = static_cast<float>(Normal->GetDirectArray().GetAt(VertexCounter).mData[0]);
vertices[VertexCounter].Normal.y = static_cast<float>(Normal->GetDirectArray().GetAt(VertexCounter).mData[1]);
vertices[VertexCounter].Normal.z = static_cast<float>(Normal->GetDirectArray().GetAt(VertexCounter).mData[2]);
}
break;
case FbxGeometryElement::eIndexToDirect:
{
index0 = Normal->GetIndexArray().GetAt(VertexCounter);
vertices[VertexCounter].Normal.x = static_cast<float>(Normal->GetDirectArray().GetAt(index0).mData[0]);
vertices[VertexCounter].Normal.y = static_cast<float>(Normal->GetDirectArray().GetAt(index0).mData[1]);
vertices[VertexCounter].Normal.z = static_cast<float>(Normal->GetDirectArray().GetAt(index0).mData[2]);
}
break;
default:
break; //TBD error
}
break;
}
}
else{
vertices[VertexCounter].Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
}
//////////////////////////////
/// LOADING TEXTURE COORDS ///
//////////////////////////////
UV = Mesh->GetElementUV(0);
if (UV){
switch (UV->GetMappingMode())
{
case FbxGeometryElement::eByControlPoint:
switch (UV->GetReferenceMode())
{
case FbxGeometryElement::eDirect:
{
vertices[VertexCounter].Texture.x = static_cast<float>(UV->GetDirectArray().GetAt(ControlPointIndex).mData[0]);
vertices[VertexCounter].Texture.y = static_cast<float>(UV->GetDirectArray().GetAt(ControlPointIndex).mData[1]);
}
break;
case FbxGeometryElement::eIndexToDirect:
{
index0 = UV->GetIndexArray().GetAt(ControlPointIndex);
vertices[VertexCounter].Texture.x = static_cast<float>(UV->GetDirectArray().GetAt(index0).mData[0]);
vertices[VertexCounter].Texture.y = static_cast<float>(UV->GetDirectArray().GetAt(index0).mData[1]);
}
break;
default:
break; //TBD error
}
break;
case FbxGeometryElement::eByPolygonVertex:
switch (UV->GetReferenceMode())
{
case FbxGeometryElement::eDirect:
{
vertices[VertexCounter].Texture.x = static_cast<float>(UV->GetDirectArray().GetAt(VertexCounter).mData[0]);
vertices[VertexCounter].Texture.y = static_cast<float>(UV->GetDirectArray().GetAt(VertexCounter).mData[1]);
}
break;
case FbxGeometryElement::eIndexToDirect:
{
index0 = UV->GetIndexArray().GetAt(VertexCounter);
vertices[VertexCounter].Texture.x = static_cast<float>(UV->GetDirectArray().GetAt(index0).mData[0]);
vertices[VertexCounter].Texture.y = static_cast<float>(UV->GetDirectArray().GetAt(index0).mData[1]);
}
break;
default:
break; //TBD error
}
break;
}
}
else{
vertices[VertexCounter].Texture = XMFLOAT2(0.0f, 0.0f);
}
VertexCounter++;
}
}
IndexLoadingEnded:
Result->IndexArray[Result->VertexArrayCount] = new unsigned int[index]; //index is now the count of indices
memcpy(Result->IndexArray[Result->VertexArrayCount], IndexArray, sizeof(unsigned int)*index);
Result->VertexArray[Result->VertexArrayCount] = new VertexType[VertexCounter];
memcpy(Result->VertexArray[Result->VertexArrayCount], vertices, sizeof(VertexType)*VertexCounter);
Result->IndexCountArray[Result->VertexArrayCount] = index;
Result->VertexCountArray[Result->VertexArrayCount] = VertexCounter;
SAFE_ARRAY_DELETE(VertexUsedArray)
Result->VertexArrayCount++;
}
void FbxLoader::EndLoading(){
if (SdkManager){
SdkManager->Destroy();
}
SAFE_ARRAY_DELETE(IndexArray)
SAFE_ARRAY_DELETE(vertices)
}
void FbxLoader::ProcessSkeleton(FbxNode* Node, ReturnType* Result, BoneType** Bone){
FbxSkeleton* Skeleton=Node->GetSkeleton();
if (!Skeleton){
*Bone = 0;
return;
}
const char* Name=Skeleton->GetInitialName();
*Bone = new BoneType;
(*Bone)->UniqueID = Node->GetUniqueID();
(*Bone)->AnimationArray = 0;
CopyToNewString(&((*Bone)->Name), Name);
int i, ChildCount = Node->GetChildCount();
if (ChildCount != 0){
(*Bone)->Children = new BoneType*[ChildCount];
for (i = 0; i < ChildCount; i++){
ProcessSkeleton(Node->GetChild(i), Result, &((*Bone)->Children[i]));
}
}
else{
(*Bone)->Children = 0;
}
(*Bone)->ChildCount = ChildCount;
(*Bone)->ID = Result->BoneCount;
Result->BoneCount++;
}
FbxAMatrix FbxLoader::GetGeometryTransformation(FbxNode* Node)
{
if (!Node)
{
throw std::exception("Null for mesh geometry");
}
const FbxVector4 lT = Node->GetGeometricTranslation(FbxNode::eSourcePivot);
const FbxVector4 lR = Node->GetGeometricRotation(FbxNode::eSourcePivot);
const FbxVector4 lS = Node->GetGeometricScaling(FbxNode::eSourcePivot);
return FbxAMatrix(lT, lR, lS);
}
void FbxLoader::ProcessBonesAndAnimations(FbxNode* Node, FbxScene* Scene, ReturnType* Result)
{
int AnimStackCount = Scene->GetSrcObjectCount<FbxAnimStack>();
Result->AnimationCount = AnimStackCount;
FbxMesh* currMesh = Node->GetMesh();
unsigned int numOfDeformers = currMesh->GetDeformerCount();
FbxAMatrix geometryTransform = FbxLoader::GetGeometryTransformation(Node);
WeightType* Weights = GetWeightArray(Node, Result);
for (unsigned int deformerIndex = 0; deformerIndex < numOfDeformers; ++deformerIndex)
{
FbxSkin* currSkin = reinterpret_cast<FbxSkin*>(currMesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
if (!currSkin)
{
continue;
}
unsigned int numOfClusters = currSkin->GetClusterCount();
for (unsigned int clusterIndex = 0; clusterIndex < numOfClusters; clusterIndex++)
{
FbxCluster* currCluster = currSkin->GetCluster(clusterIndex);
BoneType* currBone = FindBoneByID(currCluster->GetLink()->GetUniqueID(), Result);
FbxAMatrix transformMatrix;
FbxAMatrix transformLinkMatrix;
FbxAMatrix globalBindposeInverseMatrix;
currCluster->GetTransformMatrix(transformMatrix); // The transformation of the mesh at binding time
currCluster->GetTransformLinkMatrix(transformLinkMatrix); // The transformation of the cluster(joint) at binding time from joint space to world space
globalBindposeInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix * geometryTransform;
currBone->GlobalBindposeInverse = globalBindposeInverseMatrix;
unsigned int numOfIndices = currCluster->GetControlPointIndicesCount();
int* ControlPointIndices = currCluster->GetControlPointIndices();
for (unsigned int i = 0; i < numOfIndices; ++i)
{
SetWeight(&(Weights[ControlPointIndices[i]]), currCluster->GetControlPointWeights()[i], currBone->ID);
}
if (!currBone->AnimationArray){
currBone->AnimationArray = new AnimationType[AnimStackCount];
}
for (int i = 0; i < AnimStackCount; i++)
{
FbxAnimStack* lAnimStack = Scene->GetSrcObject<FbxAnimStack>(i);
FbxTakeInfo* takeInfo = Scene->GetTakeInfo(lAnimStack->GetName());
FbxTime start = takeInfo->mLocalTimeSpan.GetStart();
FbxTime end = takeInfo->mLocalTimeSpan.GetStop();
FbxLongLong AnimationLength = end.GetFrameCount(FbxTime::eFrames24) - start.GetFrameCount(FbxTime::eFrames24) + 1;
currBone->AnimationArray[i].KeyFrameArrayCount = AnimationLength;
currBone->AnimationArray[i].KeyFrameArray = new KeyFrameType[AnimationLength];
CopyToNewString(&(currBone->AnimationArray[i].Name), lAnimStack->GetName());
int k = 0;
for (FbxLongLong j = start.GetFrameCount(FbxTime::eFrames24); j <= end.GetFrameCount(FbxTime::eFrames24); j++)
{
FbxTime currTime;
currTime.SetFrame(j, FbxTime::eFrames24);
currBone->AnimationArray[i].KeyFrameArray[k].FrameNumber = k;
FbxVector4 Rotate, Scale, Translate;
FbxAMatrix currentTransformOffset = Node->EvaluateGlobalTransform(currTime) * GetGeometryTransformation(Node);
FbxAMatrix GlobalTransform = currentTransformOffset.Inverse() * currCluster->GetLink()->EvaluateGlobalTransform(currTime);
Rotate = GlobalTransform.GetR();
currBone->AnimationArray[i].KeyFrameArray[k].Rotate.x = -Rotate.mData[0];
currBone->AnimationArray[i].KeyFrameArray[k].Rotate.y = -Rotate.mData[1];
currBone->AnimationArray[i].KeyFrameArray[k].Rotate.z = Rotate.mData[2];
Scale = GlobalTransform.GetS();
currBone->AnimationArray[i].KeyFrameArray[k].Scale.x = Scale.mData[0];
currBone->AnimationArray[i].KeyFrameArray[k].Scale.y = Scale.mData[1];
currBone->AnimationArray[i].KeyFrameArray[k].Scale.z = Scale.mData[2];
Translate = GlobalTransform.GetT();
currBone->AnimationArray[i].KeyFrameArray[k].Translate.x = Translate.mData[0];
currBone->AnimationArray[i].KeyFrameArray[k].Translate.y = Translate.mData[1];
currBone->AnimationArray[i].KeyFrameArray[k].Translate.z = -Translate.mData[2];
currBone->AnimationArray[i].KeyFrameArray[k].GlobalTransform=XMFLOAT4X4(
GlobalTransform.mData[0].mData[0], GlobalTransform.mData[1].mData[0], GlobalTransform.mData[2].mData[0], GlobalTransform.mData[3].mData[0],
GlobalTransform.mData[0].mData[1], GlobalTransform.mData[1].mData[1], GlobalTransform.mData[2].mData[1], GlobalTransform.mData[3].mData[1],
GlobalTransform.mData[0].mData[2], GlobalTransform.mData[1].mData[2], GlobalTransform.mData[2].mData[2], GlobalTransform.mData[3].mData[2],
GlobalTransform.mData[0].mData[3], GlobalTransform.mData[1].mData[3], GlobalTransform.mData[2].mData[3], GlobalTransform.mData[3].mData[3]);
k++;
}
}
}
}
}
void FbxLoader::CopyToNewString(char** Dest, const char* Src){
if (Src == 0){
*Dest = 0;
return;
}
*Dest = new char[strlen(Src) + 1];
memcpy(*Dest, Src, strlen(Src) + 1);
}
FbxLoader::BoneType* FbxLoader::FindBoneByID(unsigned long long ID, ReturnType* Result){
BoneType* tempBone = Result->RootBone;
std::queue < BoneType* > BoneQueue;
while (tempBone){
if (ID==tempBone->UniqueID){
return tempBone;
}
for (int i = 0; i < tempBone->ChildCount; i++)
{
BoneQueue.push(tempBone->Children[i]);
}
if (BoneQueue.size() > 0)
{
tempBone = BoneQueue.front();
BoneQueue.pop();
}
else
{
tempBone = NULL;
}
}
return 0;
}
FbxLoader::WeightType* FbxLoader::GetWeightArray(FbxNode* Node, ReturnType* Result){
//assuming that count of meshes is smaller than count of nodes
int i=0;
while (Result->MeshArray[i]){
if (Result->MeshArray[i] == Node){
return WeightArray[i];
}
i++;
}
return 0;
}
void FbxLoader::SetWeight(WeightType* WeightPtr, float Weight, int BoneID){
if (WeightPtr->CurrID > 3){
return;
}
WeightPtr->Weights[WeightPtr->CurrID] = Weight;
WeightPtr->BoneID[WeightPtr->CurrID] = BoneID;
}
animatedmodel.vs:////////////////////////////////////////////////////////////////////////////////
// Filename: model.vs
////////////////////////////////////////////////////////////////////////////////
struct BoneMatrixType{
matrix BoneMatrix[64];
};
cbuffer MatrixBuffer
{
matrix worldMatrix;
matrix viewMatrix;
matrix projectionMatrix;
};
cbuffer BoneMatrixBuffer{
BoneMatrixType BoneMatrices[16];
};
struct VertexInputType
{
float4 position : POSITION;
float4 normal : NORMAL;
float2 tex : TEXCOORD;
float4 boneWeights : BONEWEIGHT;
uint4 boneIDs : BONEID;
uint instanceID : SV_InstanceID;
row_major matrix instanceWorld : WORLD;
row_major matrix instanceRotate : ROTATE;
float alpha : ALPHA;
};
struct PixelInputType
{
float4 position : SV_POSITION;
float3 normal : NORMAL;
float4 worldPosition: WORLDPOSITION;
float2 tex : TEXCOORD0;
float alpha : ALPHA;
};
////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
PixelInputType AnimatedModelVertexShader(VertexInputType input)
{
PixelInputType output;
// Change the position vector to be 4 units for proper matrix calculations.
input.position.w = 1.0f;
input.normal.w=0.0f;
float4 positions[4];
positions[0]=mul(input.position,BoneMatrices[input.instanceID%16].BoneMatrix[input.boneIDs.x]);
positions[1]=mul(input.position,BoneMatrices[input.instanceID%16].BoneMatrix[input.boneIDs.y]);
positions[2]=mul(input.position,BoneMatrices[input.instanceID%16].BoneMatrix[input.boneIDs.z]);
positions[3]=mul(input.position,BoneMatrices[input.instanceID%16].BoneMatrix[input.boneIDs.w]);
if(input.boneWeights.x!=0.0f || input.boneWeights.y!=0.0f || input.boneWeights.z!=0.0f || input.boneWeights.w!=0.0f){
output.position=input.boneWeights.x*positions[0] + input.boneWeights.y*positions[1] + input.boneWeights.z*positions[2] + input.boneWeights.w*positions[3];
}
else{
output.position=input.position;
}
// Calculate the position of the vertex against the world, view, and projection matrices.
output.position = mul(output.position, input.instanceWorld);
output.worldPosition=output.position;
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);
output.alpha=input.alpha;
output.normal=normalize(mul(input.normal,input.instanceRotate).xyz);
output.tex=input.tex;
return output;
}
How can I fix the size of the clothes and their positions? What is wrong with the animation? (Yes, I know that the animation speed currently depends on the fps, I will change this when the rest of the animation process works.)I don't even know if the FbxLoader is correct. There may be something wrong but I don't know much about the FBX SDK and the explanations in the documentation of this SDK are... I don't know if I want to call them "explanations", because there is almost nothing explained...
Greetings,
Magogan
PS: Sorry for my bad English