CATransform3D的一点记录

做动画时经常要用到CATransform3D,这里记录一些自己的理解,一边日后尝尝温故。

CATransform3D.h中我们找到CATransform3D的结构定义:
struct CATransform3D
{
  CGFloat m11, m12, m13, m14;
  CGFloat m21, m22, m23, m24;
  CGFloat m31, m32, m33, m34;
  CGFloat m41, m42, m43, m44;
};

这是一个矩阵,反正我第一次看的时候是一点没搞明白怎么理解它。然后在网上找到这么一个解释:

struct CATransform3D
{
CGFloat m11(x缩放), m12(y切变), m13(旋转), m14();
CGFloat m21(x切变), m22(y缩放), m23(), m24();
CGFloat m31(旋转), m32(), m33(), m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。正直/负值都有意义);
CGFloat m41(x平移), m42(y平移), m43(z平移), m44();
}; 

这个解释给每个变量标注了作用,不明真相的我根据标注实现发现是可以的。可是为什么是这样呢,我在apple的文档里好像也没找到类似的解释,那这些是效果标注别人是怎么得来的呢?
我之前写过一篇关于Core Graphics中基本仿射变换,其实道理和那个差不多,无非是矩阵控制坐标变换。
点(x,y,z,1)经过CATransform3D矩阵变换得到新的点,这个过程是通过矩阵乘法实现的:

[x y z 1][m11 m12 m13 m14
          m21 m22 m23 m24
          m31 m32 m33 m34
          m41 m42 m43 m44]-->[x' y' z' 1]

x'=(x*m11+y*m21+z*m31+m41)/(x*m14+y*m24+z*m34+m44)
y'=(x*m12+y*m22+z*m32+m42)/(x*m14+y*m24+z*m34+m44)
z'=(x*m13+y*m23+z*m33+m43)/(x*m14+y*m24+z*m34+m44)

这样看着实抽象,我们可以把它简化几个简单的基本变换。
设矩阵T:

T = [m11 m12 m13 m14
     m21 m22 m23 m24
     m31 m32 m33 m34
     m41 m42 m43 m44];

1.平移变换
令m12=m13=m14=m21=m23=m24=m31=m32=m34=0;
m11=m22=m33=m44=1;

T=[ 1   0   0   0
    0   1   0   0
    0   0   1   0
   m41 m42 m43  1]
x'=x+m41
y'=y+m42
z'=z+m43

这种情形下矩阵T的作用就是平移变换,m41,m42,m43的作用分别就是对x,y,z进行平移。

2.缩放变换
令m44=1;
m12=m13=m14=m21=m23=m24=m31=m32=m34=m41=m42=m43=0;

T=[m11  0   0   0
    0  m22  0   0
    0   0  m33  0
    0   0   0   1]
 x'=x*m11
 y'=y*m12
 z'=z*m33

这种情况矩阵T就是缩放变换,m11,m22,m33分别是x,y,z的缩放因子。

3.旋转变换
绕x轴旋转

T=[1    0      0     0
   0  cos(a) sin(a)  0
   0 -sin(a) cos(a)  0
   0    0      0     1] 
x'=x
y'=y*cos(a)-z*sin(a)
z'=y*sin(a)+z*cos(a)

绕y轴旋转

T=[cos(a)  0   sin(a)  0
   0       1    0      0
   -sin(a) 0   cos(a)  0
   0       0    0      1] 
x'=x*cos(a)-z*sin(a)
y'=y
z'=x*sin(a)+z*cos(a)

绕z轴旋转

T=[cos(a)  sin(a)  0  0
   -sin(a) cos(a)  0  0
     0       0     1  0
     0       0     0  1] 
x'=x*cos(a)-z*sin(a)
y'=x*sin(a)+y*cos(a)
z'=z

4.透视投影变换
令T

T=[1 0 0 m14
   0 1 0 m24
   0 0 1 m34
   0 0 0  1 ]
x'=x/(x*m14+y*m24+z*m34+1)
y'=y/(x*m14+y*m24+z*m34+1)
z'=z/(x*m14+y*m24+z*m34+1)

在上式中,令m14=0,m24=0

x'=x/(z*m34+1)
y'=y/(z*m34+1)
z'=z/(z*m34+1)

这就是我们所熟悉的修改m34形成投影效果 。

综上所述,网上的所看到的结构体描述并不是很精确,只有懂了原因才能更好的理解。

实际运用中,官方为我们封装了一些基本变换api,遇到复杂的动画,可以通过链接基本变换的方式组合实现。

平移变换:CATransform3DMakeRotation
旋转变换:CATransform3DMakeRotation
缩放变换:CATransform3DMakeScale

参考:http://blog.sina.com.cn/s/blog_620bf89501011fl8.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为下列代码实现可暂停效果: import UIKit class ViewController: UIViewController { private let radarAnimation = "radarAnimation" private var animationLayer: CALayer? private var animationGroup: CAAnimationGroup? private var opBtn: UIButton! override func viewDidLoad() { super.viewDidLoad() let first = makeRadarAnimation(showRect: CGRect(x: 120, y: 100, width: 100, height: 100), isRound: true) view.layer.addSublayer(first) opBtn = UIButton(frame: CGRect(x: 100, y: 450, width: 80, height: 80)) opBtn.backgroundColor = UIColor.red opBtn.clipsToBounds = true opBtn.setTitle("Hsu", for: .normal) opBtn.layer.cornerRadius = 10 view.addSubview(opBtn) let second = makeRadarAnimation(showRect: opBtn.frame, isRound: false) view.layer.insertSublayer(second, below: opBtn.layer) } @IBAction func startAction(_ sender: UIButton) { animationLayer?.add(animationGroup!, forKey: radarAnimation) } @IBAction func stopAction(_ sender: UIButton) { animationLayer?.removeAnimation(forKey: radarAnimation) } private func makeRadarAnimation(showRect: CGRect, isRound: Bool) -> CALayer { // 1. 一个动态波 let shapeLayer = CAShapeLayer() shapeLayer.frame = showRect // showRect 最大内切圆 if isRound { shapeLayer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: showRect.width, height: showRect.height)).cgPath } else { // 矩形 shapeLayer.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: showRect.width, height: showRect.height), cornerRadius: 10).cgPath } shapeLayer.fillColor = UIColor.orange.cgColor // 默认初始颜色透明度 shapeLayer.opacity = 0.0 animationLayer = shapeLayer // 2. 需要重复的动态波,即创建副本 let replicator = CAReplicatorLayer() replicator.frame = shapeLayer.bounds replicator.instanceCount = 4 replicator.instanceDelay = 1.0 replicator.addSublayer(shapeLayer) // 3. 创建动画组 let opacityAnimation = CABasicAnimation(keyPath: "opacity") opacityAnimation.fromValue = NSNumber(floatLiteral: 1.0) // 开始透明度 opacityAnimation.toValue = NSNumber(floatLiteral: 0) // 结束时透明底 let scaleAnimation = CABasicAnimation(keyPath: "transform") if isRound { scaleAnimation.fromValue = NSValue.init(caTransform3D: CATransform3DScale(CATransform3DIdentity, 0, 0, 0)) // 缩放起始大小 } else { scaleAnimation.fromValue = NSValue.init(caTransform3D: CATransform3DScale(CATransform3DIdentity, 1.0, 1.0, 0)) // 缩放起始大小 } scaleAnimation.toValue = NSValue.init(caTransform3D: CATransform3DScale(CATransform3DIdentity, 1.5, 1.5, 0)) // 缩放结束大小 let animationGroup = CAAnimationGroup() animationGroup.animations = [opacityAnimation, scaleAnimation] animationGroup.duration = 3.0 // 动画执行时间 animationGroup.repeatCount = HUGE // 最大重复 animationGroup.autoreverses = false self.animationGroup = animationGroup shapeLayer.add(animationGroup, forKey: radarAnimation) return replicator } }
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值