2017-05-15 5 views
2

J'essaie d'afficher des contours nets à partir d'une texture dans WebGL. Je passe une texture à mes fragments shaders puis j'utilise des dérivées locales pour afficher les contours/contours, cependant, ce n'est pas lisse comme je le souhaiterais.Détection de contour/contour à partir de la texture dans le fragment shader

impression Juste la texture sans travaux de transformation comme prévu:

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

avec des dérivés locaux, il manque quelques bords:

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

Répondre

2

En théorie, votre code est bon. Mais en pratique, la plupart des GPU calculent des dérivés sur des blocs de 2x2 pixels. Donc, pour les 4 pixels d'un tel bloc, les valeurs dFdX et dFdY seront les mêmes. (explication détaillée here)

Cela entraînera une sorte de aliasing et vous manquera quelques pixels pour le contour de la forme (ce qui se produit au hasard lorsque la transition du noir à la couleur de forme se produit à la frontière d'un bloc 2x2).

Pour résoudre ce problème, et obtenir le réel par dérivé de pixel, vous pouvez plutôt calculer vous-même, cela ressemblerait à ceci:

// 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.; 

Quelques choses importantes:

  • texture ne devrait pas utiliser des mipmaps
  • texture min & le filtrage de mag doit être réglé sur GL_NEAREST
  • le mode de blocage de texture doit être réglé sur pince (non t répétition)

Et voici un échantillon ShaderToy, ce qui démontre ceci:

enter image description here