floooh / sokol

minimal cross-platform standalone C headers

Home Page:https://floooh.github.io/sokol-html5

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[sokol_gfx] Array of struct uniform

mathewmariani opened this issue · comments

I've been looking around for more information on passing an array of structs to my shader, but can't find a lot of information on the subject. I should mention that I'm working with OpenGLES for the time being, and I'm not using the sokol-shdc shader compiler tool.

Here is my structure in both C++ and GLSL.

struct pointlight_t
{
  float radius;
  glm::vec3 color;
  glm::vec3 position;
};
static pointlight_t light_data[MAX_LIGHTS];
struct PointLight {
  float radius;
  vec3 color;
  vec3 position;
};
uniform PointLight[MAX_LIGHTS] lights;

I'm not sure if this is completely correct but this is how I'm describing the uniform block in my sg_shader_desc. At this point, I will add that I have no compile or runtime errors.

// [...]
.uniform_blocks[1] = {
    .layout = SG_UNIFORMLAYOUT_NATIVE,
    .size = sizeof(pointlight_t) * MAX_LIGHTS,
    .uniforms = {
        [0] = {.name = "light.radius", .type = SG_UNIFORMTYPE_FLOAT, .array_count = MAX_LIGHTS},
        [1] = {.name = "light.color", .type = SG_UNIFORMTYPE_FLOAT3, .array_count = MAX_LIGHTS},
        [2] = {.name = "light.position", .type = SG_UNIFORMTYPE_FLOAT3, .array_count = MAX_LIGHTS},
    },
},

// [...]
sg_apply_uniforms(SG_SHADERSTAGE_FS, 1, SG_RANGE(light_data));

I'm not exactly sure what is the proper way to approach this using sokol_gfx. There are no build or runtime errors, yet I don't seem to be getting any data passed to the shader. I wasn't able to find a whole lot of information about this, hopefully, you can clarify my understanding.

Hmm... without using the sokol-shdc compiler that's most likely not possible in the GL backend. You would need to convert the struct array into a plain vec4 array.

With the sokol-shdc compiler this conversion happens automatically for the GL backend (e.g. uniform blocks are flattened into a vec4 array), and then something like this could work. TBH I never tried that though.

uniform vs_params {
    PointLight lights[MAX_LIGHTS];
};

PS: maybe it doesn't work though... sokol-shdc has restrictions on what can be declared as an array because that uniform block must also be mapped to a matching C struct, and that's gnarly because of std140 alignment and padding rules, so I'm allowing arrays only for floats, vec2, vec4 and mat4.

I would probably recommend a 'structure of arrays' approach instead:

uniform vs_params {
    float light_radii[MAX_LIGHTS];
    vec4 light_colors[MAX_LIGHTS];
    vec4 light_positions[MAX_LIGHTS];
};

(vec4 instead of vec3 because of the above mentioned alignment restrictions - this is all assuming sokol-shdc though).

Without sokol-shdc this should also work for regular uniforms, but you'd need to experiment..