《iOS核心动画高级技巧》笔记(三) - 变换

变换

  • 研究可以用来对图层旋转,摆放或者扭曲的CGAffineTransform,以及可以将扁平物体转换成三维空间对象的CATransform3D

仿射变换

  • UIViewtransform属性是一个CGAffineTransform类型,用于在二维空间做旋转,缩放和平移,实际上它只是封装了内部图层的变换。
CGAffineTransformMakeRotation(CGFloat angle)

CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)


* `CALayer`同样也有一个`transform`属性,但它的类型是`CATransform3D`,而不是`CGAffineTransform`。
* `CALayer`对应于`UIView`的`transform`属性是`affineTransform`.

* 弧度换算:`#define DEGREES_TO_RADIANS(x) ((x)/180.0*M_PI)`,
 * `M_PI`:180(度),`M_PI_4`:180/4(度)

```swift

@interface ViewController ()

@property (nonatomic, weak) IBOutlet UIView *layerView;
@end
@implementation ViewController

  • (void)viewDidLoad
    {
    [super viewDidLoad];
    CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);
    self.layerView.layer.affineTransform = transform;
    }
    @end

#####混合变换
* 当操纵一个变换的时候,初始生成一个什么都不做的变换很重要
 * `CGAffineTransformIdentity`
* 混合两个已经存在的变换矩阵
 * `CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);`
* 注意:**下一个变换是基于上一个变换的结果**

```swift
- (void)viewDidLoad

{
[super viewDidLoad];
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformScale(transform, 0.5, 0.5);
transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 30.0);
transform = CGAffineTransformTranslate(transform, 200, 0);
self.layerView.layer.affineTransform = transform;
}


####3D变换
* `CG`的前缀告诉我们,`CGAffineTransform`类型属于`Core Graphics`框架,`Core Graphics`实际上是一个严格意义上的`2D`绘图`API`,并且`CGAffineTransform`仅仅对`2D`变换有效。

```swift
CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)

CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz)
CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)

* 简单运用。

```swift
@implementation ViewController
  • (void)viewDidLoad
    {
    [super viewDidLoad];
    CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
    self.layerView.layer.transform = transform;
    }
    @end

Snip20170526_2.png
透视投影
  • CATransform3D的透视效果通过一个矩阵中一个很简单的元素来控制:m34
  • m34的默认值是 0,我们可以通过设置m34-1.0 / d来应用透视效果,d代表了想象中视角相机和屏幕之间的距离,以像素为单位,通常500-1000就已经很好了
@implementation ViewController
  • (void)viewDidLoad
    {
    [super viewDidLoad];
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = - 1.0 / 500.0;
    transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
    self.layerView.layer.transform = transform;
    }
    @end


Snip20170526_3.png
灭点
  • 当在透视角度绘图的时候,远离相机视角的物体将会变小变远,当远离到一个极限距离,它们 可能就缩成了一个点,于是所有的物体最后都汇聚消失在同一个点。
  • 这个点位于变换图层的anchorPoint,改变一个图层的position,你也改变了它的灭点
  • 这句话大家自己理解,为什么要共享一个灭点?我估计效果应该是让其他3D图层整体看起来更加协调一些。
  • 当视图通过调整m34来让它更加有3D效果,应该首先把它放置于屏幕中央,然后通过平移来把它移动到指定位置(而不是直接改变它的position),这样所有的3D图层都共享一个灭点。
sublayerTransform属性
  • sublayerTransformCALayer的属性,CATransform3D类型,一次性对包含这些图层的容器做变换,所有的子图层都自动继承了这个变换方法.
  • 另一个显著的优势:灭点被设置在容器图层的中点,从而不需要再对子图层分别设置了。意味着你可以随意使用positionframe来放置子图层,而不需要把它们放置在屏幕中点,然后为了保证统一的灭点用变换来做平移。
@interface ViewController ()

@property (nonatomic, weak) IBOutlet UIView *containerView;
@property (nonatomic, weak) IBOutlet UIView *layerView1;
@property (nonatomic, weak) IBOutlet UIView *layerView2;
@end
@implementation ViewController

  • (void)viewDidLoad
    {
    [super viewDidLoad];
    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = - 1.0 / 500.0;
    self.containerView.layer.sublayerTransform = perspective;
    CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
    self.layerView1.layer.transform = transform1;
    CATransform3D transform2 = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);
    self.layerView2.layer.transform = transform2;
    }

Snip20170526_4.png
  • 个人理解:对于内部的图层并不直接是容器图层的子图层没有效果,如:内部图层的内部图层。
背面
  • 图层是双面绘制的,反面显示的是正面的一个镜像图片。
  • doubleSidedCALayer的属性,控制图层的背面是否要被绘制。这是一个BOOL类型,默认为YES
  • 如果设置为NO,那么当图层正面从相机视角消失的时候,它将不会被绘制。
扁平化图层
  • 如果对包含已经做过变换的图层的图层做反方向的变换是否会回复原样?
  • 针对 Z 轴做平面旋转可以达到预期效果(白色内部的深灰色图层是反方向变换后的,下同)
Snip20170526_5.png
  • 针对 Y 轴做立体旋转不能达到预期效果
Snip20170526_6.png
  • 针对 Y 轴旋转预期效果
Snip20170526_7.png
  • 由于它们并不都存在同一个3D空间。每个图层的3D场景其实是扁平化的,当你从正面观察一个图层,看到的实际上由子图层创建的想象出来的3D场景,但当你倾斜这个图层,你会发现实际上这个3D场景仅仅是被绘制在图层的表面。(CATransformLayer子类用于解决此类问题)
  • 个人理解:每个图层都有属于自己的3D空间,子图层3D效果是基于父图层的3D空间进行绘制的,所以父图层变换后,子图层变换是基于父图层。

固体对象(略)原文地址

大概内容就是通过代码用六个视图控件拼成一个立方体,导入GLKit库进行阴暗面处理,最后监听 3 上按钮的点击事件。

Snip20170526_8.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容