Search code examples
iosxcodeimagefiltergpuimage

Seems like a bug in GPUImagePinchDistortionFilter. Can anyone provide a solution?


I use GPUImage library from Brad Larson.

GPUImageBulgeDistortionFilter works fine over the image. But GPUImagePinchDistortion filter renders the effect over the original image in circular cut. This is not smoothly blended with the original image.

Can any one provide a solution to this ?

Pinch Effect appears in a cut circular area instead of smoothly blended with original image

Ok, got it solved.. Following is the final shader to get the smooth blending of pinch effect..

highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
 highp float dist = distance(center, textureCoordinateToUse);
 textureCoordinateToUse = textureCoordinate;

 if (dist < radius)
 {
     textureCoordinateToUse -= center;
     highp float percent = 1.0 + ((0.5 - dist) / 0.5) * scale;
     textureCoordinateToUse = textureCoordinateToUse * percent;
     textureCoordinateToUse += center;

     //modification start
     highp vec2 textureCoordinateDiff = textureCoordinate - textureCoordinateToUse;
     textureCoordinateToUse = textureCoordinateToUse + textureCoordinateDiff*(dist/radius);
     //modification end

     gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );
 }
 else
 {
     gl_FragColor = texture2D(inputImageTexture, textureCoordinate );
 }

Solution

  • The pinch distortion filter uses the following fragment shader:

     varying highp vec2 textureCoordinate;
    
     uniform sampler2D inputImageTexture;
    
     uniform highp float aspectRatio;
     uniform highp vec2 center;
     uniform highp float radius;
     uniform highp float scale;
    
     void main()
     {
         highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));
         highp float dist = distance(center, textureCoordinateToUse);
         textureCoordinateToUse = textureCoordinate;
    
         if (dist < radius)
         {
             textureCoordinateToUse -= center;
             highp float percent = 1.0 + ((0.5 - dist) / 0.5) * scale;
             textureCoordinateToUse = textureCoordinateToUse * percent;
             textureCoordinateToUse += center;
    
             gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );
         }
         else
         {
             gl_FragColor = texture2D(inputImageTexture, textureCoordinate );
         }
     }
    

    As you can see from that, there is a sharp demarkation between when the distance from the center point of the effect to the current pixel is less than the radius of the effect to when it is greater than that. This leads to the edge between the distorted region and the plain image beyond that.

    If you want this to have more of a gradual effect, you could modify the above with a smoothstep() function to more gradually ease the boundary between the distorted and normal regions. If you do so, I'd be glad to accept a pull request to that effect.