在寫Custom Layout的demo時,用到了CATransform3D的m34參數,遊手好閒的想探究下這個矩陣到底爲何能影響到圖形的透視旋轉等等變換,因此經過本篇文章總結一下收穫,供之後參考html
目錄app
- 簡單實現三維立方體
- CATransform3D&CGAffineTransform使用介紹
- 原理探究及理解
實現這個蠻簡單的,只須要合理的調整旋轉角度和平移,再加上一個定時器,完美(顯然這個效果沒什麼卵用,可是筆者這隻鶸來講,剛蹦出來的時候仍是蠻開心的)ide
實現步驟 : 1.定義一個Basic View -> 2.調整並添加立方體的六個面 3.定時器調整Basic View的layer旋轉
特別注意:旋轉時,咱們須要同時做用於6個子layer,因此請留意self.animateCube.layer.sublayerTransform = transform
中使用的是sublayerTransform
而非transform
oop
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];
An affine transformation matrix for use in drawing 2D graphics
用於繪製2D圖形的仿射變換矩陣動畫
以上爲官方文檔定義,那麼什麼是仿射變換,看看這裏數學咖們的解釋就能大概理解了→如何通俗地講解「仿射變換」這個概念?this
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便可。是否是頗有趣spa
label.transform = CGAffineTransformMakeScale(-1, -1);
Defines the standard transform matrix used throughout Core Animation.
定義核心動畫中使用的標準變換矩陣code
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官方文檔註解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可以影響屏幕座標中的透視關係了。
3D矩陣變換,其實就是2D矩陣變換的拓展,相應的3x3矩陣變成CATransform3D表明的4x4矩陣
通過對於CGAffineTransform的學習,這裏咱們就再也不推導經常使用的3D Api對應的變換了,直接貼上結果圖
變換矩陣根據功能劃分爲四個區域,這裏不作T一、T3區域的單獨標註,觀點在上文中已經提出,再也不贅述
目前大部分電子設備的圖形顯示,都是隻能用二維圖形表示三維物體,所以三維物體就要靠投影來下降位數獲得二維平面圖形,3D到2D轉換的過程,稱爲投影變換