perf(rendering): true DrawElementsInstanced — one draw call per (GfxObj × sub-mesh)

Replaces the per-entity glUniform uModel path with a shared instance VBO and
DrawElementsInstanced. All instance model matrices are uploaded to GPU once per
frame; the VAO's per-instance attribute pointers (locations 3–6, divisor=1) are
updated with a byte-offset re-point per group so a single VBO serves all groups
without requiring DrawElementsInstancedBaseInstance (not in Silk.NET 2.23).

Changes:
- InstancedMeshRenderer: add _instanceVbo, _instanceBuffer scratch; EnsureUploaded
  sets up mat4 instance attrs (locs 3–6) from the shared VBO; Draw builds the flat
  float[] of all instance matrices once then calls DrawElementsInstanced per sub-mesh.
  Drops the unused uint TerrainLayer attribute (loc 3 from vertex VBO) — mesh shaders
  never used it. Adds InstanceGroup helper to track per-group buffer offsets.
- mesh_instanced.frag: replace sampler2DArray+uTextureLayer with sampler2D uDiffuse,
  matching the existing TextureCache / individual-texture pipeline.
- mesh_instanced.vert+frag: track as committed files (were untracked).
- Shader.cs: add SetVec3 helper needed for uLightDirection uniform.
- GameWindow.cs: switch mesh shader load from mesh.vert/.frag to
  mesh_instanced.vert/.frag.

Visual output is identical: same entities, same textures, same lighting constants
(SUN_DIR=(0.5,0.4,0.6), AMBIENT=0.25, DIFFUSE=0.75 — moved from frag to vert).
Build: clean. Tests: 431/431 green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-13 18:51:49 +02:00
parent b5099e2b21
commit 6a55838a10
5 changed files with 288 additions and 109 deletions

View file

@ -58,5 +58,11 @@ public sealed class Shader : IDisposable
_gl.Uniform1(loc, value);
}
public void SetVec3(string name, Vector3 v)
{
int loc = _gl.GetUniformLocation(Program, name);
_gl.Uniform3(loc, v.X, v.Y, v.Z);
}
public void Dispose() => _gl.DeleteProgram(Program);
}