25

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

4

5 に答える 5

28

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

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

ここに画像の説明を入力

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

于 2013-10-06T18:08:58.323 に答える
4

これが私のアプローチです。p1 と p2 を直線を定義する 2 点とし、直線までの距離を測定したい点を point とします。ポイントはおそらく 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);
}

次に、それを mix および Smoothstep 関数で使用します。

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

于 2014-11-13T05:49:19.740 に答える
4

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

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

これについての良い議論があります (コード サンプル付き)。

于 2013-03-07T16:36:13.777 に答える
0

フラグメント シェーダーで線を描画するには、現在のピクセル (UV) が線の位置にあることを確認する必要があります。(Fragment シェーダー コードだけを使用すると効率的ではありません! これは glslsandbox を使用したテスト用です) 許容される UV ポイントには、次の 2 つの条件が必要です。

1- (uv、pt1) 間の最大許容距離は、(pt1、pt2) 間の距離よりも小さくする必要があります。この条件では、pt2 を中心とし、半径 = 距離 (pt2, pt1) の仮想円を作成し、距離 (pt2, pt1) よりも長い線の描画も防止します。

2- 各 UV について、ライン (pt2,pt1) の ptc 位置に接続ポイントを持つ仮想円を想定します。UV と PTC の間の距離がライン ティックネスより小さい場合、この UV をライン ポイントとして選択します。

私たちのコードでは: r = 距離 (uv, pt1) / 距離 (pt1, pt2) は、0 と 1 の間の値を与えます。r の値で pt1 と pt2 の間の点 (ptc) を補間します。

コード:

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

float line(vec2 uv, vec2 pt1, vec2 pt2,vec2 resolution)
{
    
    float clrFactor = 0.0;
    float tickness = 3.0 / max(resolution.x, resolution.y);  //only used for tickness
    
    float r  = distance(uv, pt1) / distance(pt1, pt2);
    
    if(r <= 1.0) // if desired Hypothetical circle in range of vector(pt2,pt1)
    {
        vec2 ptc = mix(pt1, pt2, r); // ptc = connection point of Hypothetical circle and line calculated with interpolation
        float dist = distance(ptc, uv);  // distance betwenn current pixel (uv) and ptc
        if(dist < tickness / 2.0)
        {
            clrFactor = 1.0;
        }
    }
    return clrFactor;
}



void main()
{
    vec2 uv = gl_FragCoord.xy / resolution.xy; //current point
    //uv = current pixel
    //      0 < uv.x < 1 , 0 < uv.x < 1
    //      left-down= (0,0)
    //      right-top= (1,1)
    
    vec2 pt1 = vec2(0.1, 0.1);  //line point1 
    vec2 pt2 = vec2(0.8, 0.7);  //line point2 
       
    
    float lineFactor = line(uv, pt1, pt2, resolution.xy);
    vec3 color = vec3(.5, 0.7 , 1.0);
    
    gl_FragColor = vec4(color * lineFactor , 1.);
}
于 2021-01-20T19:56:12.340 に答える