Arbitrary mesh-batching w/ automatic instancing

Don’t see a lot of 3d here, here’s a chunk that may help somebody else out down the road:

Here’s a simple MeshBatcher that roughly follows order your graphics draw calls around. It’s meant for general purpose use (not specialized cases like fields of grass) and assumes that a modern lighting method is used (Forward+, clustered, deferred) as it makes no considerations regarding lighting needs.

The sort key is organized to prioritize by layer then effect since the Effect is where the more costly state changes are (shader, uniforms, textures), and lastly by vtx/idx data and whether instancing is forced-off (ie: for skeletal animated meshes). The resulting draws will be fairly optimal and whenever possible instancing will be used (min/max range is configurable).

Basically you throw crap at it, which it organizes, and later you call Render with an arbitrary passID and it runs through it in as close to an optimal sequence as you’re going to get.

Only real bits required for someone to use it are:

  • Add instanced Technique variations to your Effects
    • VertexShaderOutput MainVSInstanced(in VertexShaderInput input, in float4x4 InstanceTransform : TEXCOORD1)
  • Replace/remap the Camera type of mine that isn’t included
    • should be transparent
  • add whatever helpers you need
    • Actual functions are all raw, passing vtx / idx buffers
  • decide whether to keep the IMeshBatchEffect interface for Effect classes or to instead rely on conventions (ie. it’s always a shader-constant named Transform)
    • Note: the Begin/End functions in that interface are there to deal with GPU state concerns (depth-equal, etc) and pumping in uniform values, if you ditch the interface you might have more work
  • Change vertex data semantics for the additional instance transforms buffer if desired

An naive/trivial implementation of the IMeshBatchEffect interface looks like:

    public bool PrepareInstanced(int passID)
    {
        CurrentTechnique = Techniques.Last();
        CurrentTechnique.Passes[0].Apply();
        return true;
    }

    public bool PrepareOneOff(Matrix transform, int passID)
    {
        Parameters["Transform"].SetValue(transform);
        CurrentTechnique = Techniques.First();
        CurrentTechnique.Passes[0].Apply();
        return true;
    }

    public bool EffectSelected(int passID)
    {
        return true;
    }

    public void EffectDeselected()
    {
        
    }

If you try to use it and have questions, ask.

2 Likes