2017-05-15 470 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