David Brock
David Brock

Reputation: 11

Weird Line When Wrapping Image in Fragment Shader

I have made a simple fragment shader using THREE.js. It reads each pixel's coordinate, adds a value to the x component (wrapping to 0 if it goes above 1), and returns the color of a background image at this new location. This has the effect of shifting the background image over and wrapping the part that goes off-screen. The problem is that a dark line sometimes appears where the edge of the image is shifted over:

here is a picture

Here is my code:

var vertexShader = `
varying vec2 vUv;

void main() {
  vUv = uv;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;

var fragmentShader = `
varying vec2 vUv;

uniform sampler2D background;

void main() {
  float x = mod(vUv.x + 0.47, 1.0);
  float y = vUv.y;

  gl_FragColor = texture(background, vec2(x, y));
}
`;

$(document).ready(function() {
  var plotElement = $("#plot");

  var scene = new THREE.Scene();
  var renderer = new THREE.WebGLRenderer();
  var camera = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5, 0, 1000);

  renderer.setSize(500, 500);
  plotElement.append(renderer.domElement);

  var background = new THREE.TextureLoader().load('https://wearablewearyphase.davidbrock1.repl.co/background.png');

  var material = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    uniforms: {
      background: {
        value: background
      },
    },
  });

  geom = new THREE.PlaneBufferGeometry(1, 1);
  mesh = new THREE.Mesh(geom, material);
  scene.add(mesh);
  camera.z = 1;

  function render() {
    requestAnimationFrame(render);

    renderer.render(scene, camera);
  }

  render();
});
<!DOCTYPE html>
<html>

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r118/three.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>

<body>
  <div id="plot"></div>
</body>

</html>

I am quite sure that the line is not in the original image:

original image

The boundary should not be visible at all because the left and right sides are the same color. Furthermore, the line only appears for some shift distances (49% and 47%, but not 50% or 48%, for example). I have found that if I make the output bigger than the background image than the line disappears, but I would prefer not to do this.

What is causing this line and how can I prevent it?

Note: I just used the "mod" function as an example. Originally, I had another program (another shader) calculate x and y coordinates for every pixel and save them in another texture as the red and green components. The fragment shader then looked these coordinates up in the image.

I ran into this problem while trying to create an animation like this. The lines started appearing all over the screen and did not look good.

Upvotes: 1

Views: 186

Answers (1)

M -
M -

Reputation: 28472

This is happening because the fragment shader interpolates values across pixels. So one pixel column approaches 1.0, the next one is a very squished version of your entire texture between 1.0 - 0.0, and the next one starts over at 0.0.

The easiest way to circumvent this behavior is to set your texture's wrapping mode to THREE.RepeatWrapping and get rid of the mod() so as your texture goes above 1.0, it'll automatically start over from the left again.

Upvotes: 1

Related Questions