Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to eliminate texture seams from mipmapping

I'm using texture blending in my terrain's fragment shader to blend from one texture to the next. Right at the seam between using only my grass texture and blending between dirt/grass or snow/grass textures, the mipmaps seem to cause an ugly seam (see photo below). Disabling mipmapping fixes the problem but makes my terrain very grainy/ugly at a distance. Is there a way to eliminate this seam without disabling mipmapping?


terrain-vs.glsl:

precision mediump float;

attribute vec3 Position;
attribute vec2 TextureCoord;

uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

varying vec2 texCoord;
varying float y;

void main(void) {
  gl_Position = uPMatrix * uMVMatrix * vec4(Position, 1.0);
  texCoord = TextureCoord;
  y = Position.y;
}

terrain-fs.glsl:

precision mediump float;

uniform sampler2D dirt_texture;
uniform sampler2D grass_texture;
uniform sampler2D snow_texture;

varying vec2 texCoord;
varying float y;

void main(void) {
  if (y < -5.0) {
    gl_FragColor = texture2D(dirt_texture, texCoord);
  } else if (y < 0.0) {
    gl_FragColor = mix(
      texture2D(dirt_texture, texCoord),
      texture2D(grass_texture, texCoord),
      (y + 5.0) / 5.0
    );
  } else if (y < 3.0) {
    gl_FragColor = texture2D(grass_texture, texCoord);
  } else if (y < 5.0) {
    gl_FragColor = mix(
      texture2D(grass_texture, texCoord),
      texture2D(snow_texture, texCoord),
      (y - 3.0) / 2.0
    );
  } else {
    gl_FragColor = texture2D(snow_texture, texCoord);
  }
}

TextureManager::initialize

gl.bindTexture(gl.TEXTURE_2D, texture.texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);

Configuration:

  • Windows 7 Pro SP1
  • Google Chrome 24.0.1312.57 m
  • NVIDIA GTX 680

normal view normal view

zoomed in zoomed in

like image 370
Andrew Rasmussen Avatar asked Feb 08 '13 04:02

Andrew Rasmussen


1 Answers

Explanation why the original fragment shader produces artifacts

GPU needs to know gradients to sample a texture. You either supply the gradients explicitly (textureGrad) or you let GPU to compute the gradients for you. The automatically computed gradient are computed using local differencing. See function dFdx (http://www.opengl.org/sdk/docs/manglsl/xhtml/dFdx.xml) for details.

Computing derivatives produces undefined result when the function evaluates for one pixel but not for nearby pixels (non uniform control flow).

The shader in Answer 1 works well because the textures are always sampled, no matter if their result is used or not.

More info is here http://www.opengl.org/wiki/Sampler_(GLSL)#Non-uniform_flow_control

like image 175
Maf Avatar answered Oct 14 '22 04:10

Maf