3
\$\begingroup\$

I'm writing my first game using OpenGL 2 ES (for Android), and I've currently got a particle engine and some player sprites running successfully. I'm using 4 floats for the colour of each particle which seems like total overkill. It makes sense that I should be able to use a single 32 bit int (or perhaps a single float) to hold the colours (perhaps in RGBA format) which would presumably save a lot of unnecessary loading/copying/processing, but I'm struggling to understand how I could do this.

I guess that I would need to change the shaders to take the relevant format, and also i'd need to change the way I load the color shader attribute. My fragment shader has:

varying vec4 v_Color;
gl_FragColor = v_Color * texture2D(u_TextureUnit, gl_PointCoord);

and the attribute (passed into the fragment shader from the vertex shader) is set up with:

glVertexAttribPointer(aColourLocation, COLOUR_COMPONENT_COUNT, GL_FLOAT, false, BYTES_PER_VERTEX, floatBuffer);

I've searched the documentation for what I should change vec4 and GL_FLOAT to, and what/how I'd multiply the colour with the texture, and have tried a few things but with no success.

\$\endgroup\$
  • 1
    \$\begingroup\$ You are looking in the wrong place you should set the draw buffer to a 8 bit format, all the rest happens automatically \$\endgroup\$ – ratchet freak Sep 19 '14 at 12:22
  • \$\begingroup\$ @ratchetfreak Not sure what i'd do to the shader/attrib setup. What types do I use? How do I do the colour multiply? \$\endgroup\$ – user5196 Sep 19 '14 at 12:32
  • \$\begingroup\$ this might help opengl.org/wiki/Image_Format \$\endgroup\$ – Aralox Sep 19 '14 at 13:01
  • \$\begingroup\$ @Aralox Thanks, that seems relevant. Seems that what I want would be GL_RGBA8UI. Sadly, it doesn't look like this is available on OpenGL ES 2.0 for Android: developer.android.com/reference/android/opengl/… Or am I misreading that? Should I be worried about trying to use 4 bytes instead of 16 to specify the colour of each particle? \$\endgroup\$ – user5196 Sep 19 '14 at 20:10
2
\$\begingroup\$

Fragment shaders operate with floats. This is an abstraction over the actual underlying hardware format (GLSL is a high-level language after all), so you shouldn't expect that to indicate that you've actually got a floating-point framebuffer. You'll always use vec4 in your fragment shader irrespective of if you have a 16-bit, 32-bit, 64-bit or 128-bit framebuffer, and there's no memory overhead for doing so.

There's no need to change your fragment shader; don't fall into the trap of thinking that the high-level GLSL you write is any way representative of the low-level hardware instructions that actually run.

For sending colours as a 4-byte format you adjust your glVertexAttribPointer call so that it's using GL_UNSIGNED_BYTE for the type parameter and GL_TRUE for the normalized parameter. Then also adjust your source data, and you can start sending colours as 4 bytes with a 0-255 range, in RGBA order. The hardware will automatically convert them to floats in a 0-1 range and your fragment shader, once again, remains exactly the same as before. Don't sweat the details of whether or not this is a slow operation: it isn't.

Beware of thinking you're going to be even more efficient if you decide to only send 3-bytes sometimes: hardware prefers to operate on 32-bit boundaries and while you will save a small amount of memory you risk running substantially slower as a result.

\$\endgroup\$
  • \$\begingroup\$ I guess I have to have an array of ints with which to feed the colour attribute, given that were I to continue to use a float there'd be some corruption to my RGBA int. (When changing my code to take your answer into account I discovered that I had to use ABGR format within my ints (the alpha is in the 8 most significant bits). I guess this is an endian thing - i'm using the native order in my IntBuffer) \$\endgroup\$ – user5196 Sep 24 '14 at 11:55

Your Answer

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