2017-05-15 252 views
2

我试图从WebGL中的纹理显示清晰的轮廓。 我将纹理传递给我的片段着色器,然后使用局部衍生物显示轮廓/轮廓,但是,如我所期望的那样,它不光滑。片段着色器中纹理的边缘/轮廓检测

只需打印纹理不处理按预期工作:

vec2 texc = vec2(((vProjectedCoords.x/vProjectedCoords.w) + 1.0)/2.0, 
      ((vProjectedCoords.y/vProjectedCoords.w) + 1.0)/2.0); 
vec4 color = texture2D(uTextureFilled, texc); 
gl_FragColor = color; 

enter image description here

与当地的衍生物,它错过了一些边缘:

vec2 texc = vec2(((vProjectedCoords.x/vProjectedCoords.w) + 1.0)/2.0, 
      ((vProjectedCoords.y/vProjectedCoords.w) + 1.0)/2.0); 
vec4 color = texture2D(uTextureFilled, texc); 
float maxColor = length(color.rgb); 
gl_FragColor.r = abs(dFdx(maxColor)); 
gl_FragColor.g = abs(dFdy(maxColor)); 
gl_FragColor.a = 1.; 

enter image description here

回答

2

从理论上讲,你的代码是正确的。

但实际上大多数GPU都是在2x2像素块上计算衍生产品。 因此,对于这样的块的所有4个像素,dFdX和dFdY值将是相同的。 (详细说明here

这会导致某种混淆,你会错过一些像素随机形状的轮廓(这种情况发生时,从黑到形状颜色的转变发生在一个2x2块的边界)。

要解决这个问题,并获得每像素衍生真实的,你可以代替你自己计算吧,这应该是这样的:

// get tex coordinates 
vec2 texc = vec2(((vProjectedCoords.x/vProjectedCoords.w) + 1.0)/2.0, 
       ((vProjectedCoords.y/vProjectedCoords.w) + 1.0)/2.0); 

// compute the U & V step needed to read neighbor pixels 
// for that you need to pass the texture dimensions to the shader, 
// so let's say those are texWidth and texHeight 
float step_u = 1.0/texWidth; 
float step_v = 1.0/texHeight; 

// read current pixel 
vec4 centerPixel = texture2D(uTextureFilled, texc); 

// read nearest right pixel & nearest bottom pixel 
vec4 rightPixel = texture2D(uTextureFilled, texc + vec2(step_u, 0.0)); 
vec4 bottomPixel = texture2D(uTextureFilled, texc + vec2(0.0, step_v)); 

// now manually compute the derivatives 
float _dFdX = length(rightPixel - centerPixel)/step_u; 
float _dFdY = length(bottomPixel - centerPixel)/step_v; 

// display 
gl_FragColor.r = _dFdX; 
gl_FragColor.g = _dFdY; 
gl_FragColor.a = 1.; 

一些重要的事情:

  • 质地不应该使用mipmapps
  • 纹理最小& mag过滤应设置为GL_NEAREST
  • 纹理钳位模式应设置为钳位(no反复播放)

这里是一个ShaderToy样品,证明这一点:

enter image description here