0
\$\begingroup\$

I'm trying to learn how to use GLSL ES 2.0.

In OpenGL ES 2.0, there is no gl_VertexID keyword to obtain the number of vertices processed so far. So I was wondering if there's a way to make my own counter. I know the vertex shader is executed "per vertex," so if I can increase a counter which persists between executions then that will meet my case.

Now I know I can't use a uniform because by definition they cannot be altered.

So I thought about using an attribute, assuming the value will persist between vertex shader executions, but when I write

attribute int a_vertexCounter;

in my vertex shader, the shader compiler says that an attribute cannot have the type int.

So I thought maybe if I make a_vertexCounter a vec3 for example, and increment the first component of that vector instead... This works, except that when I try

gl_Position = u_MVPMatrix * u_canPos[int(a_vertexCounter.x)];

the compiler says

Error compiling shader: 0:23: S0027: Cannot modify an input variable

I also tried setting my attribute variable to be of type ivec3 but the shader says that's not allowed either.

Maybe there's no way to do this without ES 3.0, where I could simply use gl_VertexID ?

\$\endgroup\$
5
  • 2
    \$\begingroup\$ Remember that the whole reason to use a GPU is to process data in parallel. So you can't just increment a counter for each vertex processed serially: you might have hundreds of vertices all being evaluated "first". Have you considered adding an ID to each vertex in your vertex buffer instead, so you can just read the stored value as you would with a texture coordinate? \$\endgroup\$ – DMGregory Aug 4 '19 at 17:26
  • \$\begingroup\$ @DMGregory since all my sprites are square they have the same 6 vertices, so it seems inefficient to pass in any vertices at all. Would prefer to store 6 vertices in a uniform then just use the gl_VertexID % 6 (or some ES 2 equivalent) to access the appropriate vertex from the uniform. Sprites would get transformed via matrices I will pass in as an attribute buffer. Maybe there's no way to achieve this without OpenGL ES 3 then? Or maybe that won't even work given things may happen in parallel. Perhaps I have no choice but to pass in 6 canonical vertices per sprite? \$\endgroup\$ – Pixel Aug 4 '19 at 17:36
  • \$\begingroup\$ Depending on your needs, point sprites might be an option. Otherwise it sounds like you could get away with sending just one number per vertex instead of 3 coordinates, and then look up the corresponding vertex properties from your uniform array as you describe with that one number. \$\endgroup\$ – DMGregory Aug 4 '19 at 17:44
  • \$\begingroup\$ @DMGregory not sure I can use Point Sprites, as my sprites could be any size (unless I misunderstood what I read here: informit.com/articles/article.aspx?p=770639&seqNum=7). But I like your second point. I thought I might be able to get away with sending no point information then looking up the required vertex from the uniform but seems this is not possible then. Your solution of just sending in an id which indexes into the uniform would work. Thank you. New to all this, so just reading up on this: glslstudio.com/primer \$\endgroup\$ – Pixel Aug 4 '19 at 18:00
  • 1
    \$\begingroup\$ If you make it work, be sure to post your solution as an answer! \$\endgroup\$ – DMGregory Aug 4 '19 at 18:00
0
\$\begingroup\$

Given @DMGregory's comment I realised I couldn't just count the current vertex number inside the vertex shader, because GPU's run in parallel, and can have 100's or 1000's of cores working all at once so there could be any number of vertices being processed simultaneously.

To solve this I passed in an attribute float a_vertexId, where the corresponding VBO is:

vertexIdBuffer = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ...}

Inside the vertex shader you can then do something like the following:

int spriteId;
int vertexId;

void main()
{
    spriteId = int(a_vertexId) / 6;
    vertexId = int(a_vertexId) - spriteId * 6;

    ...
}

I can then use the spriteId to access some uniform canonical vertices for a square (representing the sprite), without the need to upload 6 vec3/vec4's (a square is two triangles, 3 + 3 = 6 vertices)

Note I could not pass in an attribute int which would be preferable because GL ES SL 2.0 does not support it, nor does it support the % operator, hence the elaborate modulo math in the main() function.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.