iosobjective-copengl-eswarp

Warp \ bend effect on a UIView?


I'm trying to get a similar effect to the one described in the pictures. The white area on the left isn't on the original photo, it pushes the pixels away. I've tried using Core Image (which offered a few close effects to this) but it was too slow for my needs. I need the effect to be snappy so I can make it responsive to touch.

Is there a close effect \ animation in the iOS sdk that does something similar to this with a UIVIew? ( I couldn't find anything close) If not, can someone offer how to attack this using OpenGL? (code examples are more than welcome)

(This effect will take an important roll in an open source class I'm writing so I'd prefer not to use a 3rd party class such as GPUImage if a simpler solution is available (I'm targeting this class to be dependencies free))

enter image description hereenter image description hereenter image description here


Solution

  • Sha,

    What I did was to lay out a rectangular grid of points in my OpenGL coordinates. (I used a 50x50 grid). I then define one or more control points in that same coordinate space. I have a general pinch-stretch algorithm that I wrote. It takes a control point, a radius, and a signed integer for the amount to attract/repel grid points, and applies it to the coordinates of my grid. For a pinch, it pulls the grid points closer to the control point, and for a stretch, it pushes the control points away. The change is greatest at the control point and goes down as the distance from the control point increases up to the radius value.

    Once I've changed the coordinates of my mesh, I then define a set of triangle strips that draws the entire (warped) rectangular area of my image. I can render my entire texture onto the warped mesh with one OpenGL drawing call. OpenGL takes care of stretching the image pixels to fit the distorted triangles in my mesh of control points. Here is a sample before/after image that uses several control points to create a fat-face look. It shows the mesh grid so you can see what it's doing. It's my ugly mug, so apologies in advance:

    enter image description here

    And the stretched image:

    enter image description here

    In my case I wanted the control points along the perimeter of the image to stay in place and only the interior of the image to be distorted, so I added extra code logic to lock the perimeter control points into place. That's why the frame of the image is not pushed in like in your image. That required extra code however.

    The code ends up using the distance formula to figure out how far each grid-point is from a control point, and then trig to figure out the angle, multiplication to change the distance, and then more trig to calculate the new location for each grid-point. Since I'm only transforming a 50x50 grid of control points, though, its fast enough to keep up.

    Our app, Face Dancer, is free on the app store. (Download it at this link: Face Dancer in the App store You might want to download it and try it out. (It includes a number of free morphs, and then offers additional morphs as in-app purchases) There is also a paid "Plus" version that has all the morphs included.

    When you're running Face Dancer if you two finger double-tap on the image, it displays the grid of control points it's using to create the morph so you can see what it's doing.

    There is an OpenGL sample app called GLCameraRipple that is included with Xcode and linked from the documentation. I would suggest taking a look at that as a starting point. It takes a video feed from the camera and draws it to the screen. If you touch the screen it distorts the image as if the screen were a pool of water and your finger was causing ripples in it. It uses a mesh warp technique like what I described.

    Unfortunately I don't think the app uses GLKit, which is a much easier way to use OpenGL ES 2.0. GLKit offers a number of features that make it much easier to use, including GLKViews and GLKViewControllers.