regl-project / regl

👑 Functional WebGL
https://regl-project.github.io/
MIT License
5.21k stars 322 forks source link

Vertex data and attribute declaration dependency #328

Open vorg opened 7 years ago

vorg commented 7 years ago

It seems that in regl the vertex attribute has to match the input data dimensions e.g.

attribute vec2 position;
regl({
  attributes: {
    position: [[0, 0], [1, 0], [1, 0]]
  }
})

So now when i declare position as having 4 components nothing renders on the screen.

attribute vec4 position;

According to this SO Answer and OpenGL ES 2.0 Spec the attrbute would be expanded to 4 components with missing data filled as follows [0, 0, 0, 1] and this is how i've written my shaders so far with no problems.

How is the attribute size guessed in regl?

mikolalysenko commented 7 years ago

It guesses the attribute size using the shader. You can overload this by setting the size property in the attribute description. For example:

attributes: {
  position: {
     size: 4,
     data: [[0, 0], [1, 0], [1, 0]]
  }
}
vorg commented 7 years ago

As or regl 1.2.1 and vertex shader with the following attribute declaration

attribute vec4 position;

The example from above

attributes: {
  position: {
     size: 4,
     data: [[0, 0], [1, 0], [1, 0]]
  }
}

Will throw Error: (regl) missing buffer for attribute "position" in command unknown

Switching to

attributes: {
  position: regl.buffer({
     size: 4,
     data: [[0, 0], [1, 0], [1, 0]]
  })
}

will throw WebGL: INVALID_OPERATION: drawArrays: attempt to access out of bounds arrays

Changing position: { size: 4 ... to position: { size: 2... will still throw WebGL: INVALID_OPERATION: drawArrays: attempt to access out of bounds arrays

The only solution for the given geometry data is to change the shader code to

attribute vec2 position;
...
vec4 pos = vec4(position.xy, 0.0, 1.0)

I believe this is invalid behavior as now my geometry data is dependent on shader code (or shader on geometry).

To sum up: shader attr size == command attr size -> OK shader attr size > command attr size -> access out of bounds arrays shader attr size < command attr size -> black screen

mikolalysenko commented 7 years ago

Sorry about that it should be:

attributes: {
  position: {
     size: 2,
     data: [[0, 0], [1, 0], [1, 0]]
  }
}
vorg commented 7 years ago

@mikolalysenko no this doesn't work, i need to create regl.buffer() and match the attribute size in JS and vertex shader

vorg commented 7 years ago

Working code: https://gist.github.com/vorg/8ef68bc8fa769c21d3d97ea753147029

monfera commented 7 years ago

FWIW I've run into it also, assuming that the size is figured out from the shader reflection as the doc suggests (results of the gl.getActiveAttrib call), but indeed, an explicit size specification was needed (2 for mat2, 3 for mat3, 4 for mat4). I was going to make a small PR updating the doc but maybe the spirit of regl is to figure out the size and then found this issue.

attribute mat2 position; ...

      attributes: {

        position: {
          size: 2, // needed
          buffer: regl.buffer([
            0, 0,
            1, 1
          ])
        },
/* // this didn't work:
        position: [
            0, 0,
            1, 1
          ]
    // and neither did other variations e.g 
        position: [
          [0, 0],
          [1, 1]
        ]
*/
      }

⏫ ...well it's a moot point anyway because in the vertex shader, the position matrix is best declared componentwise, e.g. here, as two vec2 attributes, and with that, the vertexAttribPointer data i.e. size, stride and offset are necessary. I wish vertexAttribPointer could use size <= 16 rather than the current 4 but it's not a big deal to reassemble the matrix in the shader if needed.