Tutorial: How to get XNA's SkinnedSample working with MonoGame

I am wondering, how did you get it to work. I was unfortunately unable to get either one to work. I eventually got every class correct and the proper keyframe. Then called the drawingmethod as done in the skinnendexample, but i can’t see the model anywhere. Could you possible give me some advice on how to fix it?

And would it also be possible ot make the animation move on a plane?

Thanks and I am sorry if I have made a simple mistake.

:frowning:

I got it to work by following step by step from the tutorial, nothing changed.
BUT
I don’t use the default monogame shaders for any 3d, I have setup custom shaders for everything. They are almost the same as the normal monogame skinned effect ones, but obviously not ideal for someone who doesn’t want to involve custom shaders.

I too, have no idea how to make 3d objects appear on screen with the normal model.draw(…) way, somehow monogame is super confusing about that. In xna you could just call model.draw(…) and stuff would appear with simple shading.

That’s my one problem why I don’t release a tutorial and sample straight up, because I never use the default monogame shading.

@Jjagg @KonajuGames maybe you can provide help?

If you just use BasicEffect and do EnableDefaultLighting things should work. That said, there are some issues with the model classes and they’re mostly untested (in the test suite at least). Effects are untested too. I have this on my TODO list.

I did that and it didn’t work for some reason.

Anyways, why is EnableDefaultLighting not enabled by default?

I guess that’s how it is in XNA? If not we should fix that.

Oké, I did this for my drawing:

// Render the skinned mesh.
    foreach (ModelMesh mesh in impModel.Meshes)
    {
        foreach (SkinnedEffect effect in mesh.Effects)
        {
            effect.SetBoneTransforms(bones);

            effect.View = view;
            effect.Projection = projection;

            effect.EnableDefaultLighting();

            effect.SpecularColor = new Vector3(0.25f);
            effect.SpecularPower = 16;
        }

        mesh.Draw();
    }

And my model is called impModel. I also have added an effect.world and used the projection and view matrices from my camera:

  effect.World = worldMatrix;
            effect.EnableDefaultLighting();
            effect.View = camera.View;
            effect.Projection = camera.Projection;

Matrix worldMatrix = transformMatrix[mesh.ParentBone.Index] * Matrix.CreateRotationY(rotation) * Matrix.CreateTranslation(position);
Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, game.GraphicsDevice.Viewport.AspectRatio, 0.05f, 1000.0f);

and my view matrix is

 Matrix.CreateLookAt(cameraPosition, cameraLookAt, Vector3.Up);

So my lightingeffect is enabled or am I missing something?
Any thoughts by any chance?

Looks like you forgot to draw the mesh for each pass of an effect.

I am doing mesh.Draw() right? Or do you mean that I am missing something in the foreach effect loop?

Nvm. That’s not how it goes.

Maybe I’m too much used to custom effects, but isn’t there an effect.Technique[0].passes[0].apply() ?
By calling Draw, how does it know is must use this effect ?

Thanks for the responses guys.

I have put that line into my code now, but I does not look like it is making a difference.

Nono all the effect things are called by mesh.draw()

1 Like

Yeah, BetterSkinned is a significant improvement over SkinnedSample. I’ve since removed SkinnedSample and added BetterSkinned to my game using the same methods I detailed in the original post, but…

BetterSkinned does have a few of its own problems. First off, I had to write my own blending function (to change from one animation to another smoothly). Second off, it doesn’t handle scaling of bones. Try as I might, I couldn’t get it to scale bones properly without making the animation into a jumbled mess (you wouldn’t happen to know how to fix that, would you? Pleeeeaaasee…).

i am not a modeller- can you create a basic mesh that has (an) expanding / scaling bone(s) for me? just some random animation with scaling thrown in.
By the way, in your modeling program, make sure to limit bones-per-vertex or “influence per vertex” or similar to 4.

In theory it should handle scaling, since it’s just quaternion interpolation

I thought about that, too. Basically save teh current bone matrices and blend them to the first keyframe of the new animation and then play the animation is something I’ll try

I tried the “influence per vertex” thing. I think it was already on by default, but regardless it didn’t work.

I’ll link you a basic model I’ve rigged, but I don’t know how easy it would be to import into your project (if the texture isn’t in the right directory, the ContentManager throws an error). The model is meant to double the scale of the body every animation loop of “Armature|bounce”.

Here you go: Link

Oké I have made my animated model move finally. I can see that after a while it is on my position and collides with me. But for some reason I still don’t see the model displayed on my screen. For my static models, I use these methods to draw the models where I want them to be:

public void DrawIndexedPrimitives(BasicEffect effect, ModelMeshPart meshPart)
{
    foreach (EffectPass pass in effect.CurrentTechnique.Passes)
    {
        pass.Apply();
        graphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
        graphicsDevice.Indices = meshPart.IndexBuffer;
        graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, meshPart.VertexOffset, meshPart.StartIndex, meshPart.PrimitiveCount);
    }
}

After I have done this:

/* Method for drawing a model mesh. It also takes in account the rotation for
 * cases such as enemies facing certain directions. The Vector4 is used to 
 * both hold the position and the rotation. */
public void DrawModelMesh(string modelName, float rotation, Vector3 position)
{

    Model model = DOOM.AssetManager.GetModel(modelName);

    //Creates an array of Matrices for each parent bone
    Matrix[] transformMatrix = new Matrix[model.Bones.Count];

    //Fills the arrays of the previously made array of Matrices with the matrix information of each bone
    model.CopyAbsoluteBoneTransformsTo(transformMatrix);


    foreach (ModelMesh mesh in model.Meshes)
    {
        //Seperately calculates the world matrix for each parent bone in the Matrix array
        Matrix worldMatrix = transformMatrix[mesh.ParentBone.Index] * Matrix.CreateRotationY(rotation) * Matrix.CreateTranslation(position);

        foreach (ModelMeshPart meshPart in mesh.MeshParts)
        {
            BasicEffect effect = (BasicEffect)meshPart.Effect;
            effect.World = worldMatrix;
            effect.EnableDefaultLighting();
            effect.View = camera.View;
            effect.Projection = camera.Projection;
            DrawIndexedPrimitives(effect, meshPart);
        }
    }
}

I have tried to rewrite the first method to make it work with the animated model. But I have been unable to make it work. Or should the piece of code I have written as seen in a different comment just work?

You have to use SkinnedEffect instead of BasicEffect.

In your content, where oyu load the entity, you also have to set it to SkinnedEffect

I’ll check that later today, but i did try to import into blender and the model has no visible animation there.

1 Like

Thank you for your response

In the pipeline it is put to SkinnedEffect and I have rewritten the methods to this but to no avail:

public void DrawIndexedPrimitivesAnimation(SkinnedEffect effect, ModelMeshPart meshPart)
{
    foreach (EffectPass pass in effect.CurrentTechnique.Passes)
    {
        pass.Apply();
        graphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
        graphicsDevice.Indices = meshPart.IndexBuffer;
        graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, meshPart.VertexOffset, meshPart.StartIndex, meshPart.PrimitiveCount);
    }
}

And:

     Vector3 vector = Vector3.Subtract(camera.Position, impPos);
    Matrix[] bones = animationPlayer.GetSkinTransforms();
    Matrix[] transformMatrix = new Matrix[impModel.Bones.Count];
    // Compute camera matrices.
    Matrix view = camera.View;
    Matrix projection = camera.Projection;

    foreach (ModelMesh mesh in impModel.Meshes)
    {
        Matrix worldMatrix= transformMatrix[mesh.ParentBone.Index] * Matrix.CreateRotationY((float)Math.Atan2(vector.X, vector.Z)) * Matrix.CreateTranslation(impPos);

        foreach (ModelMeshPart meshPart in mesh.MeshParts)
        {

            foreach (SkinnedEffect effect in mesh.Effects)
            {
                effect.View = view;
                effect.Projection = projection;
                effect.World = worldMatrix;

                effect.EnableDefaultLighting();

                effect.SpecularColor = new Vector3(0.25f);
                effect.SpecularPower = 16;
                effect.Techniques[0].Passes[0].Apply();
                
                DOOM.DrawingManager.DrawIndexedPrimitivesAnimation(effect, meshPart);
            }
        }
        mesh.Draw();

I am probably doing something very easy wrong. But i have no clue what I am doing wrong.

Once again, thanks everyone

Yeah, Blender is a bit weird when it comes to complex FBX imports. I assure you though, the model I’ve provided I’ve loaded into my own game just fine. I don’t know if it helps, but I did tick !Experimental: Apply Transforms in Blender when I exported it.

well ok, but I don’t think there will be an animation in the game if there is no animation in blender?

All the other FBX i’ve imported worked in blender, too.