Issues showing animated model on screen

Hello.

Lately I’ve been experimenting with 3D and trying to load animated models into the game. After some research I’ve found out how it’s supposed to be done, so I’ve attempted to do it myself following SkinnedModel tutorial , buuut… I’ve come across few obstacles I don’t know how to deal with.

There are actually 2 problems with might be caused by the same issue:

  1. On one model, I’m getting Value does not fall within the expected range exception when calling SkinnedEffect.SetBoneTransforms(Matrix[]) method. Matrix array containing animation transformations is properly populated, so I really have no idea what the problem is.
  2. On few other models, I’m not getting anything rendered on screen at all. However, if I comment the line containing SetBoneTransforms() call, I do get something on screen… but (most probably) way oversized.

Example (I think lack of texture is unrelated though):

The sample code using Aether.Extras (same thing happens with BetterSkinnedModel as well):

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using tainicom.Aether.Animation;

namespace _3DFightTest
{
    /// <summary>
    /// This is the main type for your game.
    /// </summary>
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Matrix _world;
        Matrix _view;
        Matrix _projection;

        Model _knight;
        Animations _animations;
        
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            _world = Matrix.CreateTranslation(Vector3.Zero);
            _view = Matrix.CreateLookAt(new Vector3(0, 500, 500), Vector3.Zero, Vector3.Up);
            _projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), GraphicsDevice.Viewport.AspectRatio, 0.1f, 1000f);

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
            _knight = Content.Load<Model>("Animated Human");
            _animations = _knight.GetAnimations();
            _animations?.SetClip(_animations.Clips["Human Armature|Idle"]);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// game-specific content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            // TODO: Add your update logic here
            _animations?.Update(gameTime.ElapsedGameTime, true, Matrix.Identity);

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            foreach (var mesh in _knight.Meshes)
            {
                foreach (var part in mesh.MeshParts)
                {
                    var effect = part.Effect as SkinnedEffect;

                    effect.SetBoneTransforms(_animations.AnimationTransforms);
                    effect.World = _world;
                    effect.View = _view;
                    effect.Projection = _projection;

                    effect.EnableDefaultLighting();
                }

                mesh.Draw();
            }

            base.Draw(gameTime);
        }
    }
}

Now, I’ve tried multiple things to resolve issues, and only managed to resolve when model has more bones that the max limit allows for. Other issues have already started to frustrate me greatly.

What I’ve already tried:

  1. Using both SkinnedModel and BetterSkinnedModel to extend Content Pipeline (with appropriate loading and drawing code from my side)
  2. Using @nkast’s Aether.Extras extension for Monogame (preferred due to how code is used and the fact that it’s possible to define max amount of bones in Content Pipeline tool)
  3. Testing with different models

What I did not yet try:

  1. Using Bos FBX Importer/Exporter as suggested by @KonajuGames
  2. Making my own animated model in Blender

Now, from what I’ve understood, at this moment it’s not strictly problem with the code (either Monogame’s default or extensions), but with the model itself. I’ve also read that models should be in T-position when loading, and I’ve changed one model accordingly, but it didn’t help. Since I’ve pretty much exhausted possible solutions (as mentioned Bos FBX exporter) and I’d really like things to be as much out-of-the-box as possible (easier to restore things), I’m turning here for some help and suggestions. I just hope problem isn’t related to Blender… and that I won’t need to switch to Unity X)

Thanks in advance!

EDIT: I’ve also tried using Blender importer extension for Content Pipeline. While it did fix the “Value not in expected range” issue with one model, said model is still deformed. With other model I managed somehow to get part of it on screen, but… yeah, it’s unrecognizable too and I have no idea what the issue is.

You can try to swap the winding order to True when importing ^_^y

I don’t know why FBX is so popular while it’s the most complicated animated mesh file structure, If winding orders failed theres a few things you can try, export your FBX file to another animated mesh file such X(DirectX), MS3D(MilkShape), DAE(Collada) and try which format works perfectly in MG, these formats are supported by Assimp which MomoGame is using to import mesh file.

I don’t know why FBX is so popular while it’s the most complicated animated mesh file structure,

Because if you use the proper FBXSDK it’s a complete cake-walk to work with. You load a file, run it’s built in canonicalizing utilities that deal with all of the nonsense, and then get your data out. In less than 1,500 lines you can load and export the meshes, skeleton, blend-shapes, animations, materials, and IK controllers.

The FBXSDK is a total dream to work with in comparison to most vendor libraries.

"Because if you use the proper FBXSDK it’s a complete cake-walk to work with. "

I don’t think ASSIMP is using FBXSDK, Monogame is using Assimp to load mesh file ^ _^ y

Then I’ll toss a content processor that does on github tomorrow. Kind of weird that there isn’t a working one floating around already.

What’s the size of the Matrix[] that you pass in the SetBoneTransforms()?
SkinnedEffect has a limit of 72 bones.

If that’s the case and you have more than 72 bones you can try the CPU Skinned sample (XNA catalog). Aether.Animation has a CPU importer and you can with switch to it with some minor changes in the code.

But I wouldn’t rule out this being an issue with the model and/or the importer.
Can you post the stacktrace and the exception message?
vtw, the model also need to have 4 bones per vertex or less.

Let’s see… model which causes the exception gives the Matrix[] of size 73, so that’s one issue explained. Ticking “FixRealBoneRoot” doesn’t help, neither does “SwapWindingOrder” as per @DexterZ 's suggestion.

As requested, exception message is "Value does not fall within the expected range".
Stacktrace (formatted for readability):

at Microsoft.Xna.Framework.Graphics.SkinnedEffect.SetBoneTransforms(Matrix[] boneTransforms)
at _3DFightTest.Game1.Draw(GameTime gameTime) in C:\\Users\\Matic\\Source\\Repos\\3DFightTest\\3DFightTest\\Game1.cs:line 109
at Microsoft.Xna.Framework.Game.DoDraw(GameTime gameTime)
at Microsoft.Xna.Framework.Game.Tick()
at Microsoft.Xna.Framework.SdlGamePlatform.RunLoop()
at Microsoft.Xna.Framework.Game.Run(GameRunBehavior runBehavior)
at _3DFightTest.Program.Main() in C:\\Users\\Matic\\Source\\Repos\\3DFightTest\\3DFightTest\\Program.cs:line 17

Blender file importer which I used, however, gives the array length of 51. Other model gives the same discrepancy, with .fbx giving 51 bones and .blend 44. I’ve managed to figure out what the discrepancy is with a couple of Debug.Write() statements; turns out my .fbx models have couple of leaf bones which are not present in the original (which ups the amount of bones in knight model beyond limit), so that’s probably the problem with export.

I’ve also managed to get model size in line by multiplying world matrix with scaling matrix, so only model deformation remains (“noodle limbs” being the most prominent). At this point, after reading post with similar issue, I’m suspecting it’s the problem with Blender itself. Will report if I fix things, but until then, I’m open for all additional suggestions.

EDIT: I found out the reason for deformation in one model I’ve been testing - part of the skeleton armature is missing in the model itself. More precisely, limbs do not have bones in them. Great. That still doesn’t explain the deformation of the other model…

Because FBX is a complicated file structure, different vendor or engine is using their own implementation of import/export some are limited and others has some extra features.

You may try to export to an X animated mesh file and try to import X file to MG.

Did you get a chance to upload a processor for FBX? That format is a pain to work with, and anything that handles it better than ASIMP currently does would be welcome.

Thanks!

. . .

Ooook. I’ve fixed the issue with my model.
What was the source of the problem?

Model had multiple animations mapped for it. It is absolutely essential that there is another animation containing only rest pose, and that it’s the first animation of them all. I’d need someone to confirm that or correct me, but my assumption is that Monogame uses first animation clip as a reference point when doing animation transformations.

Good to know.

Anyway, thanks to everyone for help. I’ll leave it open a bit until I try few more models, then I’ll tag the title with [Solved] if everything works out. ^^
Until then, I’ll appreciate any other suggestions and advices.

@YTN, not yet. Worked on ImGuiCLI stuff all day. I’m 1/2 way through doing this FBX stuff.

Just need to write the stuff that maps the C++/CLI (it can be converted to PInvoke later once everything is known and not fluxing) inputs to the content pipeline’s ModelContent then I can start testing. So, probably be working tomorrow unless the pipeline throws a massive wrench at me - just might not be working 100% right.

I’ll worry about mapping to the stuff in Aether.Extras later for animation and the like, targeting the same output seems like the right idea … it doesn’t look like much of a hassle other than being more content pipeline psychosis (so glad I deal with resources my own way, the content pipeline is awful).