web-dev-qa-db-fra.com

Est-il possible de dessiner une épaisseur de trait dans un fragment shader?

Est-il possible pour moi d'ajouter l'épaisseur de ligne dans le fragment shader en considérant que je trace la ligne avec GL_LINES? La plupart des exemples que j'ai vus semblent ne concerner que les texels de la primitive du fragment shader et un shader d'épaisseur de trait aurait besoin d'écrire dans des texels situés en dehors du primitif de ligne pour obtenir l'épaisseur. S'il est possible cependant, un très petit exemple basique serait formidable.

18
Meda

Beaucoup est possible avec les shaders de fragments. Il suffit de regarder ce que certains gars font . Je suis loin de ce niveau moi-même mais ce code peut vous donner une idée:

#define resolution vec2(500.0, 500.0)
#define Thickness 0.003

float drawLine(vec2 p1, vec2 p2) {
  vec2 uv = gl_FragCoord.xy / resolution.xy;

  float a = abs(distance(p1, uv));
  float b = abs(distance(p2, uv));
  float c = abs(distance(p1, p2));

  if ( a >= c || b >=  c ) return 0.0;

  float p = (a + b + c) * 0.5;

  // median to (p1, p2) vector
  float h = 2 / c * sqrt( p * ( p - a) * ( p - b) * ( p - c));

  return mix(1.0, 0.0, smoothstep(0.5 * Thickness, 1.5 * Thickness, h));
}

void main()
{
  gl_FragColor = vec4(
      max(
        max(
          drawLine(vec2(0.1, 0.1), vec2(0.1, 0.9)),
          drawLine(vec2(0.1, 0.9), vec2(0.7, 0.5))),
        drawLine(vec2(0.1, 0.1), vec2(0.7, 0.5))));
}

enter image description here

Une autre alternative est de vérifier avec texture2D la couleur du pixel proche - de cette façon, vous pouvez rendre votre image luisante ou épaissie (par exemple, si l'un des pixels de réglage est blanc - activez le pixel actuel, si le pixel voisin est blanc - réglez le courant pixel gris).

18
defhlt

Voici mon approche. Soit p1 et p2 les deux points définissant la ligne, et point le point dont la distance à la ligne que vous souhaitez mesurer. Le point est probablement gl_FragCoord.xy/resolution;

Voici la fonction.

float distanceToLine(vec2 p1, vec2 p2, vec2 point) {
    float a = p1.y-p2.y;
    float b = p2.x-p1.x;
    return abs(a*point.x+b*point.y+p1.x*p2.y-p2.x*p1.y) / sqrt(a*a+b*b);
}

Ensuite, utilisez-le dans vos fonctions de mixage et de smoothstep.

Vérifiez également cette réponse: https://stackoverflow.com/a/9246451/911207

3
David Braun

Non, ce n'est pas possible dans le fragment shader. Cependant, vous pouvez utiliser un shader de géométrie pour développer votre ligne en un quad (ou en fait deux triangles) pouvant constituer une ligne épaisse. 

Voici une belle discussion sur ce sujet (avec des exemples de code).

1
ltjax