I just noticed you should also reverse the multilcation of GlobalTransformation like
XMMATRIX GlobalTransformation = NodeTransformation * ParentTransform;
I just noticed you should also reverse the multilcation of GlobalTransformation like
XMMATRIX GlobalTransformation = NodeTransformation * ParentTransform;
I accept the idea of testin with a simple model
so got simple models of two bone
first It is ideal result
It has a blue circle with its aixs of rotation
(com up and down around the axis)
but my result ( fix transpos ploblem and GlobalTransformation and etc...) is like this
the axis is center of the cube
it also come up and down but different axis give completely different results
I attach my modified codes
1. load bone data
void LoadModel::InitBones(UINT index, const aiMesh* pMesh)
{
for (UINT i = 0; i < pMesh->mNumBones; ++i) {
int BoneIndex = -1;
string BoneName(pMesh->mBones[i]->mName.data);
int tmpIndex = 0;
for (const auto& p : m_Bones) {
if (p.first == BoneName) {
BoneIndex = tmpIndex;
break;
}
tmpIndex++;
}
if (BoneIndex < 0) {
BoneIndex = (int)m_Bones.size();
Bone bone;
bone.BoneOffset = aiMatrixToXMMatrix(pMesh->mBones[BoneIndex]->mOffsetMatrix);
m_Bones.emplace_back(make_pair(BoneName, bone));
}
const aiBone* pBone = pMesh->mBones[BoneIndex];
for (UINT b = 0; b < pBone->mNumWeights; ++b) {
UINT vertexID = pBone->mWeights[b].mVertexId;
float weight = pBone->mWeights[b].mWeight;
m_meshes[index].m_vertices[vertexID].AddBoneData(BoneIndex, weight);
}
}
}
2. ReadNodeHeirarchy
void LoadAnimation::ReadNodeHeirarchy(float AnimationTime, const aiNode * pNode, const XMMATRIX& ParentTransform)
{
string NodeName(pNode->mName.data);
const aiAnimation* pAnim = m_pScene->mAnimations[0];
XMMATRIX NodeTransformation = aiMatrixToXMMatrix(pNode->mTransformation);
const aiNodeAnim* pNodeAnim = FindNodeAnim(pAnim, NodeName);
if (pNodeAnim) {
aiVector3D s;
CalcInterpolatedScaling(s, AnimationTime, pNodeAnim);
XMMATRIX ScalingM = XMMatrixScaling(s.x, s.y, s.z);
aiQuaternion q;
CalcInterpolatedRotation(q, AnimationTime, pNodeAnim);
XMMATRIX RotationM = XMMatrixRotationQuaternion(XMVectorSet(q.x, q.y, q.z, q.w));
aiVector3D t;
CalcInterpolatedPosition(t, AnimationTime, pNodeAnim);
XMMATRIX TranslationM = XMMatrixTranslation(t.x, t.y, t.z);
NodeTransformation = ScalingM * RotationM * TranslationM;
}
XMMATRIX GlobalTransformation = NodeTransformation * ParentTransform;
for (auto& p : m_Bones) {
if (p.first == NodeName) {
p.second.FinalTransformation =
m_GlobalInverse * GlobalTransformation * p.second.BoneOffset;
break;
}
}
for (UINT i = 0; i < pNode->mNumChildren; ++i) {
ReadNodeHeirarchy(AnimationTime, pNode->mChildren[i], GlobalTransformation);
}
}
aiMatrixToXMMatrix function is like your(Ivan Terziev) function
i want you to take a look at it
very thanks!
Make it even simpler I think, why is the root bone (which is the root?) moving at all? Put the root bone start from the origin pointing along one axis, and only move the second bone, perhaps at 0 degrees (straight) (should be just a translate, no rotate component), 45 and 90. It kind of looks like the order of translate / rotate might be wrong, but it will be easier to see with more simplified. (I'm not even looking at the code, there's too many permutations for my tiny brain lol).
If it helps this is what I do:
// local bone combined matrix
matBoneLocal = matBoneLocalTrans * matBoneLocalRot;
// global bone matrix is combined with parent matrix
matBone = matParent * matBoneLocal;
// the skinning matrix also combines back transform to get vertices into 'bone space'
matSkin = matBone * matRestInverse;
That last step probably isn't necessary if you store your skin verts in 'bonespace', i.e. pretransform them back to be rooted from the origin and pointing along the default axis. You can find out whether you need this by just drawing the skin with identity matrix and seeing what it looks like, whether it looks like the character in rest pose, or all the bones on top of each other.
On 2018. 2. 1. at 6:00 PM, lawnjelly said:Make it even simpler I think, why is the root bone (which is the root?) moving at all? Put the root bone start from the origin pointing along one axis, and only move the second bone, perhaps at 0 degrees (straight) (should be just a translate, no rotate component), 45 and 90. It kind of looks like the order of translate / rotate might be wrong, but it will be easier to see with more simplified. (I'm not even looking at the code, there's too many permutations for my tiny brain lol).
You inspired me! thanks
I ignored the animation imported from assimp and just tried rotation the bones
and As a result, I found the axis of rotaion to be strange.
As I predicted above, the axis was applied differently from the original (the center of the second mesh)
So many of the advice and functions we've got from above seem to have been inadequately applied
And i have one question
Maybe i misunderstood, Are you telling me not to apply all animations from root node?
I think that read all child nodes from the root node and multiply the transformations( rot, scaling, shifting)
and if current node is bone, apply the multiplied transformation value up to now
It is wrong???
Hey Guys
I've completely fixed everything!
It's matter about transpos matrix
Previously, I applied transpos function to the bone offset and mTranslation of the node
(that is, i applied transpos when I read aiMatrix4x4)
but after trying many different things, I found it to be wrong
Exactly, there is an aiMatrix4x4 which should apply transpos and aiMatrix4x4 should not apply
In my case, I applied transpos only result of transformation
This is my codes
void LoadAnimation::ReadNodeHeirarchy(float AnimationTime, const aiNode * pNode, const XMMATRIX& ParentTransform)
{
string NodeName(pNode->mName.data);
const aiAnimation* pAnim = m_pScene->mAnimations[0];
XMMATRIX NodeTransformation = XMMATRIX(&pNode->mTransformation.a1);
//I just read aiMatrix4x4 (aiMatrix to XMMATRIX format)
const aiNodeAnim* pNodeAnim = FindNodeAnim(pAnim, NodeName);
XMMATRIX anim = XMMatrixIdentity();
if (pNodeAnim) {
aiVector3D s;
CalcInterpolatedScaling(s, AnimationTime, pNodeAnim);
XMMATRIX ScalingM = XMMatrixScaling(s.x, s.y, s.z);
aiQuaternion q;
CalcInterpolatedRotation(q, AnimationTime, pNodeAnim);
XMMATRIX RotationM = XMMatrixRotationQuaternion(XMVectorSet(q.x, q.y, q.z, q.w));
aiVector3D t;
CalcInterpolatedPosition(t, AnimationTime, pNodeAnim);
XMMATRIX TranslationM = XMMatrixTranslation(t.x, t.y, t.z);
NodeTransformation = ScalingM * RotationM * TranslationM;
NodeTransformation = XMMatrixTranspose(NodeTransformation);
//I applied transpos
}
XMMATRIX GlobalTransformation = ParentTransform * NodeTransformation;
for (auto& p : m_Bones) {
if (p.first == NodeName) {
p.second.FinalTransformation =
m_GlobalInverse * GlobalTransformation * p.second.BoneOffset;
break;
}
}
for (UINT i = 0; i < pNode->mNumChildren; ++i) {
ReadNodeHeirarchy(AnimationTime, pNode->mChildren[i], GlobalTransformation);
}
}
If I read bone offset and mTransformation about node(aiMatrix4x4),
I simply transformed it into XMMATRIX format
// XMMATRIX(&aiMatrix4x4.a1)
second, If current node is a node belonging to the animation channel, and S R T transformation is performed,
transpos is applied to the transformation
The important this is that we don't apply the transpos to the parent nodes matrix
(if parent node conduct transpos function, there is a risk that it will be performed twice)
This is the result
PS. I hope this post helps people using directX and assimp
assimp library has some bugs that some models using fbx format are broken
I know that the assimp team is fixing it
I was able to observe that, in general, if the viewer provided by assimp show broken results,
my result are also broken.