• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Waaayoff

Assimp/DX11 problem - Skinning won't work :( --- FIXED!

4 posts in this topic

I'm trying to render a skinned mesh. For now i can't even render one without any animation. I just calculate the combined matrix by multiplying the offset matrix of each bone with the combined local transformation, like this:

I call this function with the root joint and an identity matrix
[code]void AnimationController::CombineTransforms(Joint* pJoint, const D3DXMATRIX& P)
{
D3DXMATRIX transf = pJoint->mLocalTransf /** pJoint->mAnimatedTransf*/ * P;

mFinalTransforms.push_back( pJoint->mOffsetTransf * transf );

for (unsigned i = 0; i < pJoint->mChildren.size(); i++)
{
CombineTransforms(pJoint->mChildren[i], transf);
}
}[/code]

I get the matrices from assimp:
mLocalTransf = transformation in aiNode with the bone's name
mOffsetTransf = offset transformation in aiBone struct

Now in my understanding, mFinalTransforms should be filled with identity matrices. But it isn't! By sending this to my vertex shader, i get the following result:

[code]cbuffer c_buffer
{
float4x4 World;
float4x4 WorldViewProj;
float4x4 FinalTransforms[100];
float3 Diffuse;
}

VS_OUT VShader(float4 position : POSITION, float4 normal : NORMAL, float2 texcoord : TEXCOORD, float4 weights : BLENDWEIGHT, int4 boneIndices : BLENDINDICES)
{
VS_OUT output;

// Apply skinning
float4 p = float4(0.0f, 0.0f, 0.0f, 1.0f);
float lastWeight = 0.0f;
int n = 3;

for(int i = 0; i < n; ++i)
{
lastWeight += weights[i];
p += weights[i]* mul(position, FinalTransforms[boneIndices[i]]);
}
lastWeight = 1.0f - lastWeight;
p += lastWeight * mul(position, FinalTransforms[boneIndices[n]]);
p.w = 1.0f;

output.position = mul(WorldViewProj, p);
output.color = float4(0.7, 0.7, 0.7, 1);
output.texcoord = texcoord;
return output;}[/code]
[img]http://img705.imageshack.us/img705/5489/wtfzat.png[/img]

What is going on??
Oh and this is how it's supposed to look like:
[img]http://img10.imageshack.us/img10/8210/goodk.png[/img]
0

Share this post


Link to post
Share on other sites
Okay i think i know what's wrong. The root bone's local transform != identity matrix. I think i'm supposed to multiply it with the aiNodes parents transforms (armature node, scene node, etc...). I'll get back to you.

Edit: Didn't work.. I was so sure it would :(
0

Share this post


Link to post
Share on other sites
Okay so i ditched assimp's offset matrix and calculated it on my own:


[code]void AnimationController::CalculateOffsets(Joint* pJoint, const D3DXMATRIX& P)
{
D3DXMATRIX combined = pJoint->mLocalTransf * P;

D3DXMatrixInverse(&pJoint->mOffsetTransf, 0, &combined);

for (unsigned i = 0; i < pJoint->mChildren.size(); i++)
{
CalculateOffsets(pJoint->mChildren[i], combined);
}
}[/code]


And this is how i create the final transformation that's passed on to the shader:
[code]void AnimationController::CombineTransforms(Joint* pJoint, const D3DXMATRIX& P)
{
D3DXMATRIX final = pJoint->mLocalTransf * pJoint->mAnimatedTransf * P;

mFinalTransforms.push_back( pJoint->mOffsetTransf * final );

for (unsigned i = 0; i < pJoint->mChildren.size(); i++)
{
CombineTransforms(pJoint->mChildren[i], final);
}
}[/code]


When pJoint->mAnimatedTransf is equal to the identity matrix, as expected the model is rendered in its default T-pose. But if i change one bone's pJoint->mAnimatedTransf to a rotation matrix, it doesn't really animate well... I think its rotating globally, not locally...

This is how i calculate the matrix: D3DXMatrixRotationY(&transf, mTime/100);

Any help would be really appreciated....
0

Share this post


Link to post
Okay so i ditched assimp's offset matrix and calculated it on my own:


[code]void AnimationController::CalculateOffsets(Joint* pJoint, const D3DXMATRIX& P)
{
D3DXMATRIX combined = pJoint->mLocalTransf * P;

D3DXMatrixInverse(&pJoint->mOffsetTransf, 0, &combined);

for (unsigned i = 0; i < pJoint->mChildren.size(); i++)
{
CalculateOffsets(pJoint->mChildren[i], combined);
}
}[/code]


And this is how i create the final transformation that's passed on to the shader:
[code]void AnimationController::CombineTransforms(Joint* pJoint, const D3DXMATRIX& P)
{
D3DXMATRIX final = pJoint->mLocalTransf * pJoint->mAnimatedTransf * P;

mFinalTransforms.push_back( pJoint->mOffsetTransf * final );

for (unsigned i = 0; i < pJoint->mChildren.size(); i++)
{
CombineTransforms(pJoint->mChildren[i], final);
}
}[/code]


When pJoint->mAnimatedTransf is equal to the identity matrix, as expected the model is rendered in its default T-pose. But if i change one bone's pJoint->mAnimatedTransf to a rotation matrix, it doesn't really animate well... I think its rotating globally, not locally... [url="http://youtu.be/OtYaw8RQVO0"]http://youtu.be/OtYaw8RQVO0[/url]

This is how i calculate the matrix: D3DXMatrixRotationY(&transf, mTime/100);

Any help would be really appreciated....

EDIT: How do i embed a youtube video?
0

Share this post


Link to post
Share on other sites
[quote name='Waaayoff' timestamp='1320165509' post='4879283']
FINALLY! It worked.

Turns out Assimp generates animations relative to the parent joint, NOT the joint itself. So i don't have to multiply the animation transformation by the local transformation. Which i only use if there is no animation for a bone.. Also there was a problem with my shader. Instead of using the last bone to make sure a total weight of 1 is used, i use the first bone.. since there is no guarantee that the vertex will be influenced by 4 bones.

Oh and the Assimp's offset transformation works..

Note to Assimp/Directx users:
1) When loading a scene don't forget to use this flag: aiProcessPreset_TargetRealtime_Quality | aiProcess_ConvertToLeftHanded
2) You might also want to remove aiProcess_FindInvalidData. If you keep it, Assimp will remove redundant keys, leaving you with an uneven number of rotation/position/scale keys per bone.
3) Transpose both local and offset transformations.

If anyone's interested, here's the code:
[code]//=====================================================================================================
// Recursively calculate the joints' combined transformations
//=====================================================================================================
void AnimationController::CombineTransforms(Joint* pJoint, const D3DXMATRIX& P)
{
// pJoint->mAnimatedTransf is initialized with Assimp's local transform (which you can find like this: g_Scene->mRootNode->FindNode(bone_name)->mTransformation)
// Then it can be replaced per frame by an interpolated animation transformation for every bone that has an animation
// pJoint->mOffsetTransf you can find in an aiBone struct
// DO NOT FORGET TO TRANSPOSE when you load them

D3DXMATRIX final = pJoint->mAnimatedTransf * P;

//mFinalTransforms contains the matrices that will be sent to the shader
mFinalTransforms.push_back( pJoint->mOffsetTransf * final );

for (unsigned i = 0; i < pJoint->mChildren.size(); i++)
{
CombineTransforms(pJoint->mChildren[i], final);
}
}
[/code]



Vertex Shader
[code]VS_OUT VShader(float4 position : POSITION, float4 normal : NORMAL, float2 texcoord : TEXCOORD, float4 weights : BLENDWEIGHT, int4 boneIndices : BLENDINDICES)
{
VS_OUT output;

float4 p = float4(0.0f, 0.0f, 0.0f, 1.0f);
float lastWeight = 0.0f;
int n = 3;

for(int i = n; i > 0; i--)
{
lastWeight += weights[i];
p += weights[i] * mul(FinalTransforms[boneIndices[i]], position);
}

lastWeight = 1.0f - lastWeight;
p += lastWeight * mul(FinalTransforms[boneIndices[0]], position);
p.w = 1.0f;

output.position = mul(WorldViewProj, p);
output.color = float4(0.7, 0.7, 0.7, 1);
output.texcoord = texcoord;
return output;
}
[/code]

Hi, I'm trying to extract bones for the bind pose from assimp as well and I'd like to extract the animation frames as well. Right now I'm having a problem in the number of bone weights that influence each vertex. I tried to specify the flag aiProcessPreset_TargetRealtime_Quality which include also aiProcess_LimitBoneWeights which is supposed to cut the number to 4 (as stated in the assimp documentation). Thing is ... it doesn't work and I still get loads of weights per vertex when I iterate through the mBones array in the mesh.
On top of this if you have some link or tutorial or forum post that explain how to extract bind bose matrices from Assimp and how to animate the model I'll appreciate that.
In the meantime what I understand is that:
[code]
struct aiBone
{
//! The name of the bone.
C_STRUCT aiString mName;

//! The number of vertices affected by this bone
//! The maximum value for this member is #AI_MAX_BONE_WEIGHTS.
unsigned int mNumWeights;

//! The vertices affected by this bone
C_STRUCT aiVertexWeight* mWeights;

//! Matrix that transforms from mesh space to bone space in bind pose
C_STRUCT aiMatrix4x4 mOffsetMatrix;

...

};
[/code]

mOffsetMatrix transform to bind pose ? so I should apply this straight away ? or what ?

But still, if limit bone weights doesn't cut to 4 I'm wasting time...

[/quote]
0

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  
Followers 0