核心動(dòng)畫知識(shí)導(dǎo)入
CoreAnimation
框架是基于OpenGL ES 手機(jī)端/OpenGL PC端
(iOS13開始為Metal
)與CoreGraphics
圖像處理框架的一個(gè)跨平臺(tái)的框架钞啸。
了解CoreAnimation
-
CoreAnimation
的封裝核心就是去簡(jiǎn)化OpenGL
圖形處理树枫,原因是OpenGL
的學(xué)習(xí)成本是非常高的肩祥;CoreAnimation也可以用作Mac OS
開發(fā) -
Core Graphics
核心繪圖 -
Graphics Hardware
圖形加速硬件戒悠,這個(gè)圖形硬件就是GPU芯片
逆趋,GPU專門用來做計(jì)算锥咸,GPU并不是顯卡靶溜,而是顯卡需要GPU -
iOS 13
之后OpenGL
更新為Metal
匾乓,Metal只針對(duì)iOS
和Mac OS
系統(tǒng);而OpenGL ES
是可以針對(duì)整個(gè)嵌入式環(huán)境
(安卓鳄厌、黑莓等都可以使用)
GPU
與CPU
的區(qū)別
CPU: 中央處理器
(英文Central Processing Unit)是一臺(tái)計(jì)算機(jī)的運(yùn)算核心和控制核心荞胡;其功能主要是解釋計(jì)算機(jī)指令以及處理計(jì)算機(jī)軟件中的數(shù)據(jù)
。
GPU:圖形處理器
(英文Graphic Processing Unit)是一個(gè)專門的圖形核心處理器了嚎;GPU是顯卡的大腦泪漂,決定了該顯卡的檔次和大部分性能,同時(shí)也是2D顯卡
和3D顯卡
的區(qū)別依據(jù)歪泳;2D顯示芯片在處理3D圖像和特效時(shí)主要依賴CPU的處理能力萝勤,稱為軟加速
;3D顯示芯片是將三維圖像和特效處理功能集中在顯示芯片內(nèi)呐伞,也即所謂的硬件加速
敌卓。
主要區(qū)別如下:
- CPU需要很強(qiáng)的通用性來處理
各種不同的數(shù)據(jù)類型
,同時(shí)又要邏輯判斷
又會(huì)引入大量的分支跳轉(zhuǎn)
和中斷
的處理伶氢,這些都使得CPU的內(nèi)部結(jié)構(gòu)異常復(fù)雜趟径;而GPU面對(duì)的則是類型高度統(tǒng)一的
、相互無(wú)依賴
的大規(guī)模數(shù)據(jù)和不需要被打斷
的純凈
的計(jì)算環(huán)境 - GPU采用了數(shù)量眾多的
計(jì)算單元
和超長(zhǎng)的流水線
癣防,但只有非常簡(jiǎn)單的控制邏輯并省去了Cache
蜗巧,而CPU不僅被Cache占據(jù)了大量空間,而且還有有復(fù)雜的控制邏輯和諸多優(yōu)化電路劣砍,相比之下計(jì)算能力只是CPU很小的一部分
惧蛹。
核心動(dòng)畫的優(yōu)點(diǎn)
- 簡(jiǎn)單易用的
高性能混合編程模型
- 用類似于
UIView
一樣,使?圖層來創(chuàng)建復(fù)雜的編程接口刑枝,更加高效的使用 - 輕量化的數(shù)據(jù)結(jié)構(gòu)香嗓,它可以同時(shí)顯示讓上百個(gè)圖層產(chǎn)?動(dòng)畫效果
- 一套?常簡(jiǎn)單的動(dòng)畫接口,能讓動(dòng)畫運(yùn)?在獨(dú)立的線程中装畅,并可以獨(dú)?于主線程之外
- 一旦動(dòng)畫配置完成并啟動(dòng)靠娱,核?動(dòng)畫就能獨(dú)立并完全控制相應(yīng)的動(dòng)畫幀
- 提?應(yīng)用性能,應(yīng)?程序只有當(dāng)發(fā)生改變的時(shí)候才會(huì)重繪內(nèi)容掠兄,使用Core Animation 可以不使?其他圖形API像云,例如
OpenGL
來獲取高效的動(dòng)畫性能. - 靈活的布局管理模型锌雀,允許圖層相對(duì)同級(jí)圖層的關(guān)系來設(shè)置屬性的位置和?小
核心動(dòng)畫圖層樹結(jié)構(gòu)
CoreAnimation
核心動(dòng)畫的結(jié)構(gòu)圖
CAAnimation
是所有動(dòng)畫對(duì)象的父類(抽象類,虛類)迅诬,實(shí)現(xiàn)CAMediaTiming
協(xié)議腋逆,負(fù)責(zé)控制動(dòng)畫的時(shí)間、速度和時(shí)間曲線等等侈贷,是一個(gè)抽象類惩歉。
核心動(dòng)畫類中可以直接使用的類
有五個(gè),其中CAAnimation
俏蛮、CAPropertyAnimation
是抽象類撑蚌,不能直接使用。
-
CAAnimationGroup
: 動(dòng)畫組搏屑,可以將很多種動(dòng)畫合并到一起争涌,組成動(dòng)畫效果 -
CATransition
: 轉(zhuǎn)場(chǎng)動(dòng)畫效果 -
CAKeyframeAnimation
: 關(guān)鍵幀動(dòng)畫效果;values
: 一個(gè)NSArray對(duì)象辣恋;里面的元素稱為關(guān)鍵幀
(keyframe)亮垫,動(dòng)畫對(duì)象會(huì)在指定的時(shí)間(duration)內(nèi),依次顯示values數(shù)組中的每一個(gè)關(guān)鍵幀抑党;簡(jiǎn)單理解為包警,很多動(dòng)畫幀執(zhí)行 -
CABasicAnimation
: 基礎(chǔ)動(dòng)畫,簡(jiǎn)單常見的動(dòng)畫效果 -
CASpringAnimation
: iOS9.0之后新增的彈簧效果動(dòng)畫底靠,是CABasicAnimation
的子類
CALayer
與UIView
的區(qū)別
-
CALayer
:繼承于NSObject
,所以不具備響應(yīng)不能處理用戶交互特铝,負(fù)責(zé)繪制暑中、渲染圖形
-
UIView
: 繼承于UIResponder
,所以可以進(jìn)行事件響應(yīng)鲫剿,屬性CALayer負(fù)責(zé)圖形繪制與渲染鳄逾;UIView
是CALayer
的delegate,可以實(shí)現(xiàn)一些簡(jiǎn)單的CALayer的方法灵莲,但要實(shí)現(xiàn)稍微復(fù)雜些的動(dòng)畫效果雕凹,就需要借助CALayer,如:陰影政冻,圓角枚抵,帶顏色的邊框
、3D變換
明场、非矩形范圍
汽摹、透明遮罩
、多級(jí)非線性動(dòng)畫
等苦锨,這也就是開發(fā)者為什么要使用CALayer
的原因 -
UIView
是用來管理CALayer
逼泣,CALayer
才是用來展示
疑問:蘋果為什么要拆分成CALayer
與UIView
兩個(gè)類呢趴泌?
CoreAnimation
是iOS與Mac OS共用的框架,而iOS與Mac OX兩者的用戶交互方式是不同的拉庶,iOS是通過手勢(shì)觸摸嗜憔,Mac OX是通過鍵盤鼠標(biāo);為了兼容兩者氏仗,單獨(dú)把CALayer
拆出來只用來繪制渲染圖形
CALayer
與UIView
的關(guān)系
每一個(gè)UIView
上面都會(huì)有一個(gè)CALayer
作為它的實(shí)例圖層屬性痹筛;我們添加的動(dòng)畫實(shí)際上是針對(duì)CALayer
來做。
Layer Tree
圖層樹(模型數(shù))主要是設(shè)置一些屬性
-
模型樹
( layer tree):程序中接觸最頻繁廓鞠,模型樹的對(duì)象是模型對(duì)象帚稠,儲(chǔ)存著動(dòng)畫的目標(biāo)值;當(dāng)你修改layer的屬性時(shí)床佳,便是通過模型樹上的對(duì)象 -
呈現(xiàn)樹
(presentation tree):包含正在運(yùn)行中的動(dòng)畫的動(dòng)態(tài)值滋早,與模型樹不同,呈現(xiàn)樹始終存儲(chǔ)著layer在屏幕當(dāng)前的狀態(tài)值砌们,呈現(xiàn)樹無(wú)法修改杆麸,只讀;可以通過讀取當(dāng)前值浪感,來做一些其他處理 -
渲染樹
(render tree):執(zhí)行實(shí)際的動(dòng)畫昔头,為CoreAnimation
私有
小結(jié):動(dòng)畫的三個(gè)動(dòng)作創(chuàng)建執(zhí)行動(dòng)畫的CALayer
、創(chuàng)建動(dòng)畫
影兽、添加動(dòng)畫
CALayer常用屬性詳解
動(dòng)畫案例準(zhǔn)備工作:新建空工程CoreAnimation
揭斧,在Main.storyboard
文件拖入一個(gè)UIView
,背景色配置成紅色并進(jìn)行關(guān)連峻堰,命名為redView
動(dòng)畫案例一
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *redView;
@property (nonatomic,strong) CALayer *layer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 新建layer讹开,并添加到self.view.layer上
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(100, 100, 100, 100);
layer.backgroundColor = [UIColor greenColor].CGColor;
_layer = layer;
[self.view.layer addSublayer:layer];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
CABasicAnimation *animation = [CABasicAnimation animation];
// 修改動(dòng)畫y的位置到600
animation.keyPath = @"position.y";
animation.toValue = @600;
animation.duration = 1;
[_redView.layer addAnimation:animation forKey:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
運(yùn)行工程并點(diǎn)擊屏幕,我們會(huì)發(fā)現(xiàn)動(dòng)畫執(zhí)行完畢后捐名,又回到了初始位置旦万,為什么會(huì)這樣?
其實(shí)在執(zhí)行動(dòng)畫的過程中會(huì)有兩個(gè)圖層:layer層
與presentation層
镶蹋,真正移動(dòng)的是presentation層
成艘;動(dòng)畫開始時(shí)會(huì)先把layer層
隱藏,讓presentation層
做動(dòng)畫贺归;動(dòng)畫結(jié)束后presentation層
就會(huì)移除淆两,layer層
再出現(xiàn);原因是視圖的layer層
根本沒有發(fā)生變化牧氮,動(dòng)畫結(jié)束就會(huì)恢復(fù)到原來的狀態(tài)琼腔。
解決辦法:設(shè)置animation
的兩個(gè)屬性
//解決動(dòng)畫恢復(fù)到初始位置
//當(dāng)動(dòng)畫完成后,不把presentation層從render樹中移除(默認(rèn)是移除的)
animation.removedOnCompletion = NO;
//當(dāng)動(dòng)畫結(jié)束后踱葛,把layer層狀態(tài)同步到presentation層丹莲;此時(shí)_redView的frame才會(huì)發(fā)生變化
animation.fillMode = kCAFillModeForwards;
CABasicAnimation
相當(dāng)于是一個(gè)數(shù)據(jù)模型
光坝,把該數(shù)據(jù)模型綁定到layer
上面。
CABasicAnimation
動(dòng)畫的fillMode
屬性介紹
-
kCAFillModeForwards
:動(dòng)畫結(jié)束后甥材,layer會(huì)一直保持動(dòng)畫最后的狀態(tài) -
kCAFillModeBackwards
:動(dòng)畫開始前盯另,只要將動(dòng)畫加入一個(gè)layer
,layer
便立即進(jìn)入動(dòng)畫的初始狀態(tài)并等待動(dòng)畫開始 -
kCAFillModeBoth
:kCAFillModeForwards
與kCAFillModeBackwards
兩者的結(jié)合洲赵,開始前保持動(dòng)畫初始狀態(tài)鸳惯,結(jié)束后保持動(dòng)畫的最后狀態(tài) -
kCAFillModeRemoved
:默認(rèn)屬性
動(dòng)畫案例二:隱式動(dòng)畫
疑問:上面紅色圖層動(dòng)畫結(jié)束恢復(fù)到原來的狀態(tài),恢復(fù)的過程給人的感覺是回彈動(dòng)畫叠萍,這就是隱式動(dòng)畫
?
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
_layer.backgroundColor = [UIColor orangeColor].CGColor;
}
我們沒有給_layer
層添加動(dòng)畫芝发,但是點(diǎn)擊頁(yè)面_layer
層由綠色變成橙色
的過程,有一種動(dòng)畫的效果苛谷,這就是隱式動(dòng)畫
辅鲸;隱式動(dòng)畫是由CoreAnimation
框架幫我們做的,其默認(rèn)動(dòng)畫時(shí)長(zhǎng)是0.25秒
腹殿,通過runloop
來執(zhí)行独悴。上面添加的CABasicAnimation
屬于顯式動(dòng)畫
。
動(dòng)畫案例三:修改隱式動(dòng)畫
如何修改系統(tǒng)的隱式動(dòng)畫
呢锣尉?
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//begin a new transaction
[CATransaction begin];
//設(shè)置隱式動(dòng)畫的時(shí)長(zhǎng)
[CATransaction setAnimationDuration:2.0];
_layer.backgroundColor = [UIColor orangeColor].CGColor;
//動(dòng)畫執(zhí)行完成的回調(diào)
[CATransaction setCompletionBlock:^{
//添加轉(zhuǎn)場(chǎng)動(dòng)畫
//rotate the layer 90 degrees
CGAffineTransform transform = self.layer.affineTransform;
transform = CGAffineTransformRotate(transform, M_PI_2);
self.layer.affineTransform = transform;
}];
[CATransaction commit];
}
CATransaction
類沒有屬性刻炒,也沒有實(shí)例方法;不能通過alloc init
去創(chuàng)建自沧,只能通過begin
坟奥、commit
壓棧出棧的方式來管理。
動(dòng)畫案例四:CALayer
常用屬性 - Contents
- (void)viewDidLoad {
[super viewDidLoad];
//除了UIImageView 能夠顯示圖片,layer也可以加載圖片
UIImage *image = [UIImage imageNamed:@"test.png"];
//不用CGImage的話暂幼,圖片加載不出來
self.view.layer.contents = (__bridge id)(image.CGImage);
//填充方式
self.view.contentMode = UIViewContentModeScaleAspectFit;
self.view.layer.contentsGravity = kCAGravityResizeAspect;
}
Contents
屬性是id
類型筏勒,原因是在Mac OS
系統(tǒng)上Contents
屬性對(duì)CGImage
和NSImage
都會(huì)起作用,image.CGImage
實(shí)際上賦值的是CGImageRef
類型旺嬉,CGImageRef
指向的是CGImage結(jié)構(gòu)
,需要進(jìn)行橋接處理
厨埋,開發(fā)中如果需要設(shè)置背景圖可以使用layer
邪媳;Contents
是id類型就可以直接在layer
的contents
上面加載一張圖片。
-
CALayer
常用屬性 -contentsScale
self.view.layer.contentsScale = [[UIScreen mainScreen] scale];
當(dāng)用代碼設(shè)置contents
圖片時(shí)荡陷,要?動(dòng)設(shè)置圖層的contentsScale
屬性雨效,避免Retina
屏幕顯示錯(cuò)誤。
CALayer
常用屬性 -makeToBounds
makeToBounds
屬性類似于UIView
中的clipsToBounds
屬性废赞,含義:是否顯示超出邊界的內(nèi)容徽龟?
CALayer
常用屬性 -contentsRect
-
contentsRect
不是按點(diǎn)來計(jì)算的,而是按照單位坐標(biāo)
唉地; -
OpenGL
的坐標(biāo)系橫向是從-1到1据悔,縱向從1到-1
的過程传透,center
坐標(biāo)就是{0, 0}
,而手機(jī)都是長(zhǎng)方形的极颓,所以OpenGL
會(huì)把單位坐標(biāo)系
轉(zhuǎn)換為設(shè)備坐標(biāo)系
朱盐,不同設(shè)備有不同的坐標(biāo);
contentsRect
比contentsGravity
屬性要靈活很多菠隆,contentsGravity
屬性只能展示圖片固定的位置與大小兵琳,而contentsRect
可以展示圖片的任意內(nèi)容(只要把單位坐標(biāo)計(jì)算好即可
);如果contentsGravity
不能滿足我們的需求時(shí)骇径,可以使用contentsRect
屬性躯肌。
CALayer中HitTest屬性的實(shí)際使用
下面我們來了解一下UIView
與CALayer
的圖層幾何
frame
是相對(duì)于父視圖的坐標(biāo),bounds
是從視圖自身出發(fā)即內(nèi)部坐標(biāo)
破衔,center
與position
相當(dāng)于父視圖上面的一個(gè)錨點(diǎn)
錨點(diǎn)就是視圖中的center屬性
和position
屬性清女,實(shí)際上就是一個(gè)坐標(biāo),錨點(diǎn)anchorPoint
是layer
的屬性(即position
)运敢。
-
CALayer
常用屬性 -ZPosition
手機(jī)開發(fā)是基于二維平面
的校仑,并不是一個(gè)優(yōu)秀的三維圖形顯示載體,但是手機(jī)中會(huì)出現(xiàn)一些立體的粒子效果传惠,于是CALayer
就提供了一個(gè)屬性ZPosition
迄沫,也就意味著CALayer
是三維的;OpenGL
和Metal
默認(rèn)是一個(gè)3D圖形api卦方,默認(rèn)坐標(biāo)系是三維坐標(biāo)系羊瘩,在描述平面圖形的時(shí)候,z坐標(biāo)是0盼砍;核心動(dòng)畫把z坐標(biāo)
單獨(dú)摘出來就是ZPosition
尘吗;呈現(xiàn)粒子的時(shí)候就必須要用到ZPosition
。
動(dòng)畫案例準(zhǔn)備工作:新建空工程CoreAnimation2
浇坐,在Main.storyboard
文件拖入兩個(gè)UIView
睬捶,背景色配置成橙色
與紅色
并進(jìn)行關(guān)連,命名為view1
與view2
近刘,兩個(gè)view
的層級(jí)關(guān)系如下
// ViewController.h文件
- (void)viewDidLoad {
[super viewDidLoad];
self.view1.layer.zPosition = 1.0;
}
運(yùn)行工程擒贸,我們發(fā)現(xiàn)橙色view
出現(xiàn)在了紅色view
上面,原因是什么呢觉渴?
在平面圖形上面z軸
默認(rèn)值是0
介劫,這里把橙色view
的z軸
值設(shè)置為1
,就意味著把橙色view
放在了上面案淋;修改了zPosition
屬性的值座韵,就更改了深度緩沖區(qū)-深度測(cè)試
,這里主要與深度緩沖區(qū)
有關(guān)踢京,本質(zhì)并不是修改圖層的層級(jí)關(guān)系
誉碴。
-
CALayer
常用屬性 -Hit Testing
動(dòng)畫案例準(zhǔn)備工作:新建空工程CoreAnimation3
宦棺,在Main.storyboard
文件拖入一個(gè)UIView,背景色配置成紅色并進(jìn)行關(guān)連翔烁,命名為layerView
渺氧,如下圖所示
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) UIView *layerView;
@property (strong,nonatomic) CALayer *blueLayer;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//1.Create sublayer
self.blueLayer = [CALayer layer];
self.blueLayer.frame = CGRectMake(0, 0, 100, 100);
self.blueLayer.backgroundColor = [UIColor blueColor].CGColor;
[self.layerView.layer addSublayer:self.blueLayer];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//1.get touchu position relative to main view(獲取相對(duì)于主視圖的觸摸位置)
CGPoint point = [[touches anyObject]locationInView:self.view];
//2.get touched layer
CALayer *layer = [self.layerView.layer hitTest:point];
//3.get layer using using hitTest
if(layer == self.blueLayer)
{
NSLog(@"Inside Blue layer");
} else if (layer == self.layerView.layer) {
NSLog(@"Inside Red layer");
}
}
@end
// 運(yùn)行工程,查看打印日志蹬屹,成功獲取點(diǎn)擊的layer層
2022-09-23 22:25:56.044062+0800 CoreAnimation3[22331:14483795] Inside Blue layer
2022-09-23 22:25:59.342807+0800 CoreAnimation3[22331:14483795] Inside Red layer
CALayer
不能響應(yīng)事件侣背,但是CALayer
的Hit Testing
屬性能夠獲取到點(diǎn)擊的圖層。
hitTest
方法介紹
// point : 在接收器的局部坐標(biāo)系(界)中指定的點(diǎn)
// event : 系統(tǒng)保證調(diào)用此方法的事件慨默。如果從事件處理代碼外部調(diào)用此方法贩耐,則可以指定nil
// returnValue : 視圖對(duì)象是當(dāng)前視圖和包含點(diǎn)的最遠(yuǎn)的后代。
// 如果點(diǎn)完全位于接收方的視圖層次結(jié)構(gòu)之外厦取,則返回nil
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
不止CALayer
中有hitTest
方法潮太,UIView
中同樣有hitTest
方法;UIView
中該方法的作用:在視圖的層次結(jié)構(gòu)中尋找一個(gè)最合適的view
來響應(yīng)觸摸事件虾攻;該方法會(huì)被系統(tǒng)調(diào)用铡买,調(diào)用時(shí)如果返回nil
,即事件被丟棄霎箍,否則返回最合適的view
來響應(yīng)事件奇钞。
-
Hit Test
調(diào)用順序
touch -> UIApplication -> UIWindow -> UIViewController.view -> subViews -> ....-> 合適的view
- 事件的傳遞順序,與
Hit Test
調(diào)用順序剛好相反
view -> superView ...- > UIViewController.view -> UIViewController ->UIWindow -> UIApplication -> 丟棄事件
說明:
- 首先由
view
來嘗試處理事件漂坏,如果處理不了景埃,事件將被傳遞到父視圖superView
-
superView
也嘗試處理事件,如果處理不了顶别,繼續(xù)傳遞給它的父視圖UIViewController.view
-
UIViewController.view
嘗試處理事件谷徙,如果處理不了,把該事件傳遞給UIViewController
-
UIViewController
嘗試處理事件驯绎,如果處理不了完慧,把事件傳遞給UIWindow
- 主窗口
UIWindow
嘗試來處理事件, 如果處理不了剩失,將傳遞給應(yīng)用單例UIApplication
- 如果
UIApplication
也處理不了骗随,該事件將被丟棄
UIView
的Hit Test
底層實(shí)現(xiàn)思路
常見的hitTest不實(shí)現(xiàn)的四種情況
(即view不響應(yīng)事件情況)
view.userInteractionEnabled = NO;
view.hidden = YES;
view.alpha < 0.05;
view 超出 superview 的 bounds;
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
//1.是否響應(yīng)事件的必然性條件
if (self.userInteractionEnabled == NO || self.alpha < 0.05 || self.hidden == YES)
{
return nil;
}
//2.touch的point在self.bounds內(nèi)
if ([self pointInside:point withEvent:event])
{
for (UIView *subView in self.subviews)
{
//進(jìn)行坐標(biāo)轉(zhuǎn)化
CGPoint coverPoint = [subView convertPoint:point fromView:self];
// 調(diào)用子視圖的 hitTest 重復(fù)上面的步驟。找到了赴叹,返回hitTestview ,沒找到返回有自身處理
UIView *hitTestView = [subView hitTest:coverPoint withEvent:event];
if (hitTestView)
{
return hitTestView;
}
}
return self;
}
return nil;
}
Hit Testing
應(yīng)?場(chǎng)景-?視圖超出?視圖范圍
,點(diǎn)擊沒有響應(yīng)指蚜;如果需求是讓超出父視圖的范圍也能點(diǎn)擊乞巧,代碼實(shí)現(xiàn)如下
仿射變換數(shù)學(xué)原理講解
-
剛體變換
:只有物體的位置
(平移變換)和朝向
(旋轉(zhuǎn)變換)發(fā)生改變,而形狀不變摊鸡;剛性變換是最一般的變換绽媒。 -
仿射變換
:仿射變換具有兩個(gè)旋轉(zhuǎn)因子
和兩個(gè)縮放因子
蚕冬,因此具有6個(gè)自由度
。不具有保角性和保持距離比的性質(zhì)是辕,但是原圖平行線變換后仍然是平行線囤热。仿射變換主要包括平移變換
、旋轉(zhuǎn)變換
获三、縮放變換
(也叫尺度變換)旁蔼、傾斜變換
(也叫錯(cuò)切變換、剪切變換疙教、偏移變換)棺聊、翻轉(zhuǎn)變換
,有六個(gè)自由度贞谓。 -
投影變換
:是最一般的線性變換限佩,有8個(gè)自由度
;射影變換保持重合關(guān)系和交比不變裸弦。但不會(huì)保持平行性祟同。即它會(huì)使得仿射變換產(chǎn)生非線性效應(yīng)
。
對(duì)于復(fù)雜的立體圖形理疙,我們要想平移是非常困難的晕城;但是通過仿射變換
,我們就可以很容易的實(shí)現(xiàn)沪斟,可以對(duì)立體圖形的任意頂點(diǎn)進(jìn)行平移广辰,實(shí)現(xiàn)代碼如下圖所示:
下面我們介紹官方文檔中的幾個(gè)矩陣
上圖展現(xiàn)了常見的transformations
的矩陣配置;任何乘以identity
矩陣的coordinate
將不會(huì)變化主之,當(dāng)乘以其他矩陣時(shí)择吊,coordinate
的變化和矩陣每個(gè)分量都有關(guān);例如槽奕,沿著X軸平移几睛,我們需要提供非零的 tx 分量
并讓ty
和tz
為0;對(duì)于旋轉(zhuǎn)操作粤攒,我們應(yīng)該提供合適的 sine
和 cosine
值所森。
-
Identity
:?jiǎn)卧仃?/li> -
Translate
:平移 -
Scale
:縮放 -
Rotate around X axis
:圍繞X
軸旋轉(zhuǎn),X值不變夯接;這里的四維
原因是OpenGL ES/Metal
中描述頂點(diǎn)除了圍繞X
焕济、Y
、Z
軸盔几,還有一個(gè)W
縮放因子晴弃。 -
Rotate around Y axis
:圍繞Y
軸旋轉(zhuǎn),Y值不變 -
Rotate around Z axis
:圍繞Z
軸旋轉(zhuǎn),Z值不變
圍繞任意軸旋轉(zhuǎn)
中參數(shù)n
表示向量(x,y,z)
上鞠,第二個(gè)參數(shù)表示角度
际邻。