16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-17 23:39:18 +02:00

Enable instancing

This commit is contained in:
2026-05-09 23:29:20 +02:00
parent b7283d8fb9
commit 587077629f
14 changed files with 304 additions and 50 deletions

View File

@@ -14,6 +14,7 @@ void gl::glsl_common_setup()
"#define MAX_LIGHTS " + std::to_string(MAX_LIGHTS) + "U\n" +
"#define MAX_CASCADES " + std::to_string(MAX_CASCADES) + "U\n" +
"#define MAX_PARAMS " + std::to_string(MAX_PARAMS) + "U\n" +
"#define MAX_INSTANCES_PER_BATCH " + std::to_string(MAX_INSTANCES_PER_BATCH) + "U\n" +
R"STRING(
const uint LIGHT_SPOT = 0U;
const uint LIGHT_POINT = 1U;
@@ -78,5 +79,31 @@ void gl::glsl_common_setup()
vec4 wiper_timer_return;
};
// Per-instance modelview matrices for GPU-instanced draws.
// The UBO itself is declared in every stage so the binding stays valid,
// but the helper functions reference gl_InstanceID which is vertex-only,
// so they are guarded behind STAGE_VERTEX.
layout (std140) uniform instance_ubo
{
mat4 instance_modelview[MAX_INSTANCES_PER_BATCH];
};
#ifdef STAGE_VERTEX
// For non-instanced draws gl_InstanceID == 0 and slot 0 is permanently set
// to identity, so effective_modelview() reduces to model_ubo.modelview.
// For instanced draws the C++ side uploads camera-space root transforms for
// instances 0..N-1 and sets model_ubo.modelview to the submodel-local chain
// (computed from identity, NOT from the camera/instance), so the product
// gives the correct final transform per instance per submodel.
mat4 effective_modelview() {
return instance_modelview[gl_InstanceID] * modelview;
}
mat3 effective_modelviewnormal() {
// instance_modelview is rotation+translation only (no scale), so its
// upper-3x3 is its own inverse-transpose (rotation matrix).
return mat3(instance_modelview[gl_InstanceID]) * modelviewnormal;
}
#endif
)STRING";
}

View File

@@ -106,6 +106,12 @@ std::pair<GLuint, std::string> gl::shader::process_source(const std::string &fil
str += "precision highp sampler2DShadow;\n";
str += "precision highp sampler2DArrayShadow;\n";
}
// expose the shader stage to glsl_common so vertex-only built-ins
// (gl_InstanceID, effective_modelview, etc.) can be guarded out of
// fragment/geometry compilations.
if (type == GL_VERTEX_SHADER) str += "#define STAGE_VERTEX 1\n";
else if (type == GL_FRAGMENT_SHADER) str += "#define STAGE_FRAGMENT 1\n";
else if (type == GL_GEOMETRY_SHADER) str += "#define STAGE_GEOMETRY 1\n";
str += "vec4 FBOUT(vec4 x) { return " + (Global.gfx_shadergamma ? std::string("vec4(pow(x.rgb, vec3(1.0 / 2.2)), x.a)") : std::string("x")) + "; }\n";
str += read_file(basedir + filename);
@@ -293,6 +299,9 @@ void gl::program::init()
if ((index = glGetUniformBlockIndex(*this, "light_ubo")) != GL_INVALID_INDEX)
glUniformBlockBinding(*this, index, 2);
if ((index = glGetUniformBlockIndex(*this, "instance_ubo")) != GL_INVALID_INDEX)
glUniformBlockBinding(*this, index, 3);
}
gl::program::program()

View File

@@ -87,6 +87,17 @@ namespace gl
static_assert(sizeof(model_ubs) == 208 + 16 * MAX_PARAMS, "bad size of ubs");
// maximum number of instances per single GPU-instanced draw call.
// 256 mat4 = 16 KiB, the guaranteed minimum UBO size. Bigger batches must split.
const size_t MAX_INSTANCES_PER_BATCH = 256;
struct instance_ubs
{
glm::mat4 instance_modelview[MAX_INSTANCES_PER_BATCH];
};
static_assert(sizeof(instance_ubs) == 64 * MAX_INSTANCES_PER_BATCH, "bad size of instance_ubs");
struct light_element_ubs
{
enum type_e