GLSLで三角形ポリゴンをオフセット/縮小するにはどうすればよいですか?


8

頂点シェーダーを使用して、他の独立したすべての(青い)三角形をオフセットする必要があります。三角形全体を操作するために、左(紫)と右(緑)の隣接する頂点を表す各頂点(赤)のカスタム(vec3)属性を作成しました。これから、隣接する両方のエッジから等距離にある(スクリーン空間で)オレンジのポイントを導出する必要があります。各三角形から派生したこのようなオレンジ色の点が3つあるため、処理された(オレンジ色の)三角形がフラグメントシェーダーに渡されます。

頂点ごとの操作 オフセット三角形

理想的には、オフセットが2番目の画像の2番目の三角形のように三角形内の使用可能なスペースを無効にする場合、三角形はカリングされます(背面/レンダリングされないなど)。

データ構造としてTHREE.BufferGeometry()を使用しています。

これが私が目指している効果のスクリーンショットです:

ここに画像の説明を入力してください


幅広いコンテキストについてもう少し詳しく説明してもらえますか?オフセット三角形は、元のメッシュのように接続されたままですか?「カリング」とは、元の三角形が破棄されることを意味しますか、それとも、オフセットが破棄され、三角形を元のサイズのままにしておくことを意味しますか?
trichoplax

1
それで...これはメッシュでどのように機能しますか?メッシュでは、頂点に3つ以上の隣接があるためです。それとも、これは個々の三角形だけのものですか?
Nicol Bolas

私の実装では、すべての三角形が連続したバッファーに配置されます:[P1.x、P1.y、P1.z、P2.x、P2.y、P2.z ... Pn.x、Pn.y、 Pn.z]隣接するポイントも属性で明示的にレイアウトされます。このようにして、隣接する面に影響を与えることなく、各面の各頂点を計算および操作できます。ニコル・ボーラス、はい、各三角形を個別に扱います。
ジャッカロープ2017年

trichoplax-「カリング」とは、後ろ向きの片面プリミティブのように、レンダリングされずに投げ出されることを意味します。
ジャッカロープ2017年

1
@Jackalope:「どちらも、GPUが顔を他の顔に「つながれた」と見なすことを示唆しているようです。ほとんどのメッシュは、隣接する三角形に「同一の属性」を使用させるだけではありません。同じ頂点を再利用ます。これは、同じインデックスを複数回使用する三角形のリスト、または三角形のストリップなどを介して行うことができます。しかし、一般的に言えば、メッシュは隣接する頂点を再利用します。メッシュは変化しませんが、特定のケースは一般的なケースを変更しません。だから私は説明を求めました。
Nicol Bolas

回答:


9

三角形▲ABCが与えられた場合、角度∠BACを直線ADで二等分し、角度二等分定理で導出されます。

BA / BD = CA / CD 三角差込図 ポイントEは、結果として得られる希望のはめ込み三角形上での目的の精密な位置を表します。角度二等分線ADにあるため、BAとCAの側面から等距離にあり、同一の直角三角形▲AFEと▲AGEを形成します。Sine for Right Trianglesを使用して、AEの長さを見つけることができます。

AE = EG / Sin(∠EAG)

これですべての計算が完了するので、GLSLを作ってみましょう。

まず、位置、法線、変換行列などのすべての一般的な属性から始めますが、頂点シェーダーは単一の頂点でのみ機能するため、隣接する頂点を追加の属性として追加する必要があります。このようにして、各頂点は独自の「点E」を見つけ、結果のはめ込み三角形を作成します。(注:それらはまだ画面スペースにないため、ここでは「B」および「C」と呼ばないでください。)

    attribute vec3 left; //vertex to the left of this vertex
    attribute vec3 right; //vertex to the right of this vertex

画面スペースと言えば、ディスプレイの縦横比も含めています(ウィンドウのサイズが変更された場合に備えて、画面のアスペクト比を均一にします)。

フラグメントシェーダーのさまざまな法線を準備し、顔をクリッピングスペースに変換したら、上記の計算を適用することに取り掛かることができます。

        attribute vec3 left; //vertex to the left of this vertex
        attribute vec3 right; //vertex to the right of this vertex
        uniform float aspect;
        varying vec3 vNormal;
        varying vec2 vUv;

        void main() {
            vNormal = normal;
            vUv = uv;

            mat4 xform= projectionMatrix * modelViewMatrix;
            vec4 A = xform * vec4( position, 1.0 );
            vec4 B = xform * vec4( left, 1.0 );
            vec4 C = xform * vec4( right, 1.0 );

            vec3 CB = C.xyz - B.xyz;
            vec2 BA = B.xy - A.xy;
            vec2 CA = C.xy - A.xy;
            float lengthBA = length(BA);
            float lengthCA = length(CA);
            float ratio = lengthBA / ( lengthBA + lengthCA );
            vec3 D = B.xyz + ratio * CB.xyz;
            vec3 AD = D - A.xyz;
            vec3 bisect = normalize(AD);

            float theta = acos( dot(BA, CA) / (lengthBA * lengthCA) ) / 2.0;
            float AE = 1.0/(sin(theta)*aspect);
            newPos.z += AE/length(AD) * (D.z - A.z);
            newPos.x += bisect.x*AE;
            newPos.y += bisect.y*AE;

            gl_Position = newPos;
        }

このコードにより、以下の結果が得られます。

スクリーンショット

このプロセスによって裏切りされた三角形のほとんどに関係するエッジケースがいくつかあることに注意してください。コードでこれに対処し始めましたが、今のところこれらのケースを単に回避することにしました。たぶん、このプロジェクトが完了したら、もう一度見直すでしょう。


1
これを理解する素晴らしい仕事!最初の数学的記述は本当に好きです。
user1118321

0

これは、三角形の内接を縮小することにより、三角関数なしで実現できます。

incircle()頂点によって形成される三角形の内接円を計算し、A,B,C中心と半径をとして返しますvec4。次に、頂点X=A,B,Cは、Q-X内接円半径に対する希望のマージンの比率()に等しい、内接円中心()までの距離の分数だけ内側に移動しm/Q.wます。

vec4 incircle(vec3 A, vec3 B, vec3 C) {
    float a = length(B - C), b = length(C - A), c = length(A - B);
    float abc = a + b + c;
    // http://mathworld.wolfram.com/Incenter.html
    vec3 I = (a * A + b * B + c * C) / abc;
    // http://mathworld.wolfram.com/Inradius.html
    float r = 0.5
            * sqrt((-a + b + c) * (a - b + c) * (a + b - c) / abc);
    return vec4(I, r);
}

vec3 A,B,C; // vertices
float m; // margin
vec4 Q = incircle(A,B,C);
A += clamp(m / Q.w, 0.0, 1.0) * (Q.xyz - A);
B += clamp(m / Q.w, 0.0, 1.0) * (Q.xyz - B);
C += clamp(m / Q.w, 0.0, 1.0) * (Q.xyz - C);

非常に興味深い、アダム!この機能について聞いたことがありませんでした。
ジャッカロープ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.