user2499946
user2499946

Reputation: 689

Plasma Shader Performance in OpenGL ES 2.0

I am using a plasma shader in my Android (libGDX) app, which I found from here:

http://www.bidouille.org/prog/plasma

Here is my shader (slightly modified):

#define LOWP lowp
precision mediump float;
#else
define LOWP
#endif
#define PI 3.1415926535897932384626433832795

uniform float time;
uniform float alpha;
uniform vec2 scale;

void main() {
  float v = 0.0;
  vec2 c = gl_FragCoord.xy * scale - scale/2.0;
  v += sin((c.x+time));
  v += sin((c.y+time)/2.0);
  v += sin((c.x+c.y+time)/2.0);
  c += scale/2.0 * vec2(sin(time/3.0), cos(time/2.0));
  v += sin(sqrt(c.x*c.x+c.y*c.y+1.0)+time);
  v = v/2.0;
  vec3 col = vec3(1, sin(PI*v), cos(PI*v));
  gl_FragColor = vec4(col *.5 + .5, alpha);
}

I am rendering it via an ImmediateModeRendererGL20, as a quad.

However, it simply appears to be way too slow for my needs. I am trying to fill almost the whole screen on my Nexus 7 (first gen) with the shader, and I cannot get even close to 60 FPS.

This is really my first real trip onto the GLSL world, and I have no idea how these things usually should perform!

I am wondering how one could optimize this shader? I really don't care about the image quality, I can sacrifice it. I came to a conclusion that somekind of lookup table might be what I am after and/or dropping the resolution of the shader..? But I am not quite sure where to begin. I am still very new to GLSL and "low-level" programming has never really been my cup of tea, but I am eager to at least try!

Upvotes: 3

Views: 1496

Answers (1)

keaukraine
keaukraine

Reputation: 5364

The ultimate way to speed this up is to pre-calculate computation-heavy stuff (sin() ans cos() stuff) and bake it into texture(s), then get ready values from them. This will make it super-fast because your shader won't make any heavy computations but consume pre-calculated values.

As was stated in comments, you can optimize performance by moving certain calculations to vertex shader. For example, you can move this line

vec2 c = gl_FragCoord.xy * scale - scale/2.0;

to vertex shader without sacrificing any quality because this is a linear function so interpolation won't distort it. Do it like this:

// vertex
...
uniform float scale;
varying mediump vec2 c;
const float TWO = 2.0;
...
void main() {
    ...
    gl_FragCoord = ...
    c = gl_FragCoord.xy * scale - scale / TWO;
    ...
}

// fragment
...
varying mediump vec2 c;
...
void main() {
    ...
    // just use `c` as usual
    ...
}

Also, please use constants instead of literals - literals use your uniform space. While this may not affect performance it is still bad (if you use too much of them you can run out of max uniforms on certain GPUs). More on this: Declaring constants instead of literals in vertex shader. Standard practice, or needless rigor?

Upvotes: 3

Related Questions