【问题标题】:From CATransform3D to CGAffineTransform从 CATransform3D 到 CGAffineTransform
【发布时间】:2012-05-08 11:06:45
【问题描述】:

我正在使用以下函数将脉冲效果应用于视图

- (void)pulse {

    CATransform3D trasform = CATransform3DScale(self.layer.transform, 1.15, 1.15, 1);
    trasform = CATransform3DRotate(trasform, angle, 0, 0, 0);

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
    animation.toValue = [NSValue valueWithCATransform3D:trasform];
    animation.autoreverses = YES;
    animation.duration = 0.3;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.repeatCount = 2;
    [self.layer addAnimation:animation forKey:@"pulseAnimation"];

}

我想使用 CGAffineTransform self.transform 而不是 CATransform3D self.layer.transform 获得相同的结果。这可能吗?

【问题讨论】:

  • 出于好奇,如果您已经从前者获得了您想要的结果,为什么还要关心您是将 CATransform3D 应用于图层还是将 CGAffineTransform 应用于视图?
  • 因为self.layer.transform的初始值和self.transform不同,不是吗?
  • 我的意思是,在使用脉冲方法之前,我对视图应用了一些仿射变换,但我没有接触图层,所以我猜变换是那里的身份
  • 据我所知,应用于视图的变换被转换为底层的适当 CATransform3D。这很容易通过对您的视图应用转换来验证,然后运行上面的动画(当然,删除了您的非功能性CATransform3DRotate())。应该是基于之前UIView的transform。
  • 谢谢,我的代码有点不清楚,我得到了错误的动画。因此我猜想这两个变换(层和视图)是不同的,但我显然错了。谢谢!

标签: core-animation core-graphics


【解决方案1】:

可以将CATransform3D 转换为CGAffineTransform,但您会失去一些功能。我发现将层及其祖先的聚合转换转换为CGAffineTransform 很有用,因此我可以使用 Core Graphics 渲染它。约束是:

  • 您的输入将在 XY 平面中被视为平面
  • 您的输出在 XY 平面上也将被视为平面
  • 来自.m34 的透视/缩短将被中和

如果你觉得这听起来不错:

    // m13, m23, m33, m43 are not important since the destination is a flat XY plane.
    // m31, m32 are not important since they would multiply with z = 0.
    // m34 is zeroed here, so that neutralizes foreshortening. We can't avoid that.
    // m44 is implicitly 1 as CGAffineTransform's m33.
    CATransform3D fullTransform = <your 3D transform>
    CGAffineTransform affine = CGAffineTransformMake(fullTransform.m11, fullTransform.m12, fullTransform.m21, fullTransform.m22, fullTransform.m41, fullTransform.m42);

您将希望首先在 3D 转换中完成所有工作,例如从您的超层连接,然后最后将聚合 CATransform3D 转换为 CGAffineTransform。鉴于图层一开始是平坦的并渲染到平坦的目标上,我发现这非常合适,因为我的 3D 旋转变成了 2D 剪切。我还发现牺牲透视是可以接受的。没有办法解决这个问题,因为仿射变换必须保留平行线。

例如,要使用 Core Graphics 渲染 3D 变换层,您可以连接变换(考虑锚点!),然后转换为仿射,最后:

    CGContextSaveGState(context);
    CGContextConcatCTM(context, affine);
    [layer renderInContext:context];
    CGContextRestoreGState(context);

【讨论】:

  • 谢谢,这是正确的答案。不幸的是,它是那些应该包含在 Cocoa API 中的功能之一,但不是因为它不是“完整”转换(而且永远不可能)。
  • 我很高兴找到了这个。我一直在搜索“3d 到 2d 矩阵”一个星期,结果发现一堆数学乱码。
  • 你到底是怎么想出来的?这太棒了!我向你的数学天才鞠躬。
【解决方案2】:

当然。如果您在 Xcode 文档中搜索 CGAffineTransform,您会发现一章标题为“CGAffineTransform 参考”。在那一章中有一节叫做“功能”。它包括等效于 CATransform3DScale (CGAffineTransformScale) 和 CATransform3DRotate (CGAffineTransformRotate) 的函数。

请注意,您对 CATransform3DRotate 的调用实际上没有任何意义。您需要围绕一个轴旋转,并且您为所有 3 个轴传递 0。通常你想使用 CATransform3DRotate(trasform, angle, 0, 0, 1.0) 围绕 Z 轴旋转。引用文档:

如果向量的长度为零,则行为未定义。

【讨论】:

  • 但重点(我的问题可能不清楚)是如何拥有相当于 [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
  • 你真的不清楚。我从 CGAffineTransform 用于视图和 CATransform3D 用于您想知道如何执行指定不同计时函数的基于视图的动画的图层这一事实猜测。为此,您想使用 animateWithDuration:delay:options:animations:completion: UIView 类方法。 options 参数包括 UIViewAnimationOptionCurveEaseInOut、UIViewAnimationOptionCurveLinear 等值。只需指定所需的选项,然后在动画块中更改变换即可。
【解决方案3】:

您可以使用 CATransform3DGetAffineTransform 将 CATransform3d 转换为 CGAffineTransform。

let scaleTransform = CATransform3DMakeScale( 0.8, 0.8, 1)
imageview.transform = CATransform3DGetAffineTransform(scaleTransform)

【讨论】:

    猜你喜欢
    • 2010-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    相关资源
    最近更新 更多