5

シェーダー結果のイメージ

基本的にカラーアルファを読み取り、それをピクセル全体のディザリング効果に変換するフラグメントシェーダーがあります。

ただし、すべての mod と if ステートメントを使用すると、プロセッサにかなり負荷がかかります。以下のコードを最適化するための推奨事項はありますか?

varying vec2 the_uv;
varying vec4 color;

void main()
{
    // The pixel color will correspond
    //  to the uv coords of the texture
    //  for the given vertice, retrieved
    //  by the Vertex shader through varying vec2 the_uv

    gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);
    vec4 tex = texture2D(_MainTex, the_uv);
    tex = tex * color ;
    float r = tex.a;

    if ( r > 0.1 ) {
        if ( ( mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y, 4.0) ) > 6.00 ) {
            gl_FragColor = color;
        }
    }

    if ( r > 0.5 ) {
        if ( ( mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y, 4.0) ) > 6.00 ) {
            gl_FragColor = color;
        }
    }

    if ( r > 0.7 ) {
        if ( ( mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0) ) > 6.00 ) {
            gl_FragColor = color;
        }
    }

    if ( r > 0.9 ) {
        if ( ( mod(gl_FragCoord.x + 1.0, 4.001) + mod(gl_FragCoord.y + 1.0, 4.0) ) > 6.00 ) {
            gl_FragColor = color;
        }
    }

    if ( r > 0.3 ) {
        if ( ( mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0) ) > 6.00 ) {
            gl_FragColor = color;
        }
    }
}

フィードバックに基づく解決策は次のとおりです。

        varying vec2 the_uv;
        varying vec4 color;

        void main()
        {
            color = gl_Color;
            gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
            the_uv = gl_MultiTexCoord0.st;
        }
        #endif

        #ifdef FRAGMENT
        uniform sampler2D _MainTex;
        uniform sampler2D _GridTex;
        varying vec2 the_uv;
        varying vec4 color;

        void main()
        {
            if (texture2D(_MainTex, the_uv).a * color.a > texture2D(_GridTex, vec2(gl_FragCoord.x, gl_FragCoord.y)*.25).a) gl_FragColor = color; 
            else gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);   

        }
4

2 に答える 2

6

あなたがやろうとしているのは、ソース アルファに基づいて各ピクセルを 4x4 グリッドで照らすかどうかを選択することです。それを行う最も簡単な方法は、まさにそれを行うことです。

最初に、ピクセル パスに必要な対応するアルファを使用して 4x4 テクスチャを初期化します (ここでは表示しないため、アルファとして 1.0 を選択しました)。

1.0 0.5 1.0 0.1
1.0 1.0 0.9 1.0
1.0 0.3 1.0 0.7
1.0 1.0 1.0 1.0

mod を完全に回避するためにこのテクスチャを繰り返し設定し、線形フィルタリングを回避するために最も近いフィルターを設定します。

次に、そのテクスチャのサンプリングを使用して、ピクセルを照らすかどうかを決定します。

vec4 dither = texture2D(_my4x4, gl_FragCoord / 4.); // 4 is the size of the texture
if (r > dither) { gl_FragColor = color; }

これは、r が 1 にならないことを前提としています。これを回避する簡単な方法があります。たとえば、1.0 以外の 4x4 テクスチャの値を 2 で除算し、if テストの前でフェッチ後にディザを 2 で乗算します。

さらにいくつかの潜在的な最適化:

  • 比較付きのテクスチャ (シャドウ テクスチャ) を使用することで、if テストを完全に回避できます。
  • textureFetch 命令を使用して /4 を回避できます
于 2011-11-07T13:59:20.483 に答える
-1

まず、最初に色が設定されているため、if ステートメントの結果に関係なく、フラグメントの色は同じになります。

第 2 に、else if を使用せずに if ステートメントのみを使用すると、コードは何があっても各計算を実行します。

これを行うためのより良い方法は、次のようにすることです。

 if ( r > 0.9 ) {
    if ( ( mod(gl_FragCoord.x + 1.0, 4.001) + mod(gl_FragCoord.y + 1.0, 4.0) ) > 6.00) {
        gl_FragColor = color;
    }
}
else if ( r > 0.7 ) {
    if ( ( mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0) ) > 6.00 ) {
        gl_FragColor = color;
    }
}
else if ( r > 0.5 ) {
    if ( ( mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y, 4.0) ) > 6.00 ) {
        gl_FragColor = color;
    }
}
else if ( r > 0.3 ) {
    if ( ( mod(gl_FragCoord.x + 2.0, 4.001) + mod(gl_FragCoord.y + 2.0, 4.0) ) > 6.00 ) {
        gl_FragColor = color;
    }
}
else if ( r > 0.1 ) {
    if ( ( mod(gl_FragCoord.x, 4.001) + mod(gl_FragCoord.y, 4.0) ) > 6.00 ) {
        gl_FragColor = color;
    }
}
else{
    gl_FragColor = color;
}

もちろん、これは出力を変更するのに役立ちません (前に述べたように) 色は決して変更されないためです。しかし、これにより、動作が少し速くなるはずです。

考慮すべきもう 1 つのことは、どのケースが最も頻繁に実行されるかということです。r が大きいケースがより一般的であると想定したため、if ステートメントの順序付けを行いました。小さい r がより一般的である場合は、順序を逆にして、r < 0.1、r < 0.3、r < 0.5、r < 0.7、r < 0.9 とすることがより理にかなっています。

ここでの要点は、コードをできるだけ早く終了させることです (つまり、if のいずれかが true を返すようにする)。if の 1 つが true を返すと、残りは無視され、残りのすべての mod 操作を計算する必要がなくなります。

于 2011-11-07T02:38:08.317 に答える