前言

在写Custom Layout的demo时,用到了CATransform3D的m34参数,不务正业的想探究下这个矩阵到底为什么能影响到图形的透视旋转等等变换,所以通过本篇文章总结一下收获,供以后参考

目录

简单实现三维立方体

CATransform3D&CGAffineTransform使用介绍

原理探究及理解

简单实现三维立方体

实现这个蛮简单的,只需要合理的调整旋转角度和平移,再加上一个定时器,完美(显然这个效果没什么卵用,但是笔者这只鶸来说,刚蹦出来的时候还是蛮开心的)

实现步骤 : 1.定义一个Basic View -> 2.调整并添加立方体的六个面 3.定时器调整Basic View的layer旋转

特别注意:旋转时,我们需要同时作用于6个子layer,所以请留意self.animateCube.layer.sublayerTransform = transform中使用的是sublayerTransform而非transform

CGRect targetBounds = (CGRect){CGPointZero,CGSizeMake(200, 200)};

self.animateCube = [[UIView alloc] initWithFrame:targetBounds];

_animateCube.center = self.view.center;

[self.view addSubview:self.animateCube];

UIView *test = [[UIView alloc] initWithFrame:targetBounds];// front

test.backgroundColor = [[UIColor blueColor] colorWithAlphaComponent:0.25];

test.layer.transform = CATransform3DTranslate(test.layer.transform, 0, 0, 100);

UIView *test1 = [[UIView alloc] initWithFrame:targetBounds];// back

test1.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];

test1.layer.transform = CATransform3DTranslate(test1.layer.transform, 0, 0, -100);

UIView *test2 = [[UIView alloc] initWithFrame:targetBounds];// left

test2.backgroundColor = [[UIColor yellowColor] colorWithAlphaComponent:0.5];

test2.layer.transform = CATransform3DTranslate(test2.layer.transform, -100, 0, 0);

test2.layer.transform = CATransform3DRotate(test2.layer.transform, M_PI_2, 0, 1, 0);

UIView *test3 = [[UIView alloc] initWithFrame:targetBounds];// right

test3.backgroundColor = [[UIColor purpleColor] colorWithAlphaComponent:0.5];

test3.layer.transform = CATransform3DTranslate(test3.layer.transform, 100, 0, 0);

test3.layer.transform = CATransform3DRotate(test3.layer.transform, M_PI_2, 0, 1, 0);

UIView *test4 = [[UIView alloc] initWithFrame:targetBounds];// head

test4.backgroundColor = [[UIColor orangeColor] colorWithAlphaComponent:0.5];

test4.layer.transform = CATransform3DTranslate(test4.layer.transform, 0, 100, 0);

test4.layer.transform = CATransform3DRotate(test4.layer.transform, M_PI_2, 1, 0, 0);

UIView *test5 = [[UIView alloc] initWithFrame:targetBounds];// foot

test5.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.5];

test5.layer.transform = CATransform3DTranslate(test5.layer.transform, 0, -100, 0);

test5.layer.transform = CATransform3DRotate(test5.layer.transform, M_PI_2, -1, 0, 0);

[self.animateCube addSubview:test];

[self.animateCube addSubview:test1];

[self.animateCube addSubview:test2];

[self.animateCube addSubview:test3];

[self.animateCube addSubview:test4];

[self.animateCube addSubview:test5];

self.animateCube.transform = CGAffineTransformMakeScale(0.5, 0.5);//CGAffineTransform

__block CATransform3D transform = CATransform3DIdentity;

NSLog(@"%@",[NSString logForCATransform3D:transform]);

// Label

UILabel *label = [[UILabel alloc] init];

label.frame = CGRectOffset(self.animateCube.frame, 0, - 100);

label.text = @"AnimatedCube";

[label sizeToFit];

[self.view addSubview:label];

transform.m34 = 1.0/-500;

float angle = M_PI / 360;

self.animateCube.layer.sublayerTransform = transform;

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0/60 repeats:YES block:^(NSTimer * _Nonnull timer) {

transform = CATransform3DRotate(transform, angle, 1, 1, 0.5);

self.animateCube.layer.sublayerTransform = transform;//

}];

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

CATransform3D&CGAffineTransform使用介绍

CGAffineTransform

An affine transformation matrix for use in drawing 2D graphics

用于绘制2D图形的仿射变换矩阵

以上为官方文档定义,那么什么是仿射变换,看看这里数学咖们的解释就能大概理解了→如何通俗地讲解「仿射变换」这个概念?

CGAffineTransformMake返回直接控制每一个参数的仿射变换矩阵

CGAffineTransform CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty);

CGAffineTransformScale返回通过缩放现有仿射变换构造的仿射变换矩阵,sx/sy即为x方向和y方向的缩放比例

CGAffineTransform CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy);

CGAffineTransformRotate返回通过旋转现有仿射变换构造的仿射变换矩阵,angle为旋转弧度

CGAffineTransform CGAffineTransformRotate(CGAffineTransform t, CGFloat angle);

CGAffineTransformInvert返回通过反转现有仿射变换构造的仿射变换矩阵。

CGAffineTransform CGAffineTransformInvert(CGAffineTransform t);

CGAffineTransformTranslate返回实现平移的仿射变换矩阵。tx/ty为偏移量

CGAffineTransform CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty);

CGAffineTransformConcat返回通过组合两个现有仿射变换构造的仿射变换矩阵。本质就是两个矩阵的乘法,上述平移、旋转、缩放的操作,如配图所示,都是可以通过点的齐次坐标与仿射变换矩阵的乘积获得,原理笔者会在第三部分解释

CGAffineTransform CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2);

几个特殊的仿射变换矩阵

CGAffineTransformMakeScale/CGAffineTransformMakeRotation/CGAffineTransformMakeTranslation 都是在原视图初始坐标的基础上变化,所以并不会累加效果,相比上述Api它少了基础仿射矩阵参数CGAffineTransform t

// scale

CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy);

// rotaion

CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle);

// translation

CGAffineTransform CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty);

CGAffineTransformIdentity即单位矩阵如下图所示,他并不会对图形造成任何影响,通常用来恢复初始状态

我们要想将文字视图翻转该怎么做呢?

很简单,只需要将CGAffineTransformMakeScale中的参数设置为-1即可。是不是很有趣

label.transform = CGAffineTransformMakeScale(-1, -1);

CATransform3D

Defines the standard transform matrix used throughout Core Animation.

定义核心动画中使用的标准变换矩阵

CATransform同样定义为结构体,代表了三维图形4x4的变换矩阵。网上有几篇文章,对每个参数功能都进行了标注,但是这样并不十分严谨。因为左上3x3的矩阵区域,各个参数需要相互作用才能达到理想的准确状态,并不单纯的是某个值负责某种准确的三维图形变换。笔者将在本文的第三部分原理探究及理解中具体解释,感(hen)兴(wu)趣(liao)的同学可以往下看看。

因为只是从2D变换变成3D变换,而且4x4矩阵本身就是3x3矩阵的拓展,原理是一样的,所以有很多相似相通的地方。

CATransform3DScale返回通过缩放现有变换构造的变换矩阵,sx/sy/sz即为x方向、y方向和z方向的缩放比例

CATransform3D CATransform3DScale (CATransform3D t, CGFloat sx,

CGFloat sy, CGFloat sz)

CATransform3DRotate返回通过旋转现有变换构造的变换矩阵,angle代表弧度,x,y,z代表各个轴上旋转的弧度倍数

CATransform3D CATransform3DRotate (CATransform3D t, CGFloat angle,

CGFloat x, CGFloat y, CGFloat z)

CATransform3DInvert返回反转后的变换矩阵

CATransform3D CATransform3DInvert (CATransform3D t)

CATransform3DTranslate返回实现x/y/z轴上平移相应距离的变换矩阵

CATransform3D CATransform3DTranslate (CATransform3D t, CGFloat tx,

CGFloat ty, CGFloat tz)

CATransform3DConcat返回同时作用两种变换矩阵的矩阵

CATransform3D CATransform3DConcat (CATransform3D a, CATransform3D b)

几个特殊的变换矩阵

CATransform3DMakeScale/CATransform3DMakeRotation/CATransform3DMakeTranslation同样是作用于原始视图的变换矩阵

/* Returns a transform that translates by '(tx, ty, tz)':

* t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1]. */

CATransform3D CATransform3DMakeTranslation (CGFloat tx,

CGFloat ty, CGFloat tz)

/* Returns a transform that scales by `(sx, sy, sz)':

* t' = [sx 0 0 0; 0 sy 0 0; 0 0 sz 0; 0 0 0 1]. */

CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy,

CGFloat sz)

/* Returns a transform that rotates by 'angle' radians about the vector

* '(x, y, z)'. If the vector has length zero the identity transform is

* returned. */

CATransform3D CATransform3DMakeRotation (CGFloat angle, CGFloat x,

CGFloat y, CGFloat z)

CATransform3DIdentity[1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 0 1],人畜无害矩阵,通常用于恢复初始状态

原理解释

CGAffineTransform

以下是苹果官方文档对于CGAffineTransform二维变换矩阵对图形影响的注解

CGAffineTransform官方文档注解An affine transformation matrix is used to rotate, scale, translate, or skew the objects you draw in a graphics context. The CGAffineTransform

type provides functions for creating, concatenating, and applying affine transformations.

Affine transforms are represented by a 3 by 3 matrix:

Because the third column is always (0,0,1), the CGAffineTransform

data structure contains values for only the first two columns.

Conceptually, an affine transform multiplies a row vector representing each point (x,y) in your drawing by this matrix, producing a vector that represents the corresponding point (x’,y’):

Given the 3 by 3 matrix, the following equations are used to transform a point (x, y) in one coordinate system into a resultant point (x’,y’) in another coordinate system.

看到这里,线代大神一定会嘴角上扬了,所以如果以下内容有任何理解或书写错误,请您务必留言给笔者鶸渣评论勘误打脸,千万不要高抬贵手。

二维的变换都可以看作是坐标的齐次坐标同[a b 0; c d 0; tx ty 1]的乘法运算

矩阵的乘法规则:第m行与第n行交叉位置的值,等于第一个矩阵第m行与第二个矩阵第n列对应位置的乘积之和。依据这个规则,再看下图,是不是感觉豁然开朗

知道了原理后,我们继续探究translate/scale/rotate到底“背地里”干了些什么

上文中我们提到了,单独对结构体中某个的参数(Translate平移的参数当然不会出错,问题集中在对于线性变化区域的标注,即CGAffineTransform左上2x2区域、CATransform3D左上3x3区域)进行功能注释是不够严谨的。

为了证明这一观点,笔者绘制了CGAffineTransformRotate仿射矩阵的推导过程图(这一结论在CATransform3DRotate矩阵中,同样适用,证明具体参数标注的不严谨)

相关推导用到的转换公式

sin(A+B) = sinAcosB + cosAsinB

sin(A-B) = sinAcosB - cosAsinB

cos(A+B) = cosAcosB - sinAsinB

cos(A-B) = cosAcosB + sinAsinB

下面给出相对简单的CGAffineTransformTranslate和CGAffineTransformScale的矩阵的简单推导

细心的同学可能会发现,系统Api修改的都是矩阵的前两列参数。那么调整第三列,会有什么样的效果?

第三列参数,直接作用到齐次坐标的n+1维的参数上,它同普通坐标的转换关系以我们一直讨论的二维为例,如下图。为保证x = x',y = y',所以默认转换后,齐次坐标的d = 1,如果第三列前两个参数均为0,那么修改右下位置的参数,可以直接控制图形的缩放。前两个参数则是随着图形中点的x、y值的变化改变对于齐次坐标中d值得影响。

不过苹果并没有给我们提供这三个参数,而是选择在二维变换时把这一列去掉了-。- 可能觉得意义不大吧。但是,在CATransform3D中,这一列得到了保留,我们熟悉的m34,正是受z轴影响的透视关键参数,相信看到这里的你,应该已经能够理解为什么改变m34能够影响屏幕坐标中的透视关系了。

CATransform3D

3D矩阵变换,其实就是2D矩阵变换的拓展,相应的3x3矩阵变成CATransform3D代表的4x4矩阵

经过对于CGAffineTransform的学习,这里我们就不再推导常用的3D Api对应的变换了,直接贴上结果图

变换矩阵根据功能划分为四个区域,这里不做T1、T3区域的单独标注,观点在上文中已经提出,不再赘述

投影变换

目前大部分电子设备的图形显示,都是只能用二维图形表示三维物体,因此三维物体就要靠投影来降低位数得到二维平面图形,3D到2D转换的过程,称为投影变换

m34为什么能改变透视关系:

m34影响到了T4区域的s值,s值会对投影的图形在z轴方向产生线性影响,为什么通常会用1/d的负值,因为用户特殊的观察视角,决定了感官上近大远小的特性,同时iOS中的坐标系,是左手坐标系,远离我们的方向,是z轴的负方向,所以越深入屏幕,图像中点的齐次坐标中的d就越大,屏幕上的投影就越小

旋转正方向的确定:左手坐标系适用于左手定律(反之亦然),握住指定轴,拇指指向该轴正方向,四指指向方向即为正方向

java 三维旋转立方体_iOS-从三维立方体到理解CATransform3DCGAffineTransformm34相关推荐

  1. 彻底搞懂“旋转矩阵/欧拉角/四元数”,让你体会三维旋转之美

    目录 旋转矩阵 坐标变换的作用 实现坐标变换所需的数据 位姿变换 坐标变换中旋转的实质 坐标变换中平移的实质 如何计算坐标系B各坐标轴在坐标系A上的投影?(多坐标变换) 如何实现坐标变换? 欧拉角 欧 ...

  2. java 三维旋转立方体_Canvas实现3D效果-可旋转的立方体

    摘要:Canvas画布是一个二维平面,如何展示出3D效果?通过将三维空间中的Z轴抽取出来,将图像的点投影到与Z轴垂直的平面上,在通过旋转等变换效果,我们就能实现3D效果. 一.建立坐标系 1)立方体坐 ...

  3. java 三维旋转立方体_【转】 CATransform3D 矩阵变换之立方体旋转实现细节

    原文网址:http://blog.csdn.net/ch_soft/article/details/7351896 第一部分.前几天做动画,使用到了CATransform3D ,由于没有学过计算机图形 ...

  4. 图形学笔记(四)变换——三维变换(三维旋转与欧拉角)、MVP变换、视图变换、投影变换(正交投影与透视投影)

    图形学笔记(三)变换--缩放.镜像.切变 图形学笔记(五)光栅化--屏幕.像素.屏幕空间.视口变换.基础图元与三角形.采样.包围盒.锯齿或走样 文章目录 1 三维空间中的变换 1.1 三维空间中的齐次 ...

  5. 地图旋转_折纸效果三维旋转,不一样的地图页设计

    我们在制作PPT或网页的过程中,有时候会用到地图来标记地点信息. 比如这样 ▲图片来自腾讯云官网 或者是这样 ▲图片来自全球敏捷运维峰会官网 今天就来给大家介绍一种地图页面的新玩法:三维折纸地图. 听 ...

  6. 三维旋转四元数系列(4.四元数三维旋转表达)

    三维旋转四元数系列(0.复数基本介绍)https://blog.csdn.net/SKANK911/article/details/90033451 三维旋转四元数系列(1.复数与二维旋转)https ...

  7. 三维旋转四元数系列(3.四元数定义与基本性质)

    三维旋转四元数系列(0.复数基本介绍)https://blog.csdn.net/SKANK911/article/details/90033451 三维旋转四元数系列(1.复数与二维旋转)https ...

  8. 三维旋转四元数系列(2.三维旋转之轴角与罗德里格斯公式推导)

    序:上两节我们介绍了复数的基本概念与性质,以及复数与二维旋转的关系. 三维旋转四元数系列(0.复数基本介绍)https://blog.csdn.net/SKANK911/article/details ...

  9. 三维旋转(根据转轴和角度)的公式。罗德里格旋转公式

    (这是从维基百科拿来的公式) 在三维旋转理论体系中,罗德里格旋转公式(根据欧林·罗德里格命名)是在给定转轴和旋转角度后,旋转一个向量的有效算法.如果v是在中的向量,k是转轴的单位向量,θ是旋转角度(根 ...

  10. 资料分享:四元数与三维旋转 | 故事:四维虫子

    该分享来自鱼粉me,资料为pdf格式,主要阐述四元数和三维旋转,作者为Krasjet. 公众号后台回复:四元数 获取完整PDF 故事分享-四维虫子 他:"你好." 我:" ...

最新文章

  1. LabVIEW实现PCB电路板坐标定位(实战篇—2)
  2. 大学计算机英语专业感想感知,非英语专业大学生英语感知学习风格研究
  3. Xamarin.Android SharedPreferences的使用方法
  4. 判断输入的数是否质数,求范围内的质数有哪些
  5. MyBatis 架构分层与模块划分-接口层
  6. CentOS6.x 下 /etc/security/limits.conf 被改错的故障经历
  7. 基于PyMC的贝叶斯建模实战
  8. 手机进程设置多少个最好_安卓手机难逃卡顿宿命?打开4个系统设置,秒变新机般流畅...
  9. 【Java中级篇】动态代理机制
  10. 数据科学即将迎来“无代码”时代
  11. Linux常用命令介绍(二)——压缩与解压缩命令
  12. 通俗易懂地讲解 __block 变量
  13. 中文字符集编码unicode,gb2312,cp936,GBK,GB18030介绍
  14. PS如何更改图片部分颜色
  15. 中国首次包揽2021年国际信息学奥赛(IOI 2021)前四名
  16. Tomcat学习笔记(含servlet)
  17. 英特尔服务器主板型号,支持英特尔® Server Board S2600JF
  18. openlayers 仿CAD(1)
  19. dubbo整合springboot图解版(九)
  20. 蚂蚁金服面试题及答案-总结

热门文章

  1. linux网络认证,在Linux下通过WEB认证方式上网
  2. Matplotlib 可视化必备神书,完整PDF下载
  3. 使用VBA在Office中输入特殊字符(3/3)
  4. oracle简易版创建数据库,建立简易金融数据库
  5. 第五章(1.8)金典网络解读—LeNet5、AlexNet、VGGNet
  6. Mysql 0427课后总结
  7. 第二周JAVA课后总结
  8. 电脑开机慢什么原因?如何管理禁止电脑开机自启动程序软件?
  9. java 字符串拆分技巧_{转}Java 字符串分割三种方法
  10. 微盟6亿美元募资怎么花?大力提升研发实力、战略布局再提速