Giter VIP home page Giter VIP logo

bcmeshtransformview's Introduction

BCMeshTransformView

BCMeshTransformView makes it easy to apply a mesh transform to a view hierarchy. It's inspired by a private CALayer property meshTransform and its value class CAMeshTransform. I highly recommend taking look at the blog post on those two as it explains the concepts in depth and hopefully justifies some API choices I made.

Features

  • Transforms regular UIKit view hierarchy
  • Animatable with block-based UIView animations of meshes
  • Supports directional lighting

The demo app contains a few examples of how a mesh transform works and what it can achieve.

Installation

BCMeshTransformView is available via CocoaPods:

pod 'BCMeshTransformView'

Alternatively, you can copy the contents of BCMeshTransformView folder to your project and include BCMeshTransformView.h.

Requirements

  • iOS 7.0
  • ARC
  • GLKit framework

You may optionally include OpenGL ES framework, as this will enable frame capturing.

Using BCMeshTransformView

	// create an instance
    BCMeshTransformView *meshView = [[BCMeshTransformView alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];
    
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 400, 300)];

	// add a view hierarchy to a contentView, subviews of contentView will get mesh-transformed
	[meshView.contentView addSubview:label];
	
	// apply a mesh
	meshView.meshTransform = [self simpleMeshTransform];

    [self.view addSubview:meshView];

Remember to add any subviews you want to get mesh-transformed to contentView, not the view itself. The class will conveniently warn when you call addSubview: method on its instance.

Using BCMeshTransform

A mesh transform consists of two different primitives: vertices and faces.

Vertices

A single vertex is represented by BCMeshVertex struct and consists of from and to fields:

typedef struct BCMeshVertex {
    CGPoint from;
    BCPoint3D to;
} BCMeshVertex;

A vertex defines mapping between the point on the surface of the view and its transformed position in the 3D space.

Both from and to field are defined in unit coordinates, similarly to how anchorPoint property of CALayer works.

Faces

A face is defined by four vertices it's spanned on. Vertices are referenced by their index in the vertices array of a mesh transform.

typedef struct BCMeshFace {
    unsigned int indices[4];
} BCMeshFace;

Depth Normalization

Since vertices are defined in unit coordinates specifies the missing depth scale has to be defined as a function of the other two coordinates. The depthNormalization parameter can be set to one of the following six constants:

extern NSString * const kBCDepthNormalizationNone;
extern NSString * const kBCDepthNormalizationWidth;
extern NSString * const kBCDepthNormalizationHeight;
extern NSString * const kBCDepthNormalizationMin;
extern NSString * const kBCDepthNormalizationMax;
extern NSString * const kBCDepthNormalizationAverage;

Simple Mesh Transform

Here's how the simplest mesh transform actually looks like:

- (BCMeshTransform *)simpleMeshTransform
{
    BCMeshVertex vertices[] = {
        {.from = {0.0, 0.0}, .to= {0.5, 0.0, 0.0}},
        {.from = {1.0, 0.0}, .to= {1.0, 0.0, 0.0}},
        {.from = {1.0, 1.0}, .to= {1.0, 1.0, 0.0}},
        {.from = {0.0, 1.0}, .to= {0.0, 1.0, 0.0}},
    };
    
    BCMeshFace faces[] = {
        {.indices = {0, 1, 2, 3}},
    };
    
    return [BCMeshTransform meshTransformWithVertexCount:4
                                                vertices:vertices
                                               faceCount:1
                                                   faces:faces
                                      depthNormalization:kBCDepthNormalizationNone];
}

This transform will perform a very simple skew transform, and you can tweak it further by modifying positions of to vertices. Check out the mesh transforms in the demo app to learn how to create more complex effects.

Although BCMeshTransform is the default base class, the mutable counterpart, BCMutableMeshTransform, is much more convenient to use.

##Animations

All versions of block-based UIView animations are supported, apart from keyframe and spring animations. Animation always begins from the current state, regardless of presence of UIViewAnimationOptionBeginFromCurrentState flag.

For an animation to occur, the current and final meshes have to be compatible:

  • they must have the same number of vertices
  • they must have the same number of faces
  • the faces at corresponding indexes must point to the same vertices, (their indices arrays must be equal)

##Lighting

BCMeshTransformView supports a simple lighting model in a form of diffuse lighting with pure white light:

@property (nonatomic) BCPoint3D lightDirection;
@property (nonatomic) float diffuseLightFactor;

The lightDirection property defines the direction of a light source in the scene. The vector doesn't have to be normalized and by default it's equal to {0.0, 0.0, 1.0}.

The diffuseLightFactor defines how much does diffuse lighting influence the general lighting of the scene. When it's equal to 1.0 the entire scene uses pure diffuse lighting, when equal to 0.0, the scene is only lit by ambient lighting. Values in between modify the percentage accordingly.

Supplementary Transforms

BCMeshTransformView supports arbitrary matrix transformations in a form of the following property:

@property (nonatomic) CATransform3D supplementaryTransform;

Every mesh vertex in the scene gets transformed with supplementaryTransform. The property can be used to apply perspective transform or any other common operation like rotation, translation and scale.

Convenience Mesh Methods

Creating BCMutableMeshTransform from scratch is tedious so I created a few convenience methods that should make the process much more pleasant:

Identity Mesh Transform

This method creates a mesh transform with given number of rows and columns of faces. Generated mesh is uniform and it doesn't contain any disturbances - applying it to BCMeshView won't have any visual effect, but it's a great start for further modifications:

+ (instancetype)identityMeshTransformWithNumberOfRows:(NSUInteger)rowsOfFaces
                                      numberOfColumns:(NSUInteger)columnsOfFaces;

Generators

Instead of manually creating buffer storage for the default constructor, you can use the following class method:

+ (instancetype)meshTransformWithVertexCount:(NSUInteger)vertexCount
                             vertexGenerator:(BCMeshVertex (^)(NSUInteger vertexIndex))vertexGenerator
                                   faceCount:(NSUInteger)faceCount
                               faceGenerator:(BCMeshFace (^)(NSUInteger faceIndex))faceGenerator;

The blocks will be called vertexCount and faceCount times respectively.

Map

A very convenient map method makes it very easy to modify existing BCMutableMeshTransform. It's extremely useful with dense identity transforms:

- (void)mapVerticesUsingBlock:(BCMeshVertex (^)(BCMeshVertex vertex, NSUInteger vertexIndex))block;

Caveats

  • BCMeshTransformView is stable and works, but it's still in beta. It won't break down unexpectedly, but I haven't seriously battle tested the class, so there still might be some edge cases when something doesn't behave as intended.

  • Mesh generation is computationally heavy and may be slow in Debug mode, especially on older devices. Compiling with optimizations (Release has -Os by default) should provide major improvements.

  • Since rendering is OpenGL based the BCMeshTransformView implicitly clips its content to bounds, regardless of clipsToBounds property state.

  • If semi-transparent faces overlap, only the frontmost one will be rendered. The original CAMeshTransform z-sorts its triangles, however, I'm using a depth buffer to resolve the relative z-order of triangles.

  • All animations on the subviews of contentView are not supported and are removed by default. Although the content of contentView is snapshotted automatically on any layer changes, this process takes over 16 ms so it's not efficient enough to afford snapshotting the layer on every frame.

bcmeshtransformview's People

Contributors

choefele avatar ciechan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bcmeshtransformview's Issues

glReadPixel

Hi, I'm an newbie to gl. I wanna render to an image(not snapshot). I googled and found that glReadPixel meets my requirements. However it has some to do with FrameBuffer and I can't not find any trace of FrameBuffer in BCMeshTransformView.

Nothings showing

Hi,
I wanted to use your library into my swift project. I've created an empty swift project and added your library via cocoa pods.

Here's my ViewController class:

import UIKit
import BCMeshTransformView

class ViewController: UIViewController {
    
    var transformView:BCMeshTransformView!
    var imageView:UIImageView!
    var transform:BCMutableMeshTransform!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        transformView = BCMeshTransformView(frame: self.view.bounds)
        transformView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        
        imageView = UIImageView(image: UIImage(named: "picture.jpg")!)
        imageView.center = CGPoint(x: transformView.contentView.bounds.midX, y: transformView.contentView.bounds.midY)
        
        transformView.contentView.addSubview(imageView)
        
        transformView.diffuseLightFactor = 0.0
        
        transform = BCMutableMeshTransform.identityMeshTransform(withNumberOfRows: 20, numberOfColumns: 20)
        
        transform.mapVertices { (vertex, vertexIndex) -> BCMeshVertex in
            return BCMeshVertex(from: vertex.from, to: vertex.to)
        }
        
        transformView.meshTransform = transform
        
        self.view.addSubview(transformView)
    }

}

When I'm running the app nothing is showing. It's entirely white.

Removing this code:

transform = BCMutableMeshTransform.identityMeshTransform(withNumberOfRows: 20, numberOfColumns: 20)
        
transform.mapVertices { (vertex, vertexIndex) -> BCMeshVertex in
    return BCMeshVertex(from: vertex.from, to: vertex.to)
}
        
transformView.meshTransform = transform

doesn't change anything.

But when in xcode I'm switching to "Show UI hierarchy" I can see an image:

https://imgur.com/a/gLg66

Here's a whole sample project:

http://www116.zippyshare.com/v/IUTXbKJg/file.html

Why I cannot see anything? I tried making an example as simple as possible.

Big image transformation

Hi, I want to apply mesh to big image (ex: 2000x2000), but I got crash:
Failed to bind EAGLDrawable: <CAEAGLLayer: 0x281e7c080> to GL_RENDERBUFFER 1
Failed to make complete framebuffer object 8cd6
What can I do?, tnx

GLKView: disable clipping to bounds

I have a problem with BCMeshTransformView, especially with GLKView inside, which renders this view. In my case MeshTransform vertices can be outside view bounds, but GLKView clips view to it's bounds. I've tried setting clipsToBounds to false in GLKView, BCMeshTransformView and contentView, but it's still clipping the content. Is there any way to fix this? The only thing I can imagine right now is to set frame to the parent frame, but it'll break tons of stuff in my code, because I'm extending BCMeshTransformView, make calculations based on it's frame, using gestures etc.

Add antialiasing

The curtain demo is great but also it demonstrates the need for antialiasing in this framework.

How to reverse ellipseMeshTransform vertex point?

In you example demo, you create a ellipseMeshTransform to map square to circular. So how can I get the square point from circular point?

+ (instancetype)ellipseMeshTransform
{
    BCMutableMeshTransform *transform = [BCMutableMeshTransform identityMeshTransformWithNumberOfRows:30 numberOfColumns:30];
    
    [transform mapVerticesUsingBlock:^BCMeshVertex(BCMeshVertex vertex, NSUInteger vertexIndex) {
        float x = 2.0 * (vertex.from.x - 0.5f);
        float y = 2.0 * (vertex.from.y - 0.5f);
        
        vertex.to.x = 0.5f + 0.5 * x * sqrt(1.0f - 0.5 * y * y);
        vertex.to.y = 0.5f + 0.5 * y * sqrt(1.0f - 0.5 * x * x);
        return vertex;
        
    }];
    
    return transform;
}

Render Transform View Hierarchy Offscreen

Hi,

I'm trying to use BCMeshTransformView to obtain a modified UIImage from an existing UIImage. My code looks like this:

- (UIImage *)addSmile:(UIImage *)inputImage {
    float scale = inputImage.scale;
    CGRect imageRect =  CGRectMake(0.f, 0.f, inputImage.size.width, inputImage.size.height );

    UIImageView *imageView = [[UIImageView alloc] initWithImage:inputImage];

    BCMeshTransformView *transformView = [[BCMeshTransformView alloc] initWithFrame:imageRect];
    transformView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    transformView.diffuseLightFactor = 0.0;
    transformView.meshTransform = [BCMutableMeshTransform buldgeMeshTransformAtPoint:CGPointMake(100, 100) withRadius:120.0 boundsSize:transformView.bounds.size];
    [transformView.contentView addSubview:imageView];

    UIView *containerView = [[UIView alloc] initWithFrame:imageRect];
    [containerView addSubview:transformView];

    UIGraphicsBeginImageContextWithOptions(workingImage.size, YES, scale);
      [containerView.layer renderInContext:UIGraphicsGetCurrentContext()];
      UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return outputImage;
}

When the references to the BCMeshTransformView are removed, outputImage is a copy of inputImage as expected. With the code above, outputImage is just a black rectangle with teh dimensions of inputImage.

Is BCMeshTransformView supposed to work in an offscreen context, or should I use a different approach to obtain a transformed UIImage?

Thanks very much!

increase curtain folding depth

thanks for developing this great framework.

I want to add more depth to curtain folds and change position of top and bottom of curtain to keep on with pan more.

I want to mimic like this video:
https://vine.co/v/Mh5qd0HEpnt

<iframe src="https://vine.co/v/Mh5qd0HEpnt/embed/simple" width="480" height="480" frameborder="0"></iframe><script src="https://platform.vine.co/static/scripts/embed.js"></script>

how can I achieve?

thanks

Circular Reference To BCMeshTransformView

It looks like the following line in BCMeshTransformView::CommonInit causes _display_link to hold a reference to the containing BCMeshTransformView. As a result, the transform view is never deallocated.

_displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkTick:)];

I'm temporarily working around this by exposing a method that allows me to call:

[_display_link invalidate]

when I'm done with the transform view. It is then deallocated when I'm done referencing it.

If there's a better way to handle this, please make a suggestion and I'll code it up and open a pull request.

Thanks again for this very useful project.

Image not Load Properly (BCMeshTransformView)

Hey
I am using this Library last 2 years but recently I am facing some issues like when I try to load the image on BCMeshTransformView it shows me a white screen & sometimes it's working Perfectly, please let me know whats the issue & how can I solve this issue.

IMG_0106
Perfect Image

IMG_0107
Image With Issue.

Frame change while apply transformation

When i'm trying to apply mesh transformation on image, some part get modified but image's frame is also changed with it.
Can you suggest me way that doesn't change frame of image while applying mesh transform.

Simulator Screen Shot - iPhone Xส€ - 2019-09-06 at 10 59 04

Possible to have transform extend beyond BCMeshTransformView's bounds?

I am currently trying to have my mesh transform 'flex' or bend using bezier curves. I am able to have my 'flex inwards' happen, but if I try to flex the view upwards, it is clipped by the bounds of the view. In looking through the code, I see that contentViewWrapperView has it's clipsToBounds set to YES. Setting this value to NO seems to have the mesh transform not be applied. I was hoping for some insight on why this happens, and if there is a way to allow the mesh transform to not be clipped.

I do not believe this matters, but for clarification I am applying this flex using the animations added by this fork : https://github.com/KevinDoughty/BCMeshTransformView

iOS 8 support

Does not appear to compile in xcode 6. Will there be an update?

Did the view refresh every second?

Hello,
When I add the UITableView to the BCMeshTransformView, the UITableView become very slow.
So I want to know if the BCMeshTransformView refresh the view every second.

Take an screenshot

Mesh transform on rotating control as in Apple's Camera app

Thanks for the great project Ciechan

I'm trying to create a rotating control as in at the bottom of Apple's Camera app:

screen shot 2014-09-22 at 09 46 13

However, I'm not able to get the math right. I guess it is similar to buldgeMeshTransformAtPoint although it doesen't buldge out in the center, but caves in towards the edges. Do you know the solution to this?

-Mathias

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.