amorbytes amorbytes - 5 months ago 63
Swift Question

Change perspective angle from right to left, in CATransformLayer iOS using CATransform3D

I am trying to draw one 3d block!

Using 2 layers and it is looking good in 3d for right side. see the attached image.

enter image description here

When I am trying to reuse same code for minor modification for left side! it's looking weird. See the attached image bellow,

enter image description here

I feel we can improve if we can change perspective angle, but don't know how to achieve that.

using

transform.m34
for perspective. any help would be greatly appreciated.

Here is source code I am using.

// left Bar
/*{
CGFloat aViewWidth = 1000;

CAGradientLayer *blueLayer = [CAGradientLayer layer];
blueLayer.anchorPoint = P(0,0.5);

blueLayer.colors = @[
(id)aBarColor.CGColor,
(id)[UIColor blackColor].CGColor
];
blueLayer.startPoint = CGPointMake(0.0, 0.5);
blueLayer.endPoint = CGPointMake(1.5, 0.5);

blueLayer.frame = CGRectMake(125, 0, aViewWidth, 250);
blueLayer.transform = CATransform3DRotate(CATransform3DIdentity, M_PI_2, 0.0f, 1.0f, 0.0f);


[baseLayer addSublayer:blueLayer];

CAGradientLayer *redLayer = [CAGradientLayer layer];

redLayer.colors = @[
(id)[UIColor whiteColor].CGColor,
(id)aBarColor.CGColor
];
redLayer.startPoint = CGPointMake(-10.0, 0.5);
redLayer.endPoint = CGPointMake(1.0, 0.5);
redLayer.anchorPoint = P(0.5,0.5);

redLayer.frame = CGRectMake(0, 0, 125, 250);

[baseLayer addSublayer:redLayer];

CGFloat perspective = -1000; //This relates to the m34 perspective matrix.

CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / perspective;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, degreesToRadians(-10.0) , 0.0f, 1.0f, 0.0f);

baseLayer.sublayerTransform = rotationAndPerspectiveTransform;

[self.view.layer addSublayer:baseLayer];

return;

CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath: @"sublayerTransform"];
transformAnimation.fillMode = kCAFillModeForwards;
transformAnimation.removedOnCompletion = NO;
{

CGFloat w0 = 0;
CGFloat w1 = aViewWidth;

w0 = w0 * sin(degreesToRadians(10)) - perspective * cos(degreesToRadians(10));
w1 = w1 * sin(degreesToRadians(10)) - perspective * cos(degreesToRadians(10));

CGFloat newWidth = w1 - w0;
newWidth = newWidth * 1.2;

CATransform3D newTransform = CATransform3DIdentity;
newTransform.m34 = 1.0 / perspective;
newTransform = CATransform3DRotate(newTransform, degreesToRadians(-10) , 0.0f, 1.0f, 0.0f);
newTransform = CATransform3DScale(newTransform, 1.0f, 1.0f, 1.0f);
newTransform = CATransform3DTranslate(newTransform, newWidth, 0.0f, 0.0f);

transformAnimation.toValue = [NSValue valueWithCATransform3D:newTransform];
transformAnimation.duration = 10.0;
}
[baseLayer addAnimation:transformAnimation forKey:@"transform"];
}*/

// Right Bar
{
CGFloat aViewWidth = 1000;

CAGradientLayer *redLayer = [CAGradientLayer layer];

redLayer.colors = @[
(id)aBarColor.CGColor,
(id)[UIColor blackColor].CGColor
];
redLayer.startPoint = CGPointMake(0.0, 0.5);
redLayer.endPoint = CGPointMake(1.5, 0.5);

redLayer.frame = CGRectMake(0, 0, aViewWidth, 250);
redLayer.position = CGPointMake(0,0);
redLayer.anchorPoint = CGPointMake(0, 0.5); // right
redLayer.transform = CATransform3DRotate(CATransform3DIdentity, M_PI_2,0.0f, 1.0f, 0.0f);

[baseLayer addSublayer:redLayer];

CAGradientLayer *blueLayer = [CAGradientLayer layer];

blueLayer.colors = @[
(id)[UIColor whiteColor].CGColor,
(id)aBarColor.CGColor
];
blueLayer.startPoint = CGPointMake(-10.0, 0.5);
blueLayer.endPoint = CGPointMake(1.0, 0.5);

blueLayer.frame = CGRectMake(0, 0, 125, 250);
blueLayer.anchorPoint = CGPointMake(0, 0.5); // right
blueLayer.position = CGPointMake(0,0);

[baseLayer addSublayer:blueLayer];

CGFloat perspective = -1 * aViewWidth; //This relates to the m34 perspective matrix.

CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / perspective;
rotationAndPerspectiveTransform = CATransform3DScale(rotationAndPerspectiveTransform, 0.1f, 0.1f, 0.1f);

baseLayer.sublayerTransform = rotationAndPerspectiveTransform;

[self.view.layer addSublayer:baseLayer];

CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath: @"sublayerTransform"];
transformAnimation.fillMode = kCAFillModeForwards;
transformAnimation.removedOnCompletion = NO;
{

CGFloat w0 = 0;
CGFloat w1 = aViewWidth;

w0 = w0 * sin(degreesToRadians(10)) - perspective * cos(degreesToRadians(10));
w1 = w1 * sin(degreesToRadians(10)) - perspective * cos(degreesToRadians(10));

CGFloat newWidth = w1 - w0;
newWidth = newWidth * 1.225;

CATransform3D newTransform = CATransform3DIdentity;
newTransform.m34 = 1.0 / perspective;
newTransform = CATransform3DRotate(newTransform, degreesToRadians(10) , 0.0f, 1.0f, 0.0f);
newTransform = CATransform3DScale(newTransform, 1.0f, 1.0f, 1.0f);
newTransform = CATransform3DTranslate(newTransform, newWidth, 0.0f, 0.0f);

transformAnimation.toValue = [NSValue valueWithCATransform3D:newTransform];
transformAnimation.duration = 10.0;
}
[baseLayer addAnimation:transformAnimation forKey:@"transform"];
}

Answer

here is the working code :

// left Bar
{
 CGFloat aViewWidth = 1000;

 CAGradientLayer *blueLayer = [CAGradientLayer layer];
 blueLayer.anchorPoint = P(0,0.5);

 blueLayer.colors = @[
 (id)aBarColor.CGColor,
 (id)[UIColor blackColor].CGColor
 ];
 blueLayer.startPoint = CGPointMake(0.0, 0.5);
 blueLayer.endPoint = CGPointMake(1.5, 0.5);

 blueLayer.frame = CGRectMake(125, 0, aViewWidth, 250);
 blueLayer.transform = CATransform3DRotate(CATransform3DIdentity, M_PI_2, 0.0f, 1.0f, 0.0f);


 [baseLayer addSublayer:blueLayer];

 CAGradientLayer *redLayer = [CAGradientLayer layer];

 redLayer.colors = @[
 (id)[UIColor whiteColor].CGColor,
 (id)aBarColor.CGColor
 ];
 redLayer.startPoint = CGPointMake(-10.0, 0.5);
 redLayer.endPoint = CGPointMake(1.0, 0.5);

redLayer.anchorPoint = P(1.0,0.5);

 redLayer.frame = CGRectMake(0, 0, 125, 250);

 [baseLayer addSublayer:redLayer];

 CGFloat perspective = -1000; //This relates to the m34 perspective matrix.
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / perspective;
rotationAndPerspectiveTransform = CATransform3DScale(rotationAndPerspectiveTransform, 0.1f, 0.1f, 0.1f);
 baseLayer.sublayerTransform = rotationAndPerspectiveTransform;

 [self.view.layer addSublayer:baseLayer];

 CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath: @"sublayerTransform"];
 transformAnimation.fillMode = kCAFillModeForwards;
 transformAnimation.removedOnCompletion = NO;
 {

 CGFloat w0 = 0;
 CGFloat w1 = aViewWidth;
 w0 = w0 * sin(degreesToRadians(-10)) - perspective * cos(degreesToRadians(-10));
 w1 = w1 * sin(degreesToRadians(-10)) - perspective * cos(degreesToRadians(-10));
 CGFloat newWidth = w1 - w0;
 newWidth = newWidth * 1.2;

 CATransform3D newTransform = CATransform3DIdentity;
 newTransform.m34 = 1.0 / perspective;
 newTransform = CATransform3DRotate(newTransform, degreesToRadians(-10) , 0.0f, 1.0f, 0.0f);
 newTransform = CATransform3DScale(newTransform, 1.0f, 1.0f, 1.0f);
 newTransform = CATransform3DTranslate(newTransform, newWidth, 0.0f, 0.0f);

 transformAnimation.toValue = [NSValue valueWithCATransform3D:newTransform];
 transformAnimation.duration = 10.0;
 }
 [baseLayer addAnimation:transformAnimation forKey:@"transform"];
 }

Change your redLayer ancherPoint to (1.0, 0.5) and use negative value of angle in w0 and w1. newWidth (which is used for translation) variable should be negative value for left side animation and positive value for right side animation.