Create Blackhole in Libgdx using GLSL Shaders and FBO

In this Tutorial, we will be creating a Blackhole using smooth step in GLSL to create a gravitational effect on light and thus it’s bending.
As the blackhole shader will be used using FBO it is necessary for the readers to know about FBO and how to use them in LibGDX.
With and Without Shader


Without and With Shader

Without and With Shader

If you are new to shader please go through these tutorials before proceeding here.

Here is the Vertex Shader, copy it in a text file and rename the file as “blackhole.vert” save it in assets/shader folder

attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;    //used by libgdx
varying vec4 v_color;     //used by pass color data to fragment shader
varying vec2 v_texCoord0;    //used by pass pixel coordinate data to fragment shader
void main() {
  gl_Position = u_projTrans * a_position;
  v_color = a_color;
  v_texCoord0 = a_texCoord0;

Here is the Fragment Shader, copy it in a text file and rename the file as “blackhole.frag” save it in assets/shader folder

#ifdef GL_ES
#define LOWP lowp
precision mediump float;
#define LOWP
#endifvarying vec2 v_texCoord0;
varying vec4 v_color;uniform LOWP sampler2D u_texture;
uniform LOWP vec2 center;
uniform LOWP float time;
void main (void)
  float distance = distance(v_texCoord0,center);
  gl_FragColor = texture2D(u_texture, v_texCoord0 + smoothstep(time,0,distance));

And below is the implementation code using LibGDX, note the use of FBO as this shader is processed on the final output render which might hurt the performance but not that much as it is running at 60fps with ease on a quite cheap android device so no need to worry about fps in this case.

package main;
import main.util.Cam;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector3;
public class Test implements ApplicationListener {
  Cam camera;
  TextureRegion fboTexRegion;
  SpriteBatch batch;
  FrameBuffer fbo;
  Sprite testing;
  Texture nebula,star;
  ShaderProgram shaderprogram;
  public void create () {;
    camera=new Cam();fbo = new FrameBuffer(Pixmap.Format.RGB565,,,false);
    fboTexRegion = new TextureRegion(fbo.getColorBufferTexture());
    fboTexRegion.flip(false, true);batch = new SpriteBatch();
    nebula = new Texture(Gdx.files.internal("images/neb3.png"));
    star = new Texture(Gdx.files.internal("images/starmed.png"));String FRAG = Gdx.files.internal("shaders/blackhole.frag").readString();
    String VERT = Gdx.files.internal("shaders/blackhole.vert").readString();

    shaderprogram = new ShaderProgram(VERT,FRAG);


  public void render () {


    fbo.begin(); //start rendering to fbo,0,0, 1); //clearing fbo;



    batch.setShader(shaderprogram);  //setting up blackhole shader as the default shader
    shaderprogram.setUniformf("time",.15f); // size of blackhole
    shaderprogram.setUniformf("center",.5f,.5f); // 0,0=lower left and 1,1 =upper righ corner


  public void resize(int width, int height) {

  public void pause() {}

  public void resume() {}

  public void dispose () {}

In the above code in the create method we must initialize FBO and fboTexRegion.In the render function


was to initiate rendering to framebuffer which will be post-processed further, then


was to set default shader so everything post this will be rendered as is. After that 2 textures are drawn namely nebula and star, and then


this stops rendering to the framebuffer. Now we set our blackhole shader as the current shader by using


then we draw fboTexRegion which was holding our framebuffer and tada we are done with light bending super powerful blackhole. Remember the center color of blackhole will be your,0,0,1);

if it is set to green then your blackhole will be greenhole 😛
These shaders are based GLSL so you can use them in any game which is in OpenGL, also you can port them to HLSL and use in DirectX Games.

With a slight modification in code using input processor you can achieve what is shown in the video above.

Was this post useful? If yes then please share.

Comments (3)

  1. Interesting but there is missing some code?

    shader.log = ” No matching function for call to smoothstep(float, int, float)”

  2. Try using smoothstep(time,0.0,distance), if the error still persists try creating a new method as descibed in

Leave a Comment

All fields marked with an asterisk (*) are required