1

画像に指のタッチでぼかしを適用するiOSアプリを開発しています。そのためにOpenGLを使用しています。ガウス ブラーを適用する頂点シェーダーとフラグメント シェーダーを作成しました。画像全体の四角形の座標 (0-1) を頂点シェーダーに渡すと、問題なく画像全体にぼかしが適用されます。今、私が指でやろうとしているのと同じことです。タッチ ポイントをキャプチャし、0 ~ 1 の範囲に変換して、そのポイントをシェーダーに渡します。しかし、それはぼやけているわけではなく、元の画像を乱しています。以下は、@ タッチ移動で実行されるメイン コードです。

-(void)setupVBOsBlur:(CGPoint)start For:(CGPoint)end
{
    static GLfloat*     vertexBuffer = NULL;
    static NSUInteger   vertexMax = 64;
    NSUInteger          vertexCount = 0,
    count,
    i;

    // Convert locations from Points to Pixels
    CGFloat scale = self.contentScaleFactor;
    start.x *= scale;
    start.y *= scale;
    end.x *= scale;
    end.y *= scale;

    // Allocate vertex array buffer
    if(vertexBuffer == NULL)
        vertexBuffer = malloc(vertexMax * 2 * sizeof(GLfloat));

    // Add points to the buffer so there are drawing points every X pixels

    count = MAX(ceilf(sqrtf((end.x - start.x) * (end.x - start.x) + (end.y - start.y) * (end.y - start.y))) , 1);
    for(i = 0; i < count; ++i) {
        if(vertexCount == vertexMax) {
            vertexMax = 2 * vertexMax;
            vertexBuffer = realloc(vertexBuffer, vertexMax * 2 * sizeof(GLfloat));
        }

        vertexBuffer[2 * vertexCount + 0] = start.x + (end.x - start.x) * ((GLfloat)i / (GLfloat)count);
        vertexBuffer[2 * vertexCount + 1] = start.y + (end.y - start.y) * ((GLfloat)i / (GLfloat)count);
        vertexCount += 1;
    }

    GLuint vb;
    glGenBuffers(1, &vb);
    glBindBuffer(GL_ARRAY_BUFFER, vb);
    glBufferData(GL_ARRAY_BUFFER, vertexCount*2*sizeof(GLfloat), vertexBuffer, GL_DYNAMIC_DRAW);

    glEnableVertexAttribArray(ATTRIB_VERTEX);
    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, 0);

    GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, backingWidth, 0, backingHeight, -1, 1);
    GLKMatrix4 modelViewMatrix = GLKMatrix4Identity; // this sample uses a constant identity modelView matrix
    mvpMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);

    [self compileShadersForFingerBlur];

    //set MVP
    glUniformMatrix4fv(mvpMatrixSlot, 1, GL_FALSE, mvpMatrix.m);
    //glUniform2f(myTextCoordSlot, start.x/320.0, ( self.bounds.size.height - start.y)/480.0);
    glUniform2f(myTextCoordSlot, start.x/320.0, ( self.bounds.size.height - start.y)/480.0);
    glUniform1i(amount, 0);

    /*
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, textureHandle);
     glUniform1i(textureUniformSlot, 0);
     */

    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_BLEND);

    glDrawArrays(GL_POINTS, 0, vertexCount);

    [eaglContext presentRenderbuffer:GL_RENDERBUFFER];
}

以下は、私の頂点シェーダーとフラグメント シェーダーです。 頂点シェーダー (水平ブラー):

    /* HBlurVertexShader.glsl */

attribute vec4 Position;
uniform mat4 MVP;
uniform vec2 myTextCoord;

varying vec2 v_texCoord;
varying vec2 v_blurTexCoords[14];

void main()
{
    gl_PointSize = 5.0;
    gl_Position = MVP * Position;

    v_texCoord = myTextCoord;

    v_blurTexCoords[ 0] = v_texCoord + vec2(-0.028, 0.0);
    v_blurTexCoords[ 1] = v_texCoord + vec2(-0.024, 0.0);
    v_blurTexCoords[ 2] = v_texCoord + vec2(-0.020, 0.0);
    v_blurTexCoords[ 3] = v_texCoord + vec2(-0.016, 0.0);
    v_blurTexCoords[ 4] = v_texCoord + vec2(-0.012, 0.0);
    v_blurTexCoords[ 5] = v_texCoord + vec2(-0.008, 0.0);
    v_blurTexCoords[ 6] = v_texCoord + vec2(-0.004, 0.0);
    v_blurTexCoords[ 7] = v_texCoord + vec2( 0.004, 0.0);
    v_blurTexCoords[ 8] = v_texCoord + vec2( 0.008, 0.0);
    v_blurTexCoords[ 9] = v_texCoord + vec2( 0.012, 0.0);
    v_blurTexCoords[10] = v_texCoord + vec2( 0.016, 0.0);
    v_blurTexCoords[11] = v_texCoord + vec2( 0.020, 0.0);
    v_blurTexCoords[12] = v_texCoord + vec2( 0.024, 0.0);
    v_blurTexCoords[13] = v_texCoord + vec2( 0.028, 0.0);

}

頂点シェーダー (垂直ブラー)

        /* VBlurVertexShader.glsl */

varying vec2 v_texCoord;
varying vec2 v_blurTexCoords[14];

void main()
{
    v_blurTexCoords[ 0] = v_texCoord + vec2(0.0, -0.028);
    v_blurTexCoords[ 1] = v_texCoord + vec2(0.0, -0.024);
    v_blurTexCoords[ 2] = v_texCoord + vec2(0.0, -0.020);
    v_blurTexCoords[ 3] = v_texCoord + vec2(0.0, -0.016);
    v_blurTexCoords[ 4] = v_texCoord + vec2(0.0, -0.012);
    v_blurTexCoords[ 5] = v_texCoord + vec2(0.0, -0.008);
    v_blurTexCoords[ 6] = v_texCoord + vec2(0.0, -0.004);
    v_blurTexCoords[ 7] = v_texCoord + vec2(0.0,  0.004);
    v_blurTexCoords[ 8] = v_texCoord + vec2(0.0,  0.008);
    v_blurTexCoords[ 9] = v_texCoord + vec2(0.0,  0.012);
    v_blurTexCoords[10] = v_texCoord + vec2(0.0,  0.016);
    v_blurTexCoords[11] = v_texCoord + vec2(0.0,  0.020);
    v_blurTexCoords[12] = v_texCoord + vec2(0.0,  0.024);
    v_blurTexCoords[13] = v_texCoord + vec2(0.0,  0.028);

}

フラグメント シェーダー:

precision mediump float;

uniform sampler2D texture;
uniform int amount;

varying vec2 v_texCoord;
varying vec2 v_blurTexCoords[14];

void main()
{
    gl_FragColor = vec4(0.0);
    if(amount > 6)
    {

        gl_FragColor += texture2D(texture, v_blurTexCoords[ 0])*0.0044299121055113265;
        gl_FragColor += texture2D(texture, v_blurTexCoords[ 1])*0.00895781211794;
        gl_FragColor += texture2D(texture, v_blurTexCoords[ 2])*0.0215963866053;
        gl_FragColor += texture2D(texture, v_blurTexCoords[ 3])*0.0443683338718;
        gl_FragColor += texture2D(texture, v_blurTexCoords[ 4])*0.0776744219933;
        gl_FragColor += texture2D(texture, v_blurTexCoords[ 5])*0.115876621105;
        gl_FragColor += texture2D(texture, v_blurTexCoords[ 6])*0.147308056121;

        gl_FragColor += texture2D(texture, v_texCoord)*0.159576912161;

        gl_FragColor += texture2D(texture, v_blurTexCoords[ 7])*0.147308056121;
        gl_FragColor += texture2D(texture, v_blurTexCoords[ 8])*0.115876621105;
        gl_FragColor += texture2D(texture, v_blurTexCoords[ 9])*0.0776744219933;
        gl_FragColor += texture2D(texture, v_blurTexCoords[10])*0.0443683338718;
        gl_FragColor += texture2D(texture, v_blurTexCoords[11])*0.0215963866053;
        gl_FragColor += texture2D(texture, v_blurTexCoords[12])*0.00895781211794;
        gl_FragColor += texture2D(texture, v_blurTexCoords[13])*0.0044299121055113265;

    }    
   else 
       gl_FragColor = texture2D(texture, v_texCoord);

}

4

1 に答える 1

0

コメントから続けるには:

あなたが取っているアプローチは、まったく良いものではないようです。コメントから2つのことを修正しても、他の問題が発生します。1つ考えてみると、ユーザーが同じ場所で2本の線をドラッグするとどうなるでしょうか? その場で画像が2回ぼやけますか?可能性はありますが、機能が失われることは保証できます。

あなたがやろうとしていることをもう少し一般的に見るには、ユーザーが画像の部分を選択してぼかすことができるようにしたいのですが、これはまさにあなたがすべきことです。これにより、ピクセルがぼやけているかどうかに関係なく、そのデータのみを保存する別のバッファーが必要になります (ぼかしの強度も保存できます)。したがって、一般的には、テクスチャが添付された FBO (フレーム バッファ オブジェクト) を作成することをお勧めします。次に、既に持っている描画コード (ポイント付き) を移動して、そのバッファーに特定の色を描画します。FBO が変更されるたびに、2 つのテクスチャ (オリジナルと FBO) を使用してメイン バッファ全体を再描画する必要があります。FBO のテクスチャが空である元の描画と、テクスチャがいっぱいであるぼやけた画像があります。この手順では、読み込み時に画像全体をぼかし、3 つのテクスチャ (オリジナル、ぼかし、キャンバス) を使用することもお勧めします。

FBO アプローチは非常に柔軟で、前述のケースでは、ぼかしの場所以外にも使用できます。異なるカラー チャネルを使用して複数の効果とその強度を設定でき、メイン バッファーで使用しているリソースに依存しません。一方で、実装が少し難しくなるかもしれません: FBO サイズは 2 の累乗でなければならず、その特定の部分だけを使用する必要があります (問題ではありません)。そのテクスチャをメイン バッファに適用すると、新しいテクスチャ座標バッファを計算するには (中程度の数学の問題)、ズームや移動を適用すると、非常に難しくなる可能性があります (大きな問題)。あなたのケースから推測すると、これをはるかに簡単に行うことができます。

FBO に色を描画する代わりに、メイン フレーム バッファーにアタッチできる他のバッファーを使用できます。おそらくまったく使用しないため、深度バッファーまたはステンシル バッファーのみに描画します (セットアップはほとんどありません)。最後に、おそらくバッファーでアルファチャンネルを使用することさえありません。

  • 新しい画像が設定されたら、元のぼやけたテクスチャを作成し、すべてのチャネルのバッファをゼロにクリアし、ブレンドを無効にしてカラー マスクを RGB のみに使用し ( glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE))、前と同じようにオリジナルを描画します。
  • 移動したタッチでブレンドを無効にし、アルファチャンネルのみを有効にし、アルファ値のある色を使用し、1.0すでに持っている描画コードを再利用しますが、ぼやけたテクスチャではなく色のみを描画する必要があります
  • 更新時 (タッチが移動した後)、RGB チャネルのみを有効にし、ブレンドを有効にしてglBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA)、フルスクリーンのぼやけたテクスチャを使用および描画します。

すべて完了しました。ここでちょっとしたメモ: ある時点で画像のスナップショットが必要になり、使用glReadPixelsする場合は、アルファ チャネルが混乱していることを理解する必要があり、それらのデータから CGImage を作成するときにそれをスキップする必要があります。

于 2013-07-19T07:52:42.273 に答える