2017-05-15 4 views
2

Ich versuche scharfe Konturen aus einer Textur in WebGL anzuzeigen. Ich übergebe eine Textur an meine Fragment-Shader, dann verwende ich lokale Ableitungen, um die Konturen/Umrisse anzuzeigen, aber es ist nicht glatt, wie ich es erwarten würde.Kanten-/Umriss-Erkennung von Textur im Fragment-Shader

Drucken Sie einfach die Textur ohne Verarbeitung funktioniert wie erwartet:

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

Mit lokalen Derivaten, es fehlt ein paar Kanten:

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

Antwort

2

In der Theorie Dein Code ist richtig.

Aber in der Praxis berechnen die meisten GPUs Ableitungen auf Blöcken von 2x2 Pixeln. Also für alle 4 Pixel eines solchen Blocks werden die Werte dFdX und dFdY gleich sein. (detaillierte Erklärung here)

Dies wird eine gewisse Art von Aliasing verursachen und Sie werden einige Pixel für die Kontur der Form zufällig verpassen (dies geschieht, wenn der Übergang von Schwarz nach der Form Farbe an der Grenze eines Blocks 2x2 auftritt).

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

Einige wichtige Dinge:

Um dies zu beheben, und die reale pro Pixel-Derivat erhalten, können Sie es sich stattdessen berechnen kann, dies würde wie folgt aussehen

  • Textur sollte nicht Verwenden Sie Mipmaps
  • Textur min & mag Filterung sollte auf GL_NEAREST gesetzt werden
  • Textur Clamp-Modus sollte eingestellt werden, um (Nr t Wiederholung)

Und hier ist eine ShaderToy Probe, demonstriert dies:

enter image description here