Sign in to follow this  
ekba89

Skinned mesh with Assimp

Recommended Posts

ekba89    788
I'm trying to load models with skinning information with assimp. I have managed to load static models but i have problems with bones. Currently I'm trying to load the famous tiny.x [img]http://public.gamedev.net//public/style_emoticons/default/smile.png[/img] but i think i'm doing something wrong with bone transformations. Lastly i didn't attach screenshots because it is just random triangles but if you want i can add it. Also before i put the code i should say the code is for tiny.x. I mean it has only 1 mesh and 35 bones in it. So i know my code won't work for other meshes but before i try to write more generalized code i wanted to understand the basics. And here is the code.

[code]AnimatedMesh* ModelLoader::LoadAnimatedModel(const char* filePath)
{
const aiScene* scene = aiImportFile(filePath, (aiProcessPreset_TargetRealtime_Quality|aiProcess_ConvertToLeftHanded) & ~aiProcess_FindInvalidData);
if(!scene)
{
return NULL;
}
AnimatedMesh* animMesh = new AnimatedMesh();
for(unsigned int i = 0; i < scene->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[i];
//Copy vertex information
unsigned int numVertices = mesh->mNumVertices;
animMesh->vertexCount = numVertices;
animMesh->vertices = new AnimatedVertexType[numVertices];
for(unsigned int i_vert = 0; i_vert < numVertices; i_vert++)
{
aiVector3D vertex = mesh->mVertices[i_vert];
animMesh->vertices[i_vert].position = aiVector3toD3DVector(vertex);
}
//Copy index information
unsigned int numIndices = mesh->mNumFaces * 3;
animMesh->indexCount = numIndices;
animMesh->indices = new unsigned int[numIndices];
unsigned int indicePosition = 0;
for(unsigned int i_face = 0; i_face < mesh->mNumFaces; i_face++)
{
aiFace face = mesh->mFaces[i_face];
animMesh->indices[indicePosition++] = face.mIndices[0];
animMesh->indices[indicePosition++] = face.mIndices[1];
animMesh->indices[indicePosition++] = face.mIndices[2];
}
//Copy bone information
animMesh->boneCount = mesh->mNumBones;
std::vector<std::vector<aiVertexWeight>> weightPerVertex(mesh->mNumVertices);

for(unsigned int i_bone = 0; i_bone < mesh->mNumBones; i_bone++)
{
aiBone* b = mesh->mBones[i_bone];

for(unsigned int i_weight = 0; i_weight < b->mNumWeights; i_weight++)
{
aiVertexWeight vertexWeight = b->mWeights[i_weight];
weightPerVertex[vertexWeight.mVertexId].push_back(aiVertexWeight(i_bone, vertexWeight.mWeight));
}

aiNode* node = scene->mRootNode->FindNode(b->mName);

//Create bone transformations------------------->i think my problem is here
Bone* meshBone = new Bone();
meshBone->boneOffsetMatrix = aiMatrixtoD3DMatrix(b->mOffsetMatrix);
meshBone->localTransformMatrix = aiMatrixtoD3DMatrix(node->mTransformation);
meshBone->transformMatrix = meshBone->boneOffsetMatrix * meshBone->localTransformMatrix;
meshBone->name = node->mName.data;
node = node->mParent;
while(node)
{
meshBone->transformMatrix = aiMatrixtoD3DMatrix(node->mTransformation) * meshBone->transformMatrix;
node = node->mParent;
}
animMesh->bones.push_back(meshBone);
}
//Get weights for each vertex
for(unsigned int x = 0; x < numVertices; x++)
{
for(unsigned int y = 0; y < weightPerVertex[x].size(); y++)
{
animMesh->vertices[x].boneIndices[y] = weightPerVertex[x][y].mVertexId; // vertex id is used as bone id when creating this vector
animMesh->vertices[x].boneWeights[y] = weightPerVertex[x][y].mWeight;
}
}
for(unsigned int x = 0; x < 35; x++) //tiny.x has 35 bones
{
animMesh->boneMatrices[x] = animMesh->bones[x]->transformMatrix; //for easy use
}
}
return animMesh;
}[/code]

And shader.

[code]matrix viewMatrix;
matrix projectionMatrix;
matrix boneMatrices[35];
struct VS_In
{
float4 position : POSITION;
unsigned int4 boneIndices : BONEINDICES;
float4 boneWeights : BLENDWEIGHTS;
};
struct PS_In
{
float4 position : SV_POSITION;
};
PS_In VS_Main(VS_In vertex)
{
PS_In output = (PS_In)0;
output.position = float4(0.0f, 0.0f, 0.0f, 1.0f);
for(int i = 0; i < 4; i++)
{
output.position += vertex.boneWeights[i] * mul(vertex.position, boneMatrices[vertex.boneIndices[i]]);
}
output.position.w = 1.0f;
matrix viewProjection = mul(viewMatrix, projectionMatrix);
output.position = mul(output.position, viewProjection);
return output;
}
float4 PS_Main(PS_In frag) : SV_TARGET0
{
return float4(1.0f, 1.0f, 1.0f, 1.0f);
}
technique11 AnimatedMesh
{
pass p0
{
SetVertexShader(CompileShader(vs_5_0, VS_Main()));
SetPixelShader(CompileShader(ps_5_0, PS_Main()));
}
}[/code]

Thanks!

Share this post


Link to post
Share on other sites
programci_84    336
If you have the full source of assimp library, then you can take a look into the project named "assimp_view". It shows how to load the model, animations, skin info etc. and manage them. Also it shows how to build D3DX buffers and render. Here's the path: assimp_sdk_dir\workspaces\vc9\

btw, it's written in C++ and for DX9. So I hope you can understand.

hth.
-R

Share this post


Link to post
Share on other sites
ekba89    788
Thanks for the advice but I already knew that. In fact my code is based on it. But I looked through it again and found out that they were multiplying their matrices with mesh's inverse global matrix. So I have added the code below to my code.
[code]aiNode* node = scene->mRootNode->FindNode("body"); //mesh is in this node for tiny.x
D3DXMATRIX inverseTransform = aiMatrixtoD3DMatrix(node->mTransformation);
node = node->mParent;
while(node)
{
inverseTransform = aiMatrixtoD3DMatrix(node->mTransformation) * inverseTransform;
node = node->mParent;
}[/code]

And I have changed the code for calculating final matrices to this

[code]meshBone->localTransformMatrix = aiMatrixtoD3DMatrix(node->mTransformation);
meshBone->transformMatrix = meshBone->localTransformMatrix;
node = node->mParent;
while(node)
{
meshBone->transformMatrix = aiMatrixtoD3DMatrix(node->mTransformation) * meshBone->transformMatrix;
node = node->mParent;
}
meshBone->transformMatrix = inverseTransform * meshBone->transformMatrix * meshBone->boneOffsetMatrix;[/code]

But its still not working. Also I tried to just sending offset matrices to test it out and every piece of her body was in the (0,0,0) point but other than that it was fine. So I think there is nothing wrong with the shader and I think problem might be bones' transform matrices. But I couldn't find what is wrong with it. Lastly I tried every possible order for multiplication of transformMatrix but it didn't work. If anyone can tell me the correct order I appreciate it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this