国产chinesehdxxxx野外,国产av无码专区亚洲av琪琪,播放男人添女人下边视频,成人国产精品一区二区免费看,chinese丰满人妻videos

5.2 3D變換

2018-02-24 14:50 更新

3D變換

CG的前綴告訴我們,CGAffineTransform類型屬于Core Graphics框架,Core Graphics實際上是一個嚴格意義上的2D繪圖API,并且CGAffineTransform僅僅對2D變換有效。

在第三章中,我們提到了zPosition屬性,可以用來讓圖層靠近或者遠離相機(用戶視角),transform屬性(CATransform3D類型)可以真正做到這點,即讓圖層在3D空間內(nèi)移動或者旋轉。

CGAffineTransform類似,CATransform3D也是一個矩陣,但是和2x3的矩陣不同,CATransform3D是一個可以在3維空間內(nèi)做變換的4x4的矩陣(圖5.6)。

圖5.7 X,Y,Z軸,以及圍繞它們旋轉的方向

由圖所見,繞Z軸的旋轉等同于之前二維空間的仿射旋轉,但是繞X軸和Y軸的旋轉就突破了屏幕的二維空間,并且在用戶視角看來發(fā)生了傾斜。

舉個例子:清單5.4的代碼使用了CATransform3DMakeRotation對視圖內(nèi)的圖層繞Y軸做了45度角的旋轉,我們可以把視圖向右傾斜,這樣會看得更清晰。

結果見圖5.8,但并不像我們期待的那樣。

清單5.4 繞Y軸旋轉圖層

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //rotate the layer 45 degrees along the Y axis
    CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
    self.layerView.layer.transform = transform;
}

@end

圖5.9?CATransform3Dm34元素,用來做透視

m34的默認值是0,我們可以通過設置m34為-1.0 /?d來應用透視效果,d代表了想象中視角相機和屏幕之間的距離,以像素為單位,那應該如何計算這個距離呢?實際上并不需要,大概估算一個就好了。

因為視角相機實際上并不存在,所以可以根據(jù)屏幕上的顯示效果自由決定它的防止的位置。通常500-1000就已經(jīng)很好了,但對于特定的圖層有時候更小后者更大的值會看起來更舒服,減少距離的值會增強透視效果,所以一個非常微小的值會讓它看起來更加失真,然而一個非常大的值會讓它基本失去透視效果,對視圖應用透視的代碼見清單5.5,結果見圖5.10。

清單5.5 對變換應用透視效果

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //create a new transform
    CATransform3D transform = CATransform3DIdentity;
    //apply perspective
    transform.m34 = - 1.0 / 500.0;
    //rotate by 45 degrees along the Y axis
    transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
    //apply to layer
    self.layerView.layer.transform = transform;
}

@end

圖5.11 滅點

Core Animation定義了這個點位于變換圖層的anchorPoint(通常位于圖層中心,但也有例外,見第三章)。這就是說,當圖層發(fā)生變換時,這個點永遠位于圖層變換之前anchorPoint的位置。

當改變一個圖層的position,你也改變了它的滅點,做3D變換的時候要時刻記住這一點,當你視圖通過調(diào)整m34來讓它更加有3D效果,應該首先把它放置于屏幕中央,然后通過平移來把它移動到指定位置(而不是直接改變它的position),這樣所有的3D圖層都共享一個滅點。

sublayerTransform屬性

如果有多個視圖或者圖層,每個都做3D變換,那就需要分別設置相同的m34值,并且確保在變換之前都在屏幕中央共享同一個position,如果用一個函數(shù)封裝這些操作的確會更加方便,但仍然有限制(例如,你不能在Interface Builder中擺放視圖),這里有一個更好的方法。

CALayer有一個屬性叫做sublayerTransform。它也是CATransform3D類型,但和對一個圖層的變換不同,它影響到所有的子圖層。這意味著你可以一次性對包含這些圖層的容器做變換,于是所有的子圖層都自動繼承了這個變換方法。

相較而言,通過在一個地方設置透視變換會很方便,同時它會帶來另一個顯著的優(yōu)勢:滅點被設置在容器圖層的中點,從而不需要再對子圖層分別設置了。這意味著你可以隨意使用positionframe來放置子圖層,而不需要把它們放置在屏幕中點,然后為了保證統(tǒng)一的滅點用變換來做平移。

我們來用一個demo舉例說明。這里用Interface Builder并排放置兩個視圖(圖5.12),然后通過設置它們?nèi)萜饕晥D的透視變換,我們可以保證它們有相同的透視和滅點,代碼見清單5.6,結果見圖5.13。

圖5.13 通過相同的透視效果分別對視圖做變換

背面

我們既然可以在3D場景下旋轉圖層,那么也可以從背面去觀察它。如果我們在清單5.4中把角度修改為M_PI(180度)而不是當前的M_PI_4(45度),那么將會把圖層完全旋轉一個半圈,于是完全背對了相機視角。

那么從背部看圖層是什么樣的呢,見圖5.14

圖5.15 反方向變換的嵌套圖層

注意做了-45度旋轉的內(nèi)部圖層是怎樣抵消旋轉45度的圖層,從而恢復正常狀態(tài)的。

如果內(nèi)部圖層相對外部圖層做了相反的變換(這里是繞Z軸的旋轉),那么按照邏輯這兩個變換將被相互抵消。

驗證一下,相應代碼見清單5.7,結果見5.16

清單5.7 繞Z軸做相反的旋轉變換

@interface ViewController ()

@property (nonatomic, weak) IBOutlet UIView *outerView;
@property (nonatomic, weak) IBOutlet UIView *innerView;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    //rotate the outer layer 45 degrees
    CATransform3D outer = CATransform3DMakeRotation(M_PI_4, 0, 0, 1);
    self.outerView.layer.transform = outer;
    //rotate the inner layer -45 degrees
    CATransform3D inner = CATransform3DMakeRotation(-M_PI_4, 0, 0, 1);
    self.innerView.layer.transform = inner;
}

@end

圖5.17 繞Y軸做相反旋轉的預期結果。

但其實這并不是我們所看到的,相反,我們看到的結果如圖5.18所示。發(fā)什么了什么呢?內(nèi)部的圖層仍然向左側旋轉,并且發(fā)生了扭曲,但按道理說它應該保持正面朝上,并且顯示正常的方塊。

這是由于盡管Core Animation圖層存在于3D空間之內(nèi),但它們并不都存在同一個3D空間。每個圖層的3D場景其實是扁平化的,當你從正面觀察一個圖層,看到的實際上由子圖層創(chuàng)建的想象出來的3D場景,但當你傾斜這個圖層,你會發(fā)現(xiàn)實際上這個3D場景僅僅是被繪制在圖層的表面。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號