2
\$\begingroup\$

I am using a SpriteBatch to render large amounts of sprites very fast. Now I want to modify the sprites with shaders to tint them in a color.

Problem 1: Altering an uniform by getting the shader and setting it between the begin/end of the batch changes the whole scene not only a single sprite. E.g.:

"EngineView.getShader().setUniformf("u_blue", (float) Math.random());"

Problem 2: It is relatively slow.

Also I found this which seems to cover the same (no proper solution): (Setting uniform value of a vertex shader for different sprites in a SpriteBatch):

You almost certainly don't want to actually do this. Changing a uniform for every quad/sprite is going to severely impact the throughput of your renderer. Much of the GPU will be sitting idle while you're drawing one measly sprite at a time. The whole point of a "sprite batch" is to draw as many sprites at the same time with as few draw calls or state changes as possible. If you need random data in your shader, use a noise texture or a noise function. stackoverflow.com/questions/4200224/… – Sean Middleditch May 23 at 21:22

My question is, if I don't want to actually do this, what is it I want to do?

\$\endgroup\$
3
\$\begingroup\$

Setting a uniform per sprite is probably not a good idea, as Sean Middleditch already pointed out.

Tinting a sprite in OpenGL can easily be done by defining the vertex colors. Since the vertices in this case are defined by SpriteBatch.draw(), you should set the tint with SpriteBatch.setColor().

From the SpriteBatch source code:

200 public void setColor (float color) {
201     this.color = color;
202 }

and

499 public void draw (Texture texture, float x, float y, 
    float width, float height) {
...
516 float color = this.color;
517 int idx = this.idx;
518 vertices[idx++] = x;
519 vertices[idx++] = y;
520 vertices[idx++] = color;
521 vertices[idx++] = u;
522 vertices[idx++] = v;
... 

(which is repeated for all 4 vertices of the quad)

The color can then be used in the vertex shader. By multiplying it with 2.0 you can use the range from 0%-200% allowing you to darken and brighten it.

v_color = a_color*gl_Color*2.0;
\$\endgroup\$
  • \$\begingroup\$ this is the way I did this before. The problem is the color is only applied by a blending mode (add or multiply). This limits the scale depending on the current blending. You can either add or multiply a color with the range 0-1 only. There are several more reasons I want to do this with shaders. \$\endgroup\$ – Benedikt S. Vogler Sep 24 '14 at 8:15
  • \$\begingroup\$ Yeah, but your shader can use the vertex colors. What SpriteBatch does, if you don't define a shader, is it loads a default shader. In (modern) OpenGL you always use shaders. You can find the default vertex and pixel shaders -here-, to see how they work and maybe use them as templates. \$\endgroup\$ – Eelfroth Sep 24 '14 at 12:05
  • \$\begingroup\$ Or, as a short answer to your initial question: You don't want to use uniforms for this task, but attributes. \$\endgroup\$ – Eelfroth Sep 24 '14 at 12:07
  • \$\begingroup\$ I added a paragraph on using the color. With this additional information @eelfroth gave me in a private conversation I was able to solve my problem. \$\endgroup\$ – Benedikt S. Vogler Oct 9 '14 at 13:28

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.