OpenGLでマルチパスシェーダーはどのように機能しますか?


12

Direct3Dでは、プログラム内でパスを文字通り定義できるため、マルチパスシェーダーの使用は簡単です。OpenGLでは、シェーダープログラムに必要な数の頂点シェーダー、ジオメトリシェーダー、およびフラグメントシェーダーを与えることができるため、もう少し複雑に思えます。

マルチパスシェーダーの一般的な例は、トゥーンシェーダーです。1つのパスは実際のセルシェーディング効果を実行し、もう1つのパスはアウトラインを作成します。2つの頂点シェーダー「cel.vert」と「outline.vert」、および2つのフラグメントシェーダー「cel.frag」と「outline.frag」(HLSLで行う方法と同様)がある場合、どうすればよいですかそれらを組み合わせてフルトゥーンシェーダーを作成しますか?

マルチパスGLSLシェーダーの背後にある理論を知りたいだけなので、これにジオメトリシェーダーを使用できると言ってほしくありません;)


「Direct3Dでは、プログラム内で文字通りパスを定義できるため、マルチパスシェーダーの使用は簡単です。」いいえ、できません。FXファイルでパスを定義できますが、HLSLシェーダーとは異なります。
ニコルボーラス

回答:


11

マルチパスの背後には「理論」はありません。「マルチパスシェーダー」はありません。マルチパスは非常に簡単です。1つのプログラムでオブジェクトを描画します。次に、別のプログラムでオブジェクトを描画します。

FXファイルなどのD3DXを使用して、これらの余分なパスを隠すことができます。しかし、彼らはまだそのように動作します。OpenGLには隠れ場所がありません。


1

セルシェーダーでオブジェクトをレンダリングしてから、アウトラインシェーダーでオブジェクトを再レンダリングします。


1
だから私は2つの異なるシェーダープログラムを作成する必要がありますか?なぜ、必要な数の頂点/ジオメトリ/フラグメントシェーダーをシェーダープログラムに提供できるのですか?1つのプログラムでそれを行う方法が必要です。
jmegaffin

1
複数のバーテックス(など)シェーダーを与えているわけではありません。メイン関数は1つしかないため、複数のエントリポイントはありません。複数のファイルをリンクしてプログラムを作成できるという点で、Cプログラムと非常によく似ています。これらのファイルを異なるプログラム間で共有できるため、コードを複製する必要はありませんが、各ファイルは必ずしもそれ自体がプログラムであるとは限りません。
チューイーガムボール

1
それは、1つのシェーダーペア(頂点+フラグメント)で一度レンダリングしてから、別のペアで再度レンダリングする(または同じ頂点シェーダー+別のフラグメントシェーダーを使用する)方法です。バッファにレンダリングし、(まだ)別のシェーダを使用して最終結果に「ブレンド」する場合があります。
ヴァルモンド

1

OpenGL 4.0には、均一なサブルーチンがあります。これらにより、実行時に非常に少ないオーバーヘッドでスワップアウトできる関数を定義できます。したがって、パスごとに1つの関数を作成できます。また、シェーダータイプごとに1つの関数。

こちらにチュートリアルがあります

古いOpenGLバージョンの場合、最善の策は、さまざまなシェーダーを用意し、それらを交換することです。それ以外の場合は、0.0または1.0のいずれかであるユニフォームで乗算した値を加算して、オンまたはオフにします。そうでない場合、条件付きifステートメントを使用できますが、OpenGLは実行/パスごとにすべての可能な結果を​​実行するため、それらが重すぎないようにしてください。


0

GLSLについて多くのことを知っている人もいるので、彼らが記録を正してくれることを願っていますが、私が見たことに基づいて、フラグメントシェーダーで次のようなことができるはずです(擬似コード、実際のGLSLは、それをよく知っている人に任せます):

out vec4 fragment_color
vec4 final_color
final_color = flat_color
If this fragment is in shadow
    final_color = shadow_color
If this fragment is an edge
    final_color = edge_color
If this fragment is a highlight
    final_color = highlight_color
fragment_color = final_color

ifこのようにsを使用すると、複数のパスのようなものが得られます。それは理にかなっていますか?

編集:また、SOに関するこの質問が誤解を払拭するのに役立つことを願っています。


2
GLSLは、有効になっていない場合でも、すべてのパスでifブランチ内のすべてのステートメントを実行することに注意することが重要です。どうやらすべてを計算し、すべての色を加算するだけで、値を1.0または0.0で乗算して有効または無効にする方が高速です。
デビッドC.ビショップ

1
@ DavidC.Bishop:それは真実ではありません。少なくとも、真実であるとは限りませ。コンパイラは、実際のブランチが高速か、「すべてを計算して後でソートする」アプローチが高速かを決定します。
ニコルボーラス

1
余談ですが、@ DavidC.Bishopが参照する動作は、シェーダーとGPUに固有のものではありません。テストされた値がまだ利用可能でない場合、通常のプログラムを実行する最新のCPUは、少なくとも1つのブランチを投機的に実行します。間違っていることが判明した場合、ロールバックしてやり直します。これにより、平均して大幅に高速化されます。
ipeet
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.