web-dev-qa-db-ja.com

フラグメントの現在の色を取得するにはどうすればよいですか?

私はGLSLのシェーダーに頭を巻き込もうとしていますが、いくつかの有用なリソースとチュートリアルを見つけましたが、基本的で些細なはずの何かのために壁に突き当たります:フラグメントシェーダーはどのようにして色を取得するのですか?現在のフラグメント?

gl_FragColor = whateverと言って最終的な色を設定しましたが、どうやらそれは出力のみの値です。入力の計算を実行できるように、入力の元の色をどのように取得しますか?それは変数のどこかにあるはずですが、誰かがその名前を知っている場合、私がこれまでに出くわしたチュートリアルやドキュメントにそれらを記録していないようで、私を壁に駆り立てています。

31
Mason Wheeler

フラグメントシェーダーは、頂点属性としてgl_Colorおよびgl_SecondaryColorを受け取ります。また、値を書き込むことができるgl_FrontColorgl_FrontSecondaryColorgl_BackColorgl_BackSecondaryColorの4つの変数を取得します。元の色をそのまま通過させたい場合は、次のようにします。

gl_FrontColor = gl_Color;
gl_FrontSecondaryColor = gl_SecondaryColor;
gl_BackColor = gl_Color;
gl_BackSecondaryColor = gl_SecondaryColor;

頂点シェーダーに続くパイプラインの修正された機能は、これらを[0..1]の範囲にクランプし、頂点が前向きか後ろ向きかを判断します。その後、通常どおり、選択した色(表または裏)を補間します。フラグメントシェーダーは、選択され、クランプされ、補間された色をgl_Colorおよびgl_SecondaryColorとして受け取ります。

たとえば、次のように標準の「死の三角形」を描いたとします。

glBegin(GL_TRIANGLES);
    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex3f(-1.0f, 0.0f, -1.0f);
    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex3f(1.0f, 0.0f, -1.0f);
    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex3d(0.0, -1.0, -1.0);
glEnd();

次に、このような頂点シェーダー:

void main(void) {
    gl_Position = ftransform();
    gl_FrontColor = gl_Color;
}

次のようなフラグメントシェーダーを使用します。

void main() {
    gl_FragColor = gl_Color;
}

固定機能パイプラインを使用しているかのように、色を透過します。

14
Jerry Coffin

マルチパスレンダリングを行う場合、つまり、フレームバッファにレンダリングしていて、以前のレンダリングを使用する2番目のレンダーパスにしたい場合は、答えは次のとおりです。

  1. テクスチャへの最初のパスをレンダリングする
  2. このテクスチャを2番目のパスにバインドします
  3. シェーダーでプライベートにレンダリングされたピクセルにアクセスする

3.2のシェーダーコード:

uniform sampler2D mytex; // texture with the previous render pass

layout(pixel_center_integer) in vec4 gl_FragCoord;
// will give the screen position of the current fragment

void main()
{
  // convert fragment position to integers
  ivec2 screenpos = ivec2(gl_FragCoord.xy);
  // look up result from previous render pass in the texture
  vec4 color = texelFetch(mytex, screenpos, 0);
  // now use the value from the previous render pass ...
}

レンダリングされた画像を処理する別の方法は、OpenGLで OpenCL を使用する-> OpenCLの相互運用です。これにより、計算のようなより多くのCPUが可能になります。

12
Danvil

「フラグメントの現在の値」とは、フラグメントシェーダーが実行される前にレンダーターゲットにあったピクセルカラー値の場合、使用できません。

その主な理由は、フラグメントシェーダーの実行時には、まだわかっていない可能性があるためです。フラグメントシェーダーは並列に実行され、(どのハードウェアに依存して)同じピクセルに影響を与える可能性があります。通常、ある種のFIFOから読み取る別のブロックが、それらを後でマージします。このマージは「ブレンディング」と呼ばれ、まだプログラム可能なパイプラインの一部ではありません。これは固定機能ですが、フラグメントシェーダーが生成したものをピクセルの以前のカラー値と組み合わせるには、いくつかの異なる方法があります。

6
Bahbar

次のような現在のピクセル座標でテクスチャをサンプリングする必要があります

vec4 pixel_color = texture2D(tex、gl_TexCoord [0] .xy);

注-texture2DはGLSL 4.00仕様で非推奨になっているので、同様のテクスチャを探してください...フェッチ関数。

また、gl_TexCoord [0] .xyの代わりに独自のピクセル座標を指定する方がよい場合もあります。その場合、頂点シェーダーを次のように記述します。

変化するvec2 texCoord; 
 
 void main(void)
 {
 gl_Position = vec4(gl_Vertex.xy、0.0、1.0); 
 texCoord = 0.5 * gl_Position.xy + vec2(0.5); 
}

また、フラグメントシェーダーでは、gl_TexCoord [0] .xyの代わりにそのtexCoord変数を使用します。

幸運を。

4

フラグメントシェーダーの重要なポイントは、出力カラーを決定することです。どのようにするかは、何をしようとしているのかに依存します。

頂点シェーダーの出力に基づいて補間された色が得られるように設定することもできますが、より一般的なアプローチは、頂点シェーダー補間から渡されたテクスチャ座標を使用してフラグメントシェーダーでテクスチャルックアップを実行することです。 。次に、選択したライティングの計算と、シェーダーが行うことを意図した他のことに従って、テクスチャルックアップの結果を変更し、それをgl_FragColorに書き込みます。

3
Alan

GPUパイプラインは、シェーダーが実行された直後基になるピクセル情報にアクセスできます。マテリアルが透明な場合、パイプラインのブレンド段階ですべてのフラグメントが結合されます。

通常、オブジェクトは、Zバッファリングアルゴで順序付けされていない限り、シーンに追加された順序でブレンドされます。最初に不透明オブジェクトを追加してから、ブレンドする順序で透明オブジェクトを慎重に追加する必要があります。

たとえば、シーンにHUDオーバーレイが必要な場合は、適切な透明なテクスチャで画面のクワッドオブジェクトを作成し、これをシーンに最後に追加するだけです。

透明なオブジェクトにSRCおよびDSTブレンド関数を設定すると、さまざまな方法で以前のブレンドにアクセスできます。

ここで出力カラーのalphaプロパティを使用して、本当に派手なブレンドを行うことができます。これは、GPUパイプラインのシングルパス(図1)で機能するため、フレームバッファー出力(ピクセル)にアクセスする最も効率的な方法です。

enter image description here
図1-シングルパス

multi pass (図2)が本当に必要な場合は、フレームバッファの出力を画面ではなく追加のテクスチャユニットにターゲット設定し、このターゲットテクスチャを次のパスにコピーする必要があります。最終パスで画面をターゲットにします。各パスには、少なくとも2つのコンテキストスイッチが必要です。

追加のコピーとコンテキストの切り替えにより、レンダリングのパフォーマンスが大幅に低下します。マルチパスは本質的にシリアル化されているため、マルチスレッドのGPUパイプラインはここではあまり役に立ちません。

enter image description here
図2-マルチパス

シェーダー言語(Slang/GLSL)は変更される可能性があるため、非推奨を避けるために、パイプラインダイアグラムを使用した口頭による説明に頼りました。

1