Question

I use this code inside a subclass of CALayer which instances are sublayers of the root CALayer.

-(void)setSelected:(bool)s {
    selected=s;
    if (s)
    {
        CATransform3D  rot = CATransform3DMakeRotation(M_PI, 0, 1, 0);
        rot.m34=-1.0 / 200;
        [self setTransform:rot];

    }
    else
    {
            CATransform3D  rot = CATransform3DMakeRotation(0, 0, 1, 0);
        rot.m34=-1.0 / 200;
        [self setTransform:rot];
    }
}

When the selected property to set to TRUE, here is what happens: the rotation is done until the angle is equal to M_PI/2, then the layer disappears because it is orthogonal. The end of the animation is wrong: the edge that appeared to grow in the first part of the animation (for example on the left side), ends the animation on the left side instead of the right side. However the content is flipped.

I think this has something to do with the interpolation between the two rotation matrices but I can't understand exactly what is happening.

Details: The animation looks like it is doing this:

  1. increment rotation around Y axis by +Pi/2
  2. content flipping
  3. increment rotation around Y axis by -Pi/2, as if it bounced of the (yz)plane

The flipped content is what I am trying to achieve.

Here are the frames of the animation I get. As you can see, the small side of the trapezoid is always of the left; it should be on the right on at the end of the animation (top right frame). A layer rotating around the Y-axis

Was it helpful?

Solution

The math of your transform is not correct. You should apply the perspective transform after the rotation transform, which means concatenating both transforms. Changing the m34 coefficient of your rotation transform is not equivalent.

You should replace your code by the following :

-(void)setSelected:(bool)s {
    selected=s;
    CATransform3D perpectiveTransform = CATransform3DIdentity;
    perpectiveTransform.m34 =-1.0 / 200;

    if (s)
    {

        CATransform3D  rot = CATransform3DMakeRotation(M_PI, 0, 1, 0);
        [self setTransform:CATransform3DConcat(rot, perpectiveTransform)];

    }
    else
    {
        CATransform3D  rot = CATransform3DMakeRotation(0, 0, 1, 0);
        [self setTransform:CATransform3DConcat(rot, perpectiveTransform)];
    }
}

By the way, an often more convenient method to apply perspective transforms is to use the superlayer's sublayerTransform property, thus applying it to every sublayer (if this is needed).

This would yield something like :

self.superlayer.sublayerTransform = perspectiveTransform;  //do this in your setup
....
self.transform = rot;

for an identical looking result.

OTHER TIPS

If anyone just wants to flip an image's or view's direction horizontally

yourView.layer.transform = CATransform3DMakeScale(-1, 1, 1);

or

yourView.layer.affineTransform =  CGAffineTransformMakeScale(-1, 1);

Imagine that your layer is a piece of flat translucent plastic with an image projected onto it, so it shines through both sides. At a rotation of pi/2, it is edge-on, and so it disappears. When your rotation gets greater than pi/2 but less than pi, the back of the flat sheet of plastic is exposed. Because it's translucent, you see the back side of the image, but because you're seeing it from the back, it's mirror-imaged. When the angle gets to pi, the sheet is flipped a full 180 degrees on the y axis. It's upside-down, and you can see the image from the back, so it's backwards.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top