LibGDX packs the RGBA components into a single float, and sends it along the pipeline. This is much faster than sending four floats (R, G, B, A) to the vertex shader. Unfortunately, this means that OpenGL will “normalize” the value in the range 0.0 to 1.0.
One option is to add a uniform value for “brightness.” See here. This is useful if you have a whole bunch of sprites that need the same brightness value. This should probably be fast enough for most use cases.
If you need better performance (e.g. per-sprite brightness), you should use a vertex attribute for brightness, instead of a uniform (so it can be batched). You basically have two options. Either you hack it, or you re-implement SpriteBatcher to have a proper brightness attribute.
To hack it, you could pass in a U texture coordinate larger than 1.0, and in the vertex shader, the brightness is taken from the integral part of the coordinate, and the actual U coordinate is the fractional [icode]fract(…)[/icode]. Then you send both of those along to your fragment shader. This means no “texture repeat” wrapping (which is pretty rare in 2D games, anyways).
The “proper” solution is to have a brightness attribute in your sprite batcher; but this is more work. You’d have to implement the Batch interface, copy over most of SpriteBatch’s code, and then add in the extra vertex attributes. Read more about working with mesh here.
And if you are just looking to change the brightness of the whole screen (rather than individual sprites), you should just use shaders and a post-processing step.
Cheers.