Creating SkinnedEffect at runtime not working


I have now successfully got a collada model with 166 bones to animate. I now have run into some issues with the SkinnedEffect class. In the skinned animation example, assigning each part a specific texture works, but for my model, the texture for all parts is always the last one set. This I assume is because only one effect is created and given to all mesh parts. I find it rather strange that the FBX would have a unique shader assigned but collada does not, maybe this is because the example FBX was not created with MonoGame but with XNA?

My biggest problem right now is that I am unable to create a new SkinnedEffect for each mesh myself. When i try to replace the existing effect collection for the mesh, the animation stops, the model turns black and even setting the world matrix has no effect on the models placement. The camera can be moved but the model stays fixed in relation to the screen. I have tried both creating a new effect and cloning the existing effect, both end with the same static black pair of legs on the screen that does not move even when the camera is changed.

Is there any reason why creating a SkinnedEffect shader at runtime will not work or is this a bug? I don’t want the extra overhead of keeping effects in my custom model classes and with static models I have been able to create the shader at runtime to prevent bloat in the model file itself.


hmm this should technically work, but it might be a problem with how monogame handles the effect applying in the background.

If all mesh parts have the same shader the bone transformations only need to be sent once, but if all meshes have different shaders they need to be sent each time.

What you really want though is - each mesh has the same shader. Submit all bone transformations once per frame. Submit all textures once per shader and draw.

I understand the way monogame does it by default sucks a bit for 3d, but can you maybe provide the code snippet where you are drawing the model?
(Maybe the one where it works but the textures are wrong?)

I think we can work it out.

Well to get round the stupid 72 bone limit inherited from XNA and get my model with 166 bones to work, I have had to rewrite the blend indices for each mesh part to reference only the bones that that part needs. This means each mesh part will be given a different subset of transforms each one under the 72 bone limit. The lower body for example has no need for transforms for facial or hand bones. So I will need to set the transforms for each mesh part for each frame. This is working with the shader created in the Model but not when I try to create my own shader as a replacement. It seems very inefficient to have to check each mesh name and assign the correct texture for every draw call when the textures should be assigned once at the start.

As the model is drawn and animated correctly using the original effect from the model, but breaks when i try to assign my own, i would think it would be the code where i create the new shader that would be the problem rather than the draw code?

` foreach (ModelMesh mesh in model.Meshes)
// A) Use of existing shader works but textures must be assigned for each mesh each draw call
//SkinnedEffect skinnedEffect = mesh.Effects[0] as SkinnedEffect;

            // B) Create my own Effect
            SkinnedEffect skinnedEffect = new SkinnedEffect(game.GraphicsDevice);

            skinnedEffect.CurrentTechnique = skinnedEffect.Techniques["SkinnedEffect_PixelLighting_FourBone"];

            skinnedEffect.WeightsPerVertex = 4;
            skinnedEffect.PreferPerPixelLighting = true;
            skinnedEffect.AmbientLightColor = new Vector3(1f, 1f, 1f);

            // Asign Texture (Every mesh gets the last texture assigned here)
            if (mesh.Name == "headMesh")
                skinnedEffect.Texture = Tex_Head;
            else if (mesh.Name == "lowerBodyMesh")
                skinnedEffect.Texture = Tex_Lower;
            else if (mesh.Name == "upperBodyMesh")
                skinnedEffect.Texture = Tex_Upper;
                skinnedEffect.Texture = Tex_Head;

            // If creating my own Shader, enable this to replace the existing one
            List<Effect> EffectList = new List<Effect>();
            mesh.Effects = new ModelEffectCollection(EffectList);


So i found out that the way i was assigning the effect, by creating a new ModelEffectCollection passing that to ‘Mesh.Effects’ was the problem. If I set the ‘ModelMeshPart.Effect’ property with the new skinned effect it does work.