web-dev-qa-db-ja.com

フラグメントシェーダーで線の太さを描くことはできますか?

GL_LINESで線を引くことを考慮して、フラグメントシェーダーに線の太さを追加することは可能ですか?私が見たほとんどの例は、フラグメントシェーダーのプリミティブ内のテクセルのみにアクセスしているようで、線の太さのシェーダーは、太さを取得するためにラインプリミティブの外側のテクセルに書き込む必要があります。ただし、可能であれば、非常に小さな基本的な例がいいでしょう。

21
Meda

フラグメントシェーダーを使用すると、かなり多くのことが可能です。見てください 一部の人がやっていること 。私はそのレベルから遠く離れていますが、このコードはあなたにアイデアを与えることができます:

#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

もう1つの方法は、近くのピクセルの色をtexture2Dで確認することです。これにより、画像を白くしたり濃くしたりできます(たとえば、調整ピクセルのいずれかが白の場合、現在のピクセルを白にします。白-現在のピクセルを灰色にします)。

21
defhlt

これが私のアプローチです。 p1とp2をラインを定義する2つのポイントとし、ポイントをラインまでの距離を測定したいポイントとします。ポイントはおそらくgl_FragCoord.xy/resolutionです。

これが関数です。

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);
}

次に、それをミックスおよびスムースステップ関数で使用します。

また、この回答をチェックしてください: https://stackoverflow.com/a/9246451/911207

4
David Braun

いいえ、フラグメントシェーダーではGL_LINESのみを使用することはできません。これは、GLは、ラスタライザに送信するジオメトリのみに描画することを制限するため、ギザギザの元のラインとスムージング頂点を含むジオメトリを使用する必要があるためです。たとえば、ジオメトリシェーダーを使用して、太い線のようにポーズをとることができる理想的な線(または実際には2つの三角形)の周りの四角形に線を拡張します。

一般に、より大きなジオメトリ(フルスクリーンクワッドを含む)を生成する場合、フラグメントシェーダーを使用して滑らかな線を描くことができます。

Here's その件に関する素敵な議論(コードサンプル付き)。

1
ltjax

単純なハックは、頂点シェーダーにジッターを追加することです:gl_Position + = vec4(delta、delta、delta、0.0);ここで、deltaはピクセルサイズ、つまり1.0/viewsizeです。

ゼロを使​​用して線描画パスを2回実行し、次にデルタをジッターとして使用します(ユニフォームとして渡されます)。

0
KBVIS