Search code examples
androidopengl-eslibgdxshadertextures

Libgdx shader optimization


Hello everyone using libgdx!

I have 40 fps in the game because of the shader. This shader draws the background and I want to reduce the number of pixels it processes.

In Create method I generate a texture with Pixmap whose width and height are 1/10 of the actual screen size.

pixmap = new Pixmap( (int)(Math.ceil(WIDTH/10f)), (int)(Math.ceil(HEIGHT/10f)), Pixmap.Format.RGBA8888 );
backGround = new Texture(pixmap);

Then I set camera.zoom at 0.1 so the texture now is fullscreen.

camera.position.set( WIDTH/2f*0.1f, HEIGHT/2f*0.1f, 0);
camera.zoom = 0.1f;
camera.update();
batch.setProjectionMatrix(camera.combined);

Then the shader in Render method draws a circle, but that shader processes screen's pixel instead of texture's ones and I got nice and smooth picture as before.

Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.draw(backGround,0,0);

Fragment shader's code:

vec3 yellow = vec3(0.93, 0.93, 0.32);

vec2 relativePosition = gl_FragCoord.xy / u_ScreenResolution;
relativePosition.x *= u_ScreenResolution.x / u_ScreenResolution.y;
float normDistance = pow(   (  pow(relativePosition.x - 0.3,2.0) + pow(relativePosition.y - 0.5,2.0)  ), 0.5   );
int distance = int(  round( normDistance + 0.4  )  );
gl_FragColor = vec4(vec3(0.0) + yellow*clamp(1.0-distance, 0.0, 1.0), 1.0);

Not sure if I'm expressing the idea correctly, so here is a picture:

image i drawn


Solution

  • "that shader processes screen's pixel instead of texture's ones" <- this

    You have a texture which is backed by the pixmap (of a lower resolution), but you have not drawn to that lower resolution pixmap first. What happens is that what you see on screen is what is calculated by the shader on the basis of -screen coordinates-. i.e. your pixmap resolution is irrelevant because what you get is calculated by the shader and not derived from the pixmap.

    The effect you want needs the lower resolution texture backed by pixmap to be drawn to first with your shader, and then that -low resolution rendered texture- be scaled up to the screen using the default shader which maps to the texture.

    Use a framebuffer, which is effectively a screen except in memory not actually on screen, to allow openGL to consider your low resolution pixmap to be the screen, draw to that first, then use the resultant blocky texture as texture to scale to the screen. Which is

    FrameBuffer fbo = new FrameBuffer(Format.RGB888, screenwidth, screenheight, false);
    fbo.begin();
    //render here
    fbo.end();
    //grab and use as texture scaled to the full  screen
    

    There is an example here

    LibGDX FrameBuffer