2

独自のBrad LarsonGPUImageフレームワークを使用して、GLSL のフラグメント シェーダーにAtkinson ディザリング アルゴリズムを実装しようとしています。(これは不可能なことの 1 つかもしれませんが、私はまだそれを決定するのに十分な知識がないので、とにかく先に進んで実行しています。)

アトキンソン アルゴリズムは、元の Macintosh で見られるように、グレースケール イメージを純粋な白黒にディザリングします。基本的に、ピクセルの周囲のいくつかのピクセルを調査し、それぞれが純粋な黒または白からどれだけ離れているかを判断し、それを使用して累積的な「エラー」を計算する必要があります。そのエラー値に特定のピクセルの元の値を加えた値が、黒か白かを決定します。問題は、私が知る限り、エラー値が (ほとんど?) 常にゼロか、いつの間にかゼロに近いことです。私が考えているのは、私がサンプリングしているテクスチャが私が書き込んでいるテクスチャと同じであるため、エラーが最終的にゼロ (またはそれに近い) になるということです。 m サンプリングはすでに黒または白です。

これは正しいですか、それともサンプリングして書き込んでいるテクスチャは異なりますか? 前者の場合、それを回避する方法はありますか?後者の場合、このコードの他の問題を見つけることができるでしょうか? 困惑しており、適切にデバッグする方法がわからない可能性があります。

varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;

uniform highp vec3 dimensions;

void main()
{
    highp vec2 relevantPixels[6];

    relevantPixels[0] = vec2(textureCoordinate.x, textureCoordinate.y - 2.0);
    relevantPixels[1] = vec2(textureCoordinate.x - 1.0, textureCoordinate.y - 1.0);
    relevantPixels[2] = vec2(textureCoordinate.x, textureCoordinate.y - 1.0);
    relevantPixels[3] = vec2(textureCoordinate.x + 1.0, textureCoordinate.y - 1.0);
    relevantPixels[4] = vec2(textureCoordinate.x - 2.0, textureCoordinate.y);
    relevantPixels[5] = vec2(textureCoordinate.x - 1.0, textureCoordinate.y);

    highp float err = 0.0;

    for (mediump int i = 0; i < 6; i++) {
        highp vec2 relevantPixel = relevantPixels[i];
        // @todo Make sure we're not sampling a pixel out of scope. For now this
        // doesn't seem to be a failure (?!).
        lowp vec4 pointColor = texture2D(inputImageTexture, relevantPixel);
        err += ((pointColor.r - step(.5, pointColor.r)) / 8.0);
    }

    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
    lowp float hue = step(.5, textureColor.r + err);

    gl_FragColor = vec4(hue, hue, hue, 1.0);
}
4

2 に答える 2

2

ここにはいくつかの問題がありますが、最大の問題は、フラグメント シェーダー内で効率的な方法でアトキンソン ディザリングを実行できないことです。この種のディザリングは順次処理であり、その上下のフラグメントの結果に依存します。フラグメントシェーダーは、OpenGL ES の 1 つのフラグメントにのみ書き込むことができます。指定する Python 実装で必要とされるような隣接するフラグメントではありません。

シェーダに適したディザの実装の可能性については、「ピクセル シェーダの Floyd-Steinberg ディザリングの代替案」という質問を参照してください。

また、通常、同じテクスチャに読み書きすることはできませんが、Apple は iOS 6.0 でいくつかの拡張機能を追加し、フレームバッファに書き込み、同じレンダー パスで書き込まれた値から読み取ることができるようにしました。

奇妙なエラー結果が表​​示される理由については、GPUImage フィルター内の座標系が 0.0 ~ 1.0 の範囲に正規化されています。1.0 を追加してテクスチャ座標をオフセットしようとすると、テクスチャの末尾を超えて読み取られます (デフォルトではエッジの値にクランプされます)。これが、隣接するピクセルからのサンプリングを必要とする他のフィルターで、texelWidth と texelHeight の値をユニフォームとして使用しているのを目にする理由です。これらは、画像全体の幅と高さの割合として計算されます。

また、フラグメント シェーダー内でテクスチャ座標の計算を行うことはお勧めしません。これにより、依存するテクスチャの読み取りが発生し、レンダリングが非常に遅くなるからです。可能であれば、それを頂点シェーダーに移動します。

最後に、タイトルの質問に答えるために、通常、テクスチャを読み取っているときに変更することはできませんが、iOS のテクスチャ キャッシュ メカニズムを使用すると、シェーダーがシーンを処理しているときにテクスチャ値を上書きできる場合があります。これにより、通常、ティアリング アーティファクトが悪化します。

于 2013-02-11T22:23:18.387 に答える