private void ImportJoints(int frameIdx, Dictionary <string, Quaternion> jointRotations, ref Vector3 rootTranslation, Node joint, Node parentJoint)
        {
            string jointName = joint.Name;

            if (!inverseBindPosesByJointName.TryGetValue(jointName, out Matrix invBindPose))
            {
                return;
            }

            Matrix relAnimPose;

            if (frameIdx < 0)
            {
                relAnimPose = ColladaUtils.MatrixFromString(joint.Matrix);
            }
            else
            {
                relAnimPose = animationPosesByJointName[jointName][frameIdx];
            }

            Matrix bindPose           = bindPosesByJointName[jointName];
            Matrix bindTranslation    = Matrix.Translation(bindPose.TranslationVector);
            Matrix invBindTranslation = Matrix.Translation(-bindPose.TranslationVector);

            Matrix parentBindPose = parentJoint != null ? bindPosesByJointName[parentJoint.Name] : Matrix.Identity;

            Matrix invBindPoseWithoutTranslation = invBindPose;

            invBindPoseWithoutTranslation.TranslationVector = Vector3.Zero;

            Matrix local = invBindPoseWithoutTranslation * relAnimPose * parentBindPose * invBindTranslation;

            local.Decompose(out Vector3 localScale, out Quaternion localRotation, out Vector3 localTranslation);

            if (!Vector3.NearEqual(localScale, Vector3.One, Epsilon))
            {
                throw new ArgumentException("local joint transform has a non-unity scale");
            }

            if (parentJoint != null)
            {
                if (!Vector3.NearEqual(localTranslation, Vector3.Zero, Epsilon))
                {
                    throw new ArgumentException("local joint transform has a non-zero translation");
                }
            }
            else
            {
                rootTranslation = localTranslation;
            }

            jointRotations[jointName] = localRotation;

            foreach (Node child in joint.Nodes)
            {
                ImportJoints(frameIdx, jointRotations, ref rootTranslation, child, joint);
            }
        }
 private void LoadAnimationPoses()
 {
     foreach (var animation in root.LibraryAnimations.Animations)
     {
         string   jointName = animation.Name;
         Matrix[] poses     = ColladaUtils.MatricesFromString(animation.Sources.Single(s => s.Id.EndsWith("-output-transform")).FloatArray);
         animationPosesByJointName[jointName] = poses;
     }
 }
        private void LoadBindPoses()
        {
            //Assumes bind_shape_matrix is Identity

            List <Source> controllerSources = root.ControllerLibrary.Controllers[0].Skin.Sources;

            string[] jointNames = controllerSources.Find(s => s.Id.EndsWith("-Joints")).NameArray
                                  .Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
            Matrix[] inverseBindPoses = ColladaUtils.MatricesFromString(controllerSources.Find(s => s.Id.EndsWith("-Matrices")).FloatArray);

            if (inverseBindPoses.Length != jointNames.Length)
            {
                throw new InvalidOperationException("expected equal number of bind poses and weights");
            }

            for (int i = 0; i < jointNames.Length; ++i)
            {
                Matrix mat = inverseBindPoses[i];
                inverseBindPosesByJointName[jointNames[i]] = mat;
                mat.Invert();
                bindPosesByJointName[jointNames[i]] = mat;
            }
        }