Search code examples
xnamonogame

Custom Default Effect in Monogame Content Pipeline


So I ended up writing my first HLSL Shader for MonoGame, and managed to somehow connect it to a Model I want to draw. So far so good. However the "somehow managed to do it code" is in my opinion ugly, and probably not the Intended way to achieve this:

internal Model(ContentManager content)
{
    mModel = content.Load<Microsoft.Xna.Framework.Graphics.Model>("models/CustomModel");
    // individual effect for individual models
    var effect = content.Load<Effect>("effects/CustomEffect").Clone();
    effect.Parameters["Texture"].SetValue(mModel.Meshes[0].MeshParts[0].Effect.Parameters["Texture"].GetValueTexture2D());

    foreach (var mesh in mModel.Meshes)
    {
        foreach (var meshPart in mesh.MeshParts)
        {
            meshPart.Effect = effect;
        }
    }
}

As you can see I load in my Model and the effect individually and replace all the BasicEffects of the model with my newly loaded custom effect. And keep the old TextureVariable.

I'm for myself convinced that there's a more elegant solution to this, a solution that involves telling MonoGame to use CustomEffect instead of BasicEffect. I know that using the MGCB Tool I can specify a DefaultEffect for the ModelProcessor, however I haven't found out what I need to do so I can specify my effect there without the Game crashing and telling me that effects/CustomEffect isn't a valid effect.

So is there a better way to achieve the same goal my existing code does? And if so, how?


Solution

  • Your solution is the primary one available, and the most flexible.

    You do need to move the effect clone and parameter lines inside the foreach loop and change it to:

    var effect = content.Load<Effect>("effects/CustomEffect").Clone();
    effect.Parameters["Texture"].SetValue(meshPart.Effect.Parameters["Texture"].GetValueTexture2D());
    

    Otherwise all parts of the model will use the same texture.

    The lack of elegance is in the fact that this is a direct carry-over from the XNA platform.

    The other option is to make your parameters and semantics match those of BasicEffect, at which point you should be able to set it in the Model Processor. The model processor expects the parameters exist and in that specific order.