OpenGL-エッジの検出


11

任意のメッシュをロードし、エッジに沿って太い黒い線を描画して、トゥーンシェーディングのような外観にします。ステンシルバッファーを使用して、オブジェクトの周りに黒いシルエットを描くことができました。あなたはここで結果を見ることができます:

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

しかし、欠けているのはオブジェクト自体の黒い線です。法線の不連続性をチェックすることを考えました:隣接するピクセルが現在のものとは異なる法線ベクトルを持っているかどうかをチェックします。はいの場合、エッジが見つかりました。残念ながら、OpenGLでもGLSL頂点/フラグメントシェーダーでも、このアプローチをどのように実装できるかわかりません。

このアプローチやエッジ検出に関するその他のサポートについて、私はとても嬉しく思います。

編集:メッシュにテクスチャを使用していません。

もっと正確に言うと、次のように見えるCAD / CAMソリューションを作成したいと思います(Top Solid https://www.youtube.com/watch?v=-qTJZtYUDB4から取得):

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


「エッジ」をより詳細に定義する必要があると思います。単純なワイヤーフレームとどう違うのですか?cifzの回答には、スクリーンスペースの後処理の適切な説明がありますが、質問からそれが適用可能かどうかを判断することは困難です。
Andreas

まあ、エッジとは、固体を形成する「折り目」と「尾根」を意味します。ワイヤーフレームはすべての三角形の面を表示しますが、これは私が望むものではありません。
enne87 2016年

わかりました、まさに私が求めたこと:-)私はそれらの折り目と尾根からワイヤーフレームを生成します。まだ難しいのは、折り目/尾根が何であるかを決定することです。それを行う方法について何か考えがありますか?
Andreas

1
CADプログラムは、ほとんどの場合、これをシェーダーで行いません。代わりに、モデルからのハードエッジを認識し、その情報からメッシュの上に線を引きます。
joojaa 2016年

joojaaこのテクニックについてもっと情報がありますか?二重曲面自由曲面の場合はどうしますか?また、何か自由な形で切り取られたり切り取られたりしているコーンやシリンダーがあるとどうなるかわかりません。stackoverflow.com/questions/43795262/...
斗山Bosnjak 'pailhead'

回答:


17

一般に、エッジ検出は沸騰して、勾配値の高い画像の領域を検出します。

私たちの場合、勾配を画像関数の微分として大まかに見ることができるので、勾配の大きさは、(隣接するピクセル/テクセルに関して)画像が局所的にどれだけ変化するかについての情報を提供します
これで、エッジは不連続性の指標となるので、グラデーションを定義したので、この情報で十分です。画像の勾配が見つかったら、それをしきい値に適用してバイナリ値のエッジ/非エッジを取得するだけです。

この勾配をどのように見つけるかは本当にあなたが求めていることであり、私はまだ答えていません:)

たくさんの方法!ここにカップル:)

組み込みシェーダー関数

hlslとglslはどちらも派生関数を提供します。GLSLには、x方向とy方向の勾配情報をそれぞれ提供するdFdxとdFdyがあります。通常、これらの関数は2x2フラグメントのブロックで評価されます。
単一方向に関心がない限り、領域内の勾配がどれほど強いかを示すコンパクトな結果を得る良い方法は、dFdyとdFdyの絶対値の合計以外に何も与えないfwidthです。
特定のチャネルではなく画像全体のエッジに関心がある可能性があるため、画像関数を輝度に変換することができます。これを念頭に置いて、エッジ検出に関しては、シェーダーに次のものを含めることができます。

  float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
  float gradient = fwidth(luminance );
  float isEdge = gradient > threshold;

高いしきい値では粗いエッジが見つかり、逆に低いしきい値では誤ったエッジが検出される可能性があります。自分のニーズにより適したしきい値を見つけるために実験する必要があります。

これらの関数が機能する理由は言及する価値がありますが、今はその時間がないので、後でこの回答を更新する可能性があります:)

画面スペースの後処理

これよりも洗練された方法で、画像処理におけるエッジ検出の分野は広大です。必要に応じてエッジ検出を検出するための数十の方法を紹介しますが、ここでは簡単にしてみましょう。興味があれば、さらに多くのオプションを紹介できます。

したがって、アイデアは上記のものと似ていますが、必要に応じて、より広い近傍を見て、周囲のサンプルに一連の重みを使用できるという違いがあります。通常、カーネルを使用して画像に対してたたみ込みを実行すると、結果として適切な勾配情報が得られます。
非常に一般的な選択はSobelカーネルです

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

これにより、それぞれx方向とy方向の勾配が得られます。

                                  私がずっと前に書いた古いpdfから。

として、勾配から単一の値を取得できます。GradientMagnitude=(Gradientx)2+(Gradienty)2

次に、前述の方法と同じようにしきい値を設定できます。

ご覧のように、このカーネルは中央のピクセルにより多くの重みを与えるので、効果的に勾配+伝統的に役立つ少しの平滑化を計算します(多くの場合、画像はガウスぼかしで小さなエッジを除去します)。

上記は非常にうまく機能しますが、平滑化が気に入らない場合は、Prewittカーネルを使用できます。

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

(私は急いでいることに注意してください、すぐに画像の代わりに適切なフォーマットのテキストを書きます!)

実は、リアルタイムグラフィックスではなく、画像処理-方法でエッジ検出を検出するためのカーネルとテクニックはたくさんあります。したがって、dFdx / y関数でうまくいくので、より複雑な(意図しない)メソッドを除外しました。 。


非常に素晴らしい説明cifzですが、特定の状況でグラデーションが表示されない場合はどうなりますか?たとえば、立方体の背面には光源がないため、グラデーションは表示されません。次に、あなたが説明するこの画像ベースのエッジ検出プロセスは機能しないでしょう、そうですか?
enne87 2016年

遅延レンダラーを使用する場合、同じことを行うことができますが、通常のバッファーで、または再度、プリパスがある場合は、アルゴリズムを深度に適用できます。それでも、スクリーンスペースアプローチがすべての場合に理想的であるとは限らない可能性があります。実行可能なソリューションは、このエフェクトの予算、シーンの複雑さに大きく依存します。
cifz

これが本当にゲームの中心である可能性がある場合、非常に簡単ですが、負荷がかかる可能性があるため、各頂点の隣接する法線の勾配を計算し(読み込み時のオフライン)、この係数を追加の頂点属性として渡します。
cifz

あなたの助けのために再びcifzを変更します。ええと、私が達成したいのは、これに似たCAD / CAMソリューションを開発することです:youtube.com/watch?v=-qTJZtYUDB4そして、すべての黒い縁、折り目をレンダリングするためにどのように管理したかを本当に知りたいですと尾根。cifz、あなたはグラフィックプログラミングの専門家として、スクリーンスペースのアプローチの1つを使用してこの外観を実現したと思いますか?あるいは、隣接する法線の勾配を計算することによって?これがどうやってできるのか本当に知りたいです。再度、感謝します!
enne87

1
誰かにお金を払う必要はありません。オンラインでいくつかのチュートリアルを読み始め、いくつかの本を購入し、一生懸命勉強してください:)それは最後に非常にやりがいがあります!
cifz

3

他の人もエッジを検出する必要がある場合に備えて: ワイヤーフレームを表示する方法の良い記事がここにあり、この記事はエッジのみを表示する方法を説明しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.