1

XNA で 2D ゲームをプログラミングしています。これで、レベル要素を定義するポリゴンができました。それらは、簡単にレンダリングできるように三角形化されています。ここで、ポリゴンをアウトライン テクスチャとしてレンダリングするシェーダーを書きたいと思います。そのため、ポリゴンの真ん中にテクスチャが表示され、境界線で何とか光るはずです。

私の最初のアイデアは、ポリゴンに沿って歩き、特定のテクスチャで各線分にクワッドを描くことでした。これは機能しますが、テクスチャが強制的にオーバーラップする小さなコーナーでは奇妙に見えます。

私の 2 番目のアプローチは、すべての境界頂点を、ポリゴンの外側を指すある種の法線でマークすることでした。これをシェーダーに渡すと、三角形分割のエッジ全体で法線が補間され、補間された「法線」をシェーディングの値として使用できます。まだテストできませんでしたが、うまくいきますか?三角形分割の特別な特性は、すべての頂点が境界線上にあるため、ポリゴンの内側に頂点がないことです。

私が達成したいことについて、皆さんはより良いアイデアを持っていますか?

クワッド ソリューションを使用した現在の外観の写真は次のとおりです。

輪郭を描かれた多角形

4

3 に答える 3

1
  1. オブジェクトを 2 回レンダリングできます。最初のものの背後にあるより大きなストレッチ バージョン。複雑なオブジェクトを均一に引き伸ばして境界線を作成することはできないため、理想的ではありません。

  2. スクリーン バッファにアクセスできる場合は、グロー コンポーネントをレンダー ターゲットにレンダリングし、フルスクリーン クワッドをビューポートに合わせて、フルスクリーン 2D シルエット フィルタを追加できます。

    このようにして、半径、色、ぼかしを定義することで、エッジを完全に制御できます。オブジェクト レンダー パスからの RGB 値などの追加の出力値を使用すると、さまざまな高度なグローを使用することもできます。

    rendermonkey のシェーダー エディターにはいくつかの例があったと思います。それは間違いなく、作業して物事を試すための良い出発点です.

于 2012-04-24T19:08:30.050 に答える
1

必要に応じて、新しい境界頂点リストを計算します (元の三角形ストリップを使用した簡単な塗りつぶしの例)。一定の境界線幅と凸多角形を使用する場合は、次のようになります。

B_new = B - (BtoA.normalized() + BtoC.normalized()).normalized() * 幅;

ここに画像の説明を入力

そうでない場合は、さらに複雑になる可能性があります。古いがかなり普遍的な解決策があります。


//Helper function. To working right, need that v1 is before v2 in vetex list and vertexes are going to (anti???) cloclwise! float vectorAngle(Vector2 v1, Vector2 v2){

    float alfa;

    if (!v1.isNormalised())
        v1.normalise();
    if (!v2.isNormalised())
        v2.normalise();

    alfa = v1.dotProduct(v2);

    float help = v1.x;
    v1.x = v1.y;
    v1.y = -help;

    float angle = Math::ACos(alfa);

    if (v1.dotProduct(v2) < 0){
        angle = -angle;
    }


    return angle;
}

//Normally dont use directly this!
Vector2 calculateBorderPoint(Vector2 vec1, Vector2 vec2, float width1, float width2){

    vec1.normalise();
    vec2.normalise();

    float cos = vec1.dotProduct(vec2);            //Calculates actually cosini of two (normalised) vectors (remember math lessons)
    float csc = 1.0f / Math::sqrt(1.0f-cos*cos);  //Calculates cosecant of angle, This return NaN if angle is 180!!!

    //And rest of the magic
    Vector2 difrence = (vec1 * csc * width2) + (vec2 * csc * width1);


    //If you use just convex polygons (all angles < 180, = 180 not allowed in this case) just return value, and if not you need some more magic. 
    //Both of next things need ordered vertex lists!



    //Output vector is always to in side of angle, so if this angle is.
    if (Math::vectorAngle(vec1, vec2) > 180.0f) //Note that this kind of function can know is your function can know that angle is over 180 ONLY if you use ordered vertexes (all vertexes goes always (anti???) cloclwise!)
        difrence = -difrence;


    //Ok and if angle was 180...
    //Note that this can fix your situation ONLY if you use ordered vertexes (all vertexes goes always (anti???) cloclwise!)
    if (difrence.isNaN()){
        float width = (width1 + width2) / 2.0;   //If angle is 180 and border widths are difrent, you cannot get perfect answer ;)

        difrence = vec1 * width;

        //Just turn vector -90 degrees
        float swapHelp = difrence.y
        difrence.y = -difrence.x;
        difrence.x = swapHelp;
    }

    //If you don't want output to be inside of old polygon but outside, just: "return -difrence;"
    return difrence;

}

//Use this =)
Vector2 calculateBorderPoint(Vector2 A, Vector2 B, Vector2 C, float widthA, float widthB){
    return B + calculateBorderPoint(A-B, C-B, widthA, widthB);
}

于 2012-11-27T00:59:53.587 に答える
0

あなたの2番目のアプローチが可能になる可能性があります...

外側の頂点 (境界) を 1 でマークし、内側の頂点 (内側) を 0 でマークします。

ピクセル シェーダーでは、その値が 0.9f または 0.8f より大きいものを強調表示するように選択できます。

それはうまくいくはずです。

于 2012-04-24T17:24:39.683 に答える