Quick answer: Cache the handle from shader_get_uniform(sh, "name") once. After shader_set(sh), call shader_set_uniform_f_array(handle, flat_array). Length must match the shader’s declared uniform size.
You upload 16 light positions to a shader. Lights render at the origin. The handle was wrong, or the call happened before shader_set, or the array length didn’t match.
The Symptom
Uniform array values default to 0 in the shader. show_debug_message of the array on the GML side shows correct values; the shader doesn’t see them.
The Fix
/// In Create event
sh_handle_lights = shader_get_uniform(sh_lighting, "u_lights");
/// In Draw event
shader_set(sh_lighting);
var data = array_create(16 * 4, 0);
for (var i = 0; i < 16; ++i) {
data[i*4 + 0] = lights[i].x;
data[i*4 + 1] = lights[i].y;
data[i*4 + 2] = lights[i].radius;
data[i*4 + 3] = lights[i].intensity;
}
shader_set_uniform_f_array(sh_handle_lights, data);
draw_self();
shader_reset();
Cache handle in Create. shader_set first, then upload, then draw, then reset.
Shader Declaration
// Shader
uniform vec4 u_lights[16];
void main() {
vec4 light = u_lights[0];
// ...
}
16 vec4s = 64 floats in the GML array. The size declared in the shader must match (or be larger).
For Big Data
If you need more than ~64 vec4s, encode the data into a surface and sample as a texture in the shader. Uniform array slots are limited.
Verifying
Add a debug visualization in the shader (output u_lights[0].x as red channel). If red is 0, upload failed. If non-zero, upload succeeded.
“Cache handle. shader_set first. Flat array of right length. Uniforms upload.”
Related Issues
For surface lost, see surface lost. For asset precache, see asset precache.
Cache. Set. Upload. Shader sees.