Arrays (not tables) and shaders

I am trying to do some new shader magic, I’ll post it when I get it working, it’s almost there… but… my shader has a uniform array for instance “uniform mat4 matrices[10]” and in lua I have a table of 10 matrices… but how do I make it work with the shader.

As far as I know the only data structure in lua is the table, but the shaders are expecting to recieve arrays…

Anyone know the answer? I can always go for a set of uniforms rather than an array, but it’ll get pretty horrible.

I tested it, and I think at when you set a uniform array to a table it converts it, but I would I assume that would work as long as they were all the same type, (all float, all int, etc…) but I didn’t test it with different types. I made a copy of the radial blur shader, and used a uniform float array for the samples, then set it to a table of floats, and it worked. Are you getting any specific error?

I read somewhere that shaders only accept 1D arrays…

My shader takes a float array of 100, and it works. Strange…

I just read something interesting

“Switching between uniform buffer bindings is typically faster than switching dozens of uniforms in a program. Therefore, uniform buffers can be used to quickly change between different sets of uniform data for different objects that share the same program.
Also, uniform buffer objects can typically store more data than non-buffered uniforms. So they can be used to store and access larger blocks of data than unbuffered uniform values.
Lastly, they can be used to share information between different programs. So modifying a single buffer can effectively allow uniforms in multiple programs to be updated.”

Now I see we have access to buffers in Codea… Don’t know if this helps because I’ve never used buffers.

@Ignatz that’s where I’d got to, just tried it and no joy. Even though in OpenGl i think these arrays are buffers, the buffer functionality on Codea is for vertex attributes, non uniform buffers.

@SkyTheCoder sounds interesting, it may be that matrices are too complex objects for Codea to sort out correctly, I’ll have another play with this later, if I can pump arrays of floats or ideally vecs I can probably reconstitute the matrices in the shader… Not sure if that would be better or worse than just binding 10 seperate matrices and dealing with that.

Why don’t you share a simplified example and we’ll see if we can help?

I think I’ll just finish the current project with the rough way of doing it (multiple uniforms and if statements in the shader) which isn’t perfect, but allows me to do what I want to do, then after I’ve shared it we can look at improvements.

@spacemonkey I’ve just tried a simple experiment and I can’t get an array of matrices into the shader. I’ll post my code so that others can experiment (and so that you can say whether or not it is a reasonable approximation of what you are trying to do).

Vertex shader: So I have an array and a single matrix for testing. I tried putting an element of the array in the gl_Position line but that led to no image showing so I put it in the vColor line as a way of extracting the elements of the matrix. Again, no image shown. I conclude that the m[0] (and m[1]) are getting set to the zero matrix despite me setting them to the identity matrix in the lua code. The mm is there as a sanity check to show that I can get a matrix in somehow and to show that what would happen if m[0] were a non-zero matrix.

//
// A basic vertex shader
//

//This is the current model * view * projection matrix
// Codea sets it automatically
uniform mat4 modelViewProjection;
uniform mat4 m[2];
uniform mat4 mm;
//This is the current mesh vertex position, color and tex coord
// Set automatically
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;

//This is an output variable that will be passed to the fragment shader
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;

void main()
{
    //Pass the mesh color to the fragment shader
    vColor = m[0]*color;
    vTexCoord = texCoord;
    highp mat4 mmm = m[0] * m[1];
    //Multiply the vertex position by our combined transform
    gl_Position = mm*modelViewProjection * position;
}

Fragment shader:

//
// A basic fragment shader
//

//Default precision qualifier
precision highp float;

//This represents the current texture on the mesh
uniform lowp sampler2D texture;

//The interpolated vertex color for this fragment
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

void main()
{
    //Sample the texture at the interpolated coordinate
    lowp vec4 col = texture2D( texture, vTexCoord ) * vColor;

    //Set the output color to the texture color
    gl_FragColor = col;
}

Program:

function setup()
    m = mesh()
    m.shader = shader("Documents:MatrixArray")
    m.texture = "Cargo Bot:Codea Icon"
    m:addRect(WIDTH/2,HEIGHT/2,200,200)
    m.shader.m = {matrix(),matrix()}
    m.shader.mm = matrix()
end

function draw()
    background(0)
    m:draw()
end

One thing I found with experimenting with arrays in shaders is that your array will get truncated to the length that is actually used in the shader. So if you declare an array of length 3 but only use the first 2 elements, your array will actually only be of length 2.

@Andrew_Stacey yes that’s a good example and your findings are consistent with mine. My Skeletal Animation thread is what I was working on and at the moment I just created a load of uniforms, one for each matrix which is bad from a performance point of view inside the shader, and causes more cut and pasting of code if you want more bones.

@spacemonkey Maybe we should ask @Simeon if this would be possible to fix.

@Andrew_Stacey (and @Simeon ) yeah, I think it’s an extension of the API. For vertex attrbiutes in opengl you bind a GL_ARRAY_BUFFER and this is I guess what mesh:buffer(“xyz”) is giving us. For uniform arrays in opengl you bind GL_UNIFORM_BUFFER so I guess a mesh:uniformBuffer(“xyz”) or something would work.

Note: This is from google, I’ve never used full opengl myself.

The PDF summary of OpenGL ES says this

  • structures and blocks can be arrays
  • only 1-dimensional arrays supported
  • structure members can be arrays

maybe you can make a 1D array of structs which will enable you to pass multiple items per array element.

Well… technically it is a 1 dimensional array of mat4 (4x4 matrix) items. So that should be compliant with the OpenGl ES spec.

@Simeon any comment on this problem? I could really clean up some code if I could hand arrays of matrices to a shader… in OpenGL ES 2.0 I think this is:

void glUniformMatrix4fv( GLint location,
GLsizei count,
GLboolean transpose,
const GLfloat *value);

And I guess since I can pass it non array matrices you must already do something like this with a count of 1…