19

GLSL にラジアル ブラー シェーダーがあります。これは、テクスチャを取得し、それにラジアル ブラーを適用して、結果を画面にレンダリングします。これまでのところ、これは非常にうまく機能しています。

問題は、シーンの最初のテクスチャに放射状のぼかしが適用されることです。しかし、私が実際にやりたいのは、このぼかしをシーン全体に適用することです。

この機能を実現する最善の方法は何ですか? シェーダーのみでこれを行うことはできますか?それとも、最初に (OpenGL で) シーンをテクスチャにレンダリングしてから、このテクスチャをシェーダーに渡してさらに処理する必要がありますか?

// Vertex shader

varying vec2 uv;

void main(void)
{
    gl_Position = vec4( gl_Vertex.xy, 0.0, 1.0 );
    gl_Position = sign( gl_Position );
    uv = (vec2( gl_Position.x, - gl_Position.y ) + vec2(1.0) ) / vec2(2.0);
}


// Fragment shader

uniform sampler2D tex;
varying vec2 uv;
const float sampleDist = 1.0;
const float sampleStrength = 2.2; 

void main(void)
{
    float samples[10];
    samples[0] = -0.08;
    samples[1] = -0.05;
    samples[2] = -0.03;
    samples[3] = -0.02;
    samples[4] = -0.01;
    samples[5] =  0.01;
    samples[6] =  0.02;
    samples[7] =  0.03;
    samples[8] =  0.05;
    samples[9] =  0.08;

    vec2 dir = 0.5 - uv; 
    float dist = sqrt(dir.x*dir.x + dir.y*dir.y); 
    dir = dir/dist; 

    vec4 color = texture2D(tex,uv); 
    vec4 sum = color;

    for (int i = 0; i < 10; i++)
        sum += texture2D( tex, uv + dir * samples[i] * sampleDist );

    sum *= 1.0/11.0;
    float t = dist * sampleStrength;
    t = clamp( t ,0.0,1.0);

    gl_FragColor = mix( color, sum, t );
}

代替テキスト

4

1 に答える 1

17

これは、レンダリングにシーン全体に効果 (ここでは放射状のぼかし) を適用するため、基本的に「後処理」と呼ばれます。

そうです、その通りです。後処理の良い方法は次のとおりです。

  • 画面サイズの NPOT テクスチャを作成する ( GL_TEXTURE_RECTANGLE)、
  • FBO を作成し、それにテクスチャをアタッチします
  • この FBO をアクティブに設定し、シーンをレンダリングします
  • FBO を無効にし、FBO のテクスチャでフルスクリーン クワッドを描画します。

「理由」については、理由は簡単です。シーンが並行してレンダリングされます (フラグメント シェーダーは、多くのピクセルに対して個別に実行されます)。ピクセル (x,y) に対して放射状のぼかしを行うには、まず周囲のピクセルのぼかし前のピクセル値を知る必要があります。そして、それらはその間にレンダリングされるだけなので、最初のパスでは利用できません。

したがって、シーン全体がレンダリングされ、フラグメント (x,y) のフラグメント シェーダーがシーンから任意のピクセルを読み取れるようになった後にのみ、放射状のぼかしを適用する必要があります。これが、そのために 2 つのレンダリング ステージが必要な理由です。

于 2011-01-02T16:38:11.253 に答える