web-dev-qa-db-ja.com

フラグメントシェーダーで2Dポリゴンに境界線を描く

GL_TRIANGLESとフラットカラー、2Dシミュレーションを使用して、単純なxy平面上にフラットにレンダリングするいくつかの単純なポリゴン(20頂点未満)があります。

これらのポリゴンに、さまざまな太さの境界線と異なる色を追加したいと思います。同じ頂点とglLineWidth/GL_LINE_LOOPを使用して実装されたものがあります。これは機能しますが、別のレンダリングパスであり、すべての頂点変換を繰り返します。

Gl_FragCoordと頂点データまたはテクスチャ座標、あるいはその両方を使用してフラグメントシェーダーでこれを実行できるはずだと思いますが、よくわかりません。単純な試みは明らかに正しくありません。

次のようなものを想像します。

uniform vec2 scale;  // viewport h/w
uniform float line_width;
uniform vec4 fill_color;
uniform vec4 border_color;

varying vec4 vertex; // in world coords

void main()
{
    if (distance_from_Edge(gl_FragCoord, vertex, scale) < line_width)
    {
        // we're close to the Edge the polygon, so we're the border.
        gl_FragColor = border_color;
    }
    else
    {
        gl_FragColor = fill_color;
    }
}

私が理解しようとしている部分はdistance_from_Edge関数です-それはどのように計算できますか? gl_FragCoordの使用は間違ったアプローチです-ある種のテクスチャマッピングを使用する必要がありますか?

実験として、スケールを使用して頂点をピクセル空間に変換し、そのピクセルとgl_FragCoordの間の距離をピクセル単位で計算してみましたが、奇妙な結果が得られましたが、私は実際には理解していませんでした。さらに、頂点ではなくエッジまでの距離が必要ですが、それを取得する方法はわかりません。

何か案は?

編集:ニコルの応答に基づいて、私の質問は次のようになります:

エッジ頂点としてマークされた3つのコーナー頂点と、エッジではないとしてマークされた中央の1つの頂点がある三角形(合計で3つの三角形でレンダリングされている)があるとすると、フラグメントシェーダーで補間して特定の境界を描画する方法厚さ? Edgeフラグをフラグメントシェーダーに渡し、必要な線の太さを渡し、補間計算を行って、エッジ頂点とエッジ頂点ではないエッジ間の距離を計算し、必要に応じて境界/塗りつぶしとして色にしきい値を設定します?

21
bloodearnest

三角形を扱っているので、必要なのは重心座標だけです。三角形の各頂点にIDを割り当て、頂点とフラグメントステージ間のハードウェアの組み込み補間を使用して、フラグメントシェーダーの各頂点からの相対距離を計算します。

各頂点の重心座標は、反対側のエッジからの距離と考えることができます。下の図では、頂点P0の反対側のエッジはe1であり、その距離はh1で表されます。その重心座標は<0.0, h1, 0.0>。 GPUは、この座標空間を内部で使用して、ラスタライズ中にフラグメントが生成されたときに三角形の頂点属性を補間し、三角形内の位置に基づいて頂点ごとのプロパティに重み付けをすばやく行うことができます。

Diagram illustrating the calculation of distance from each Edge

以下は、これを行う方法を説明する2つのチュートリアルです。これは通常、ワイヤーフレームオーバーレイのレンダリングに使用されるため、検索に成功する可能性があります。目的のために、これは事実上ワイヤーフレームレンダリングの特殊化であるため(追加で、ポリゴンの外部エッジに属さないラインを破棄する必要があるため)、エッジの頂点を識別し、追加の処理を実行する必要があります。

たとえば、頂点が外部エッジの一部でない場合、それに<1,100,0>のような重心座標を割り当て、接続された頂点<0,100,1>と内部エッジは無視されます(仮定すると)これは、下の図に示すように、<0,1,0>と指定された頂点の反対側のエッジです。アイデアは、このEdgeに沿ったポイントが0.0(または境界線の一部としてフラグメントをシェーディングするために使用するしきい値)の近くで補間しないようにして、三角形の中心からの方向に極端に離れていることです。反対の頂点はこれを解決します。

Diagram showing how to exclude interior edges

ジオメトリシェーダーなし(OpenGL ES対応):

重心座標を保持するように頂点データを変更できる場合、これを行う方法を説明するリンクは次のとおりです。ストレージと前処理の要件が高くなります(特に、隣接するエッジ間での頂点の共有は、それぞれの三角形が異なる入力重心座標を持つ3つの頂点で構成される必要があるため、ジオメトリシェーダーが望ましい解決策)。ただし、ジオメトリシェーダーを必要とする一般的なソリューションよりもはるかに多くのOpenGL ESクラスハードウェアで実行されます。

https://web.archive.org/web/20190220052115/http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/

ジオメトリシェーダー(ない OpenGL ESフレンドリー):

または、このチュートリアルに示すように、ジオメトリシェーダーを使用して、レンダリング時に各三角形の重心座標を計算することもできます。 OpenGL ESでは、ジオメトリシェーダーにアクセスできない可能性があるため、これはおそらく無視できます。

http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_10.htmlhttp://strattonbrazil.blogspot.com/2011/09/single- pass-wireframe-rendering_11.html

このソリューションの理論的根拠はここにあります(Internet Archive Wayback Machineの厚意による):

http://web.archive.org/web/ */ http://cgg-journal.com/2008-2/06/index.html

27