CATransform3DRotate after CATransform3DTranslate

2.4k views Asked by At

I'm trying to make a folding facebook menu like the one you can see here: http://www.mobileinc.co.uk/2012/05/folding-iphone-sidebar-menu/

For now, I'm juste working on the "folding" part. I have 2 layers: - left layer has an anchor point at {1,.5} - right layer has an anchor point at {0,.5}

I can make them fold in the middle of my main view without problem like that: CGFloat width = self.view.frame.size.width; CGFloat destinationWidth = slider.value * width;

CGFloat hypothenuse = self.view.frame.size.width/2.0f;
CGFloat adjacent = destinationWidth / 2.0f;
CGFloat opposite = sqrtf(powf(hypothenuse, 2)-powf(adjacent, 2));

CGFloat marginLeft = (width - destinationWidth) / 2;

CGFloat angle = asinf(opposite/hypothenuse);

CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0f / -4000.0f;

rightSide.layer.transform = CATransform3DRotate(CATransform3DTranslate(transform,0,0,-opposite),-angle, 0, 1, 0);
leftSide.layer.transform = CATransform3DRotate(CATransform3DTranslate(transform,0,0,-opposite),angle, 0, 1, 0);

This works perfectly. The problem comes when I try to translate my layers on the x axis like this: CATransform3DTranslate(transform,-marginLeft,0,-opposite)

Layers still fold with the good z translation but it ends with an awkward angle as if the whole view had been rotated.

This is obviously linked to the perspective (when I don't set m34, it "works") but I can't figure how to compensate it...

Thank you in advance!

Cheers,

TeuBeu2

1

There are 1 answers

0
dave On

You're composing 4 transforms, in this order:

  1. Rotate
  2. Translate Z
  3. Translate X
  4. Project

The problem is that you want to do the translate X after the projection, not before. As it is, you're pulling the fold back towards the center a bit with the projection. Try this:

CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0f / -4000.0f;

transform = CATransform3DConcat(transform, CATransform3DMakeTranslation(-marginLeft,0,0));

rightSide.layer.transform = ...

Disclaimer: I haven't actually tested this