BLOG

Transform Layers

In the previous post, I showed you how to use the replicator layer class (CAReplicatorLayer). The main problem with layers is that if you want to render them in 3D is quite hard. You need to apply a 3D transformation to each sublayer, fight against the anchor point to get the right transformations. Then, you have to apply a 3D transformation to the root layer and change the m34 value of the 3D transformation matrix to simulate the prospective. If you don’t do that, everything looks flat. Transform layers are the solution to this. So, this time I want to show you another interesting core animation layer that can be used to create a 3D layer hierarchy, rather than the flattened hierarchy rendering model used by other CALayer classes.

To better understand what I am talking about, this video shows what you can do with a CATransformLayer. I created this small animation to let you understand how it works:

This animated cube is obtained using the CATransformLayer class. Here the source code, I used to build the small cube:

- (CATransformLayer *)generateTransformLayerTree {
    // Create a transform layer
    CATransformLayer *transformLayer = [CATransformLayer layer];
    transformLayer.bounds = BOUNDS;

    CGPoint centralPoint = 
            CGPointMake(transformLayer.bounds.size.width/2.0, 
                transformLayer.bounds.size.height/2.0);

    // This is the first side of the cube
    CALayer *layer1 = [CALayer layer];
    layer1.bounds = BOUNDS;
    layer1.position = centralPoint;
    layer1.borderColor = [[UIColor lightGrayColor] CGColor];
    layer1.borderWidth = BORDERWIDTH;
    layer1.backgroundColor = [[UIColor colorWithRed:1.0 green:0. blue:0. alpha:0.7] CGColor];

    // This is the second side. 
    // Notice that a 3D transform is applied to it
    // to rotate it of 90° along the y axis and translate it
    CALayer *layer2 = [CALayer layer];
    layer2.bounds = BOUNDS;
    layer2.position = centralPoint;
    layer2.borderColor = [[UIColor lightGrayColor] CGColor];
    layer2.borderWidth = BORDERWIDTH;
    layer2.backgroundColor = [[UIColor colorWithRed:0.0 green:1.0 blue:0.0 alpha:0.7] CGColor];
    CGFloat degrees = 90.0;
    CGFloat radians = DegreesToRadians(degrees);
    CATransform3D t1 = CATransform3DIdentity;
    t1 = CATransform3DRotate(t1, radians, 0.0f, 1.0f, 0.0f);
    t1 = CATransform3DTranslate(t1, 0, 0, SQUARE_SIZE/2.0f);
    t1 = CATransform3DTranslate(t1, SQUARE_SIZE/2.0f, 0.0f, 0.0f);
    layer2.transform = t1;

    // This is the 3rd side of the cube. This goes behind the first square.
    CALayer *layer3 = [CALayer layer];
    layer3.bounds = BOUNDS;
    layer3.position = centralPoint;
    layer3.borderColor = [[UIColor lightGrayColor] CGColor];
    layer3.borderWidth = BORDERWIDTH;
    layer3.backgroundColor = [[UIColor colorWithRed:0.0f green:0.0f blue:1.0f alpha:0.7f] CGColor];
    t1 = CATransform3DIdentity;
    t1 = CATransform3DTranslate(t1, 0.0f, 0.0f, -SQUARE_SIZE);
    layer3.transform = t1;

    // Finally, the last side.
    CALayer *layer4 = [CALayer layer];
    layer4.bounds = BOUNDS;
    layer4.position = centralPoint;
    layer4.borderColor = [[UIColor lightGrayColor] CGColor];
    layer4.borderWidth = BORDERWIDTH;
    layer4.backgroundColor = [[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.7] CGColor];
    t1 = CATransform3DIdentity;
    t1 = CATransform3DRotate(t1, radians, 0.0, 1.0, 0.0);
    t1 = CATransform3DTranslate(t1, 0, 0, -SQUARE_SIZE/2.0f);
    t1 = CATransform3DTranslate(t1, SQUARE_SIZE/2.0f, 0.0f, 0.0f);
    layer4.transform = t1;

    [transformLayer addSublayer:layer1];
    [transformLayer addSublayer:layer2];
    [transformLayer addSublayer:layer3];
    [transformLayer addSublayer:layer4];

    // Place the anchorPoint in the center of the cube
    transformLayer.anchorPointZ = -SQUARE_SIZE/2.0;
    return transformLayer;
}

You need some defines for this source code. Here, they are:

#define SQUARE_SIZE 300.0f
#define BOUNDS  CGRectMake(0.0f, 0.0f, SQUARE_SIZE, SQUARE_SIZE)
#define BORDERWIDTH     1.0f

So, now let’s try to understand what I did. First of all, I created an open face cube: it has only four sides. I leave you as exercise to add the top and bottom side. The first side I creates is a red square (layer1). I placed it in the center of the transform layer. Nothing new here, right? The third side (layer3) goes behind the first side at the distance of SQUARE_SIZE points. So, I created again a rectangle and applied to it a translation of -SQUARE_SIZE points. Now, the left (layer4) and right (layer2) sides are similar. They are first rotated 90° with respect to the y axis and then translated to left and to the right, respectively. Finally, they are translated to the back (inside the screen) half SQUARE_SIZE. Finally, I added the four layers to the transform layer and to make the transformations work correctly I moved the anchorPointZ to the center of the cube. In this way, when you apply any animation to the transform layer everything is transformed correctly.

Now, what happens if we combine the replicator layer from the previous post and this transform layer. Well, here it is an example:

If you liked this post, check here our iOS training classes. You can learn more about these and other really advanced topic topics.

Keep coding,

Geppy

5 Notes/ Hide

  1. bgnori-technology reblogged this from do-nothing
  2. do-nothing reblogged this from invasivecode
  3. invasivecode posted this

Recent comments

Blog comments powered by Disqus
Designed and developed in California © 2008-2014 iNVASIVECODE INC