Am I supposed to have an effect instance per mesh that instantiate once and apply every time mesh is rendered?

In a lot of tutorials I see lines like these:

foreach(EffectPass pass in basicEffect.CurrentTechnique.Passes)
 {
     pass.Apply();
     GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 3);
 }

Which lead me to believe that the right way to draw a 3d mesh is the following:

  1. Create an effect (instance can be made once in constructor and reused).
  2. Update its world & projection matrix.
  3. Iterate its passes and draw the mesh vertices.

For example, I wrote a 3d cube class with a Draw() function that looks something like this:

        _effect.World = _world;
        device.SetVertexBuffer(_shapeBuffer);

        foreach (EffectPass pass in _effect.CurrentTechnique.Passes)
        {
            pass.Apply();
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, NUM_TRIANGLES);
        }

But is this the appropriate way to use effects? I’m asking because the code above seem to load the effect shaders to the GPU per object, so if I have 1000 cubes I will be uploading the shaders 1000 times? Does it make sense to work like that?

And if the answer is yes, eg it make sense to apply effect x passes per object, will I get any performance boost from grouping together objects that share the same effects, even if I apply the passes for every render anyway? And is it smart to keep the same effect instance alive and reuse it as long as the object live, or better to just create it before rendering and toss it after?

In general if there are thumb rules of whats the right way to use effects with multiple objects in MonoGame I’d love to hear more…

Thanks,

This is incorrect. The shader is uploaded to the GPU on creation. Applying the pass lets the graphical backend know what shaders it should use on the next draw (by settings GraphicsDevice.VertexShader and .PixelShader)
and applies the render state. Source: https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework/Graphics/Effect/EffectPass.cs#L63

It will be better for performance if you minimize render state changes, so grouping stuff makes sense. MonoGame caches a lot of the render state, so if you reapply the same state it will probably not interact with the GPU.

Reuse it, definitely. You don’t want the effect to be destroyed and recreated (e.g. sent to the GPU) every frame.

Great explanation, thanks!

So just to be sure I understand…

So if I create 1000 objects, and each one of them got his own effect instance, MonoGame will upload the shaders only once (when the first object and his effect are created) and when rendering the object and applying the pass all it will do is tell the GPU which shader to use?