Warp \\ bend effect on a UIView?

2019-01-16 12:07发布

问题:

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

回答1:

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:

And the stretched image:

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.



回答2:

There's a new great open source class that answers my question completely with a magnificent example. You can find it here.



回答3:

Another thing you might look at is the Core Image hole distortion filter (CIHoleDistortion) that was added in iOS 6. It creates an effect rather like what you're looking for. Here is a sample image generated from a test program I wrote that gets pretty close.

However, you'll notice that Apple's filter causes the image to "pull away" from the edges of the frame. I think this is a bug, but good luck getting Apple to fix it:



回答4:

What you show looks like a mesh warp. That would be straightforward using OpenGL, but "straightforward OpenGL" is like straightforward rocket science.

I wrote an iOS app for my company called Face Dancerthat's able to do 60 fps mesh warp animations of video from the built-in camera using OpenGL, but it was a lot of work. (It does funhouse mirror type changes to faces - think "fat booth" live, plus lots of other effects.)



回答5:

I would investigate two approaches: First, Core Image Filters, which include a number of distortion filters like you seem to need. The main problem is that many of these aren't available in iOS (but are on OSX...).

Second, the GPUImage library has a number of distortion filters that you can use too. Here's a Q that discusses how they might be used:

How can you apply distortions to a UIImage using OpenGL ES?