As a solution for this question I implemented the shader with a test program:

import com.badlogic.gdx.ApplicationAdapter
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.Sprite
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.glutils.ShaderProgram

class ShaderTestApp : ApplicationAdapter() {
  lateinit var batch: SpriteBatch
  lateinit var noiseTexture: Texture
  lateinit var sprite: Sprite
  lateinit var shaderProgram: ShaderProgram

  private val vertexShaderString = """
    attribute vec4 a_position;
    attribute vec4 a_color; //required by libgdx
    attribute vec2 a_texCoord0;

    uniform mat4 u_projTrans;

    varying vec4 v_color;
    varying vec2 v_texCoords;

    void main() {
      v_color = a_color;
      v_texCoords = a_texCoord0;
      gl_Position = u_projTrans * a_position;

  private val fragmentShaderString = """
     #ifdef GL_ES
      precision mediump float;

  varying vec4 v_color;
  varying vec2 v_texCoords;

  uniform sampler2D u_noise;
  uniform sampler2D u_texture;
  uniform mat4 u_projTrans;

  uniform float u_noise_scale;
  uniform vec2 u_noise_scroll_velocity;
  uniform float u_distortion;
  uniform float u_time;

  void main() {
          vec2 waveUV = v_texCoords * u_noise_scale;
          vec2 travel = u_noise_scroll_velocity * u_time;
          vec2 uv = v_texCoords;
          uv = uv + (u_distortion * (texture2D(u_noise, waveUV + travel).rgb - 0.5));
          waveUV += 0.2;
          uv = uv + (u_distortion * (texture2D(u_noise, waveUV - travel).rgb - 0.5));
          vec3 color = texture2D(u_texture, uv).rgb;
          gl_FragColor = vec4(color, 1.0);

  override fun create() {
    batch = SpriteBatch()
    val img = Texture("background/water-surface-reflection-withBg.png")
    img.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat)
    noiseTexture = Texture("background/gradient.png")
    noiseTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat)
    sprite = Sprite(img)
    sprite.setSize(Gdx.graphics.width.toFloat(), Gdx.graphics.height.toFloat())

    shaderProgram = ShaderProgram(vertexShaderString, fragmentShaderString)
    if (!shaderProgram.isCompiled) {

  var time = 0f
  override fun render() {
    time += Gdx.graphics.deltaTime
    Gdx.gl.glClearColor(1f, 0f, 0f, 1f)

    shaderProgram.setUniformf("u_noise_scale", 0.1f)
    shaderProgram.setUniform2fv("u_noise_scroll_velocity", floatArrayOf(.006f, .007f), 0, 2)
    shaderProgram.setUniformf("u_distortion", 0.04f)
    shaderProgram.setUniformf("u_time", time)
    batch.shader = shaderProgram
    batch.draw(sprite, sprite.x, sprite.y, sprite.width, sprite.height)

object ShaderTestLauncher {
  fun main(arg: Array<String>) {
    val config = LwjglApplicationConfiguration()
    config.samples = 2
    config.width = 640
    config.height = 640
    LwjglApplication(ShaderTestApp(), config)

Which looks like this:

enter image description here

  • 1
    \$\begingroup\$ It looks like you might be using nearest / point filtering on the noise texture, instead of bilinear. Can you confirm? \$\endgroup\$ – DMGregory Sep 23 '18 at 21:14
  • \$\begingroup\$ It was set to Nearest (GL_NEAREST) but replacing it with Linear (GL_LINEAR) but it had no effect on the noise texture. Setting it on the main texture hat a BIG impact, it looks perfect now. \$\endgroup\$ – morpheus05 Sep 23 '18 at 21:31
  • 1
    \$\begingroup\$ Sweet! Feel free to write up the changes you made as an answer. :) \$\endgroup\$ – DMGregory Sep 23 '18 at 21:32

After an input from DMGregory I added the following lines after instantiating all textures:

img.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
noiseTexture.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)

It looks perfect now.

Result as requested:

enter image description here

| improve this answer | |
  • \$\begingroup\$ For the sake of completeness, you might want to add an animated gif of the result :) \$\endgroup\$ – Vaillancourt Sep 24 '18 at 0:26
  • \$\begingroup\$ ok, I added an gif with the result \$\endgroup\$ – morpheus05 Sep 24 '18 at 19:32

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.