1

我一直在开发 iOS 应用程序,它在图像上的手指触摸上应用模糊。我为此使用OpenGL。我已经编写了顶点和片段着色器来应用高斯模糊。当我将整个图像矩形坐标(0-1)传递到顶点着色器时,它会将模糊应用于整个图像而没有任何问题。现在,我正在尝试在手指触摸上做同样的事情。我捕获接触点,转换为 0-1 范围并将该点传递给着色器。但它不会模糊,而是会干扰原始图像。以下是在@ touch 移动时执行的主要代码:

-(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

从评论继续:

您采取的方法似乎根本不是一个很好的方法。修复评论中的两件事仍然会产生其他问题。想想 1 如果用户在同一个地方拖动 2 行会发生什么?图像会在那个地方模糊两次吗?它可能会,但我可以向您保证,它将失去其功能。

为了使您尝试做的事情看起来更笼统:您希望用户能够选择要模糊的图像部分,这正是您应该做的。这导致您需要另一个仅存储该数据的缓冲区,无论像素是否模糊(也可以存储模糊的强度)。所以总的来说,我建议创建一个带有附加纹理的 FBO(帧缓冲区对象)。然后移动您已经拥有的绘图代码(带有点)以在该缓冲区上绘制特定颜色。现在,每次 FBO 更改时,您都需要使用 2 个纹理(原始和 FBO 的)重新绘制整个主缓冲区,其中 FBO 的纹理为空,而纹理已满则为模糊图像。此过程还建议您在加载时模糊整个图像并使用 3 个纹理(原始、模糊、画布)。

FBO 方法非常灵活,在提到的情况下,您可以将它用于比模糊位置更多的地方。您可以使用不同的颜色通道获得多种效果及其强度,并且与您在主缓冲区中使用的资源无关。另一方面,它可能会有点难以实现:FBO 大小必须是 2 的幂,并且您只需要使用它的某个部分(不是问题),将其纹理应用于主缓冲区将迫使您计算一个新的纹理坐标缓冲区(中等数学问题),如果你应用一些缩放和移动东西会变得非常困难(大问题)。根据您的情况猜测,您可以更轻松地做到这一点。

您可以使用可以附加到主帧缓冲区的其他缓冲区,而不是为 FBO 绘制一些颜色:仅绘制到深度缓冲区或模板缓冲区(很少设置),因为您可能根本不使用它们。现在对于盛大的最后你可能甚至不使用缓冲区上的 alpha 通道:

  • 当设置新图像时,创建原始和模糊纹理,将所有通道的缓冲区清除为零,禁用混合并仅将颜色遮罩用于 RGB ( glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE)) 并像以前一样绘制原始图像。
  • 触摸移动禁用混合,仅启用 alpha 通道并使用具有 alpha 值的颜色并重1.0用您已有的绘图代码,除非您应该只绘制颜色,而不是模糊的纹理
  • 刷新时(触摸移动后)仅启用 RGB 通道,启用混合和使用glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA)并绘制全屏模糊纹理。

全部完成,这里只是一个小提示:如果您在某个时候想要一个图像快照并且您将使用glReadPixels您需要了解您的 Alpha 通道是一团糟,并且您需要在从这些数据创建 CGImage 时跳过它。

于 2013-07-19T07:52:42.273 回答