Add the ability to update an uniform array in the constants buffer

It’s possible to update a shader uniform array with go.set():

go.set(url, "example", vmath.vector4(1), { index = 5 } )

But there is no way to do it with a constants buffer created by render.constant_buffer().

Would like to do it by this way:

self.constants = render.constant_buffer()
self.constants.example[5] = vmath.vector4(1)

Use case

I’m trying to implement forward shading using additional texture data with positions and colors of light sources. That’s a 32x32 texture that I update every frame because of lights movement. It takes time to extract values from the texture data in the fragment shader program. For example, 20 light sources require to find and read 100 pixels of data per a fragment.

This looks adequate for 20 light sources, but not for 60 light sources.

I know, forward shading is not the best way of rendering lighting. But maybe performance could be better if iterating over uniform arrays instead of reading 5 pixels per light source and extracting all the parameters from them?

For example, look at this method of extracting the light source position from 3 pixels that I use now:

vec3 get_data(int index) {
    float x = float(index % texture_size) / float(texture_size);
    float y = float(index / texture_size) / float(texture_size);
    vec2 coord = vec2(x, y);
    return texture2D(illumination, coord).rgb;
}

float data_to_axis(vec3 data) {    
    float r = 255.0 * data.r * 256.0 * 256.0;
    float g = 255.0 * data.g * 256.0;
    float b = 255.0 * data.b;
    float value = r + g + b;
    value = value - (max_uint24 * 0.5);
    value = value * (axis_capacity / max_uint24);
    return value;
}

...
vec3 light_position = vec3(
    data_to_axis(get_data(pixel + 1)),
    data_to_axis(get_data(pixel + 2)),
    data_to_axis(get_data(pixel + 3))
);
...

Voting

If you’d like to have forward shading like that more optimized, please upvote for #6529 :+1::+1::+1:

9 Likes

Hi, I’ve started working on this in an experimental fashion already, it just needs a bit of design and cleaning up :+1: probably done in a week or two as I’m currently doing it on the side for fun

10 Likes

Are you talking about deferred shading? :wink:
If so, it’s even better than just uniform arrays!

6 Likes

We need both! :sob:

6 Likes

Haha no just constant uniform arrays but I’ll look at deferred after no worries :wink:

8 Likes

Apologies for reviving an old thread, but now that this has been added, how would I access the values in a constant buffer in the fragment program?

For example, if I have constant_buffer.lights[3] = vec4(1.0, 0.5, 0.2, 0.0), would the light array show up as uniform mediump vec4 light3 or maybe something else?

Good question! @jhonny.goransson what is your take on it?

if you have specified an array constant in a constant buffer in your render script called lights, you specify it in a shader like so:

uniform vec4 lights[16] -- size is up to you

If you have specified a constant array of matrices, you need to change vec4 to mat4.

4 Likes

And how would the array of vec4s be specified in the Material file? Currently I am listing each light independently like so:

Do you need to configure their data from the editor or just specify that there is a constant? If you don’t need to modify the data you just add a constant with the base name of the array, so if you have an array specified in the shader like so: uniform vec4 my_array[16] you just add a single constant in the list with the name “my_array”.

For editing in the material view there is an unfortunate side-effect that the UI doesn’t support vectors. We have planned an redesign of that view to fix this (and other UX issues) at some point, but if you need to change the “value” part of an array you need to open the material in a text file and do the modifications there. For now it’s probably easiest to just set the values from code (what I would do).

2 Likes