OpenGL + OpenGL ES +Metal 系列文章彙總
在不會OpenGL ES的情況下,如何利用CoreAnimation實作一個立方體,并旋轉,整體效果如下
整體實作的思路如下
主要分為兩部分
- ViewDidLoad函數:初始化工作
- update更新:定時器實作旋轉
ViewDidLoad函數
初始化工作包含兩部分:
- addFaces:添加6個面,通過變換組合成立方體
- addCADisplayLink:添加定時器,并放入runloop
addFaces函數
這部分主要是将6個面作相應的變換添加到容器中
- OC版本
//添加面
- (void)addFaces{
self.faces = @[_view0, _view1, _view2, _view3, _view4, _view5];
// 主view
CATransform3D perspective = CATransform3DIdentity;
// 核心動畫設定透視投影
perspective.m34 = -1.0 / 500.0;
// 圍繞x,y分别旋轉,M_PI_4 = π/4,π=180°
// x:順時針旋轉45°,y:順時針旋轉45°
perspective = CATransform3DRotate(perspective, -M_PI_4, 1, 0, 0);
perspective = CATransform3DRotate(perspective, -M_PI_4, 0, 1, 0);
self.containerView.layer.sublayerTransform = perspective;
//添加face1
// z軸平移100
// (除了第一個視圖外,其餘的視圖都是基于第一個視圖的位置進行平移+旋轉的)
CATransform3D transform = CATransform3DMakeTranslation(0, 0, 100);
[self addFace:0 withTransform:transform];
添加face2 --平移y+旋轉y
transform = CATransform3DMakeTranslation(100, 0, 0);
transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
[self addFace:1 withTransform:transform];
//
// 添加face3 -- 平移y+旋轉x
transform = CATransform3DMakeTranslation(0, -100, 0);
transform = CATransform3DRotate(transform, M_PI_2, 1, 0, 0);
// [self addFace:2 withTransform:transform];
// 添加face4 -- 平移y+旋轉x
transform = CATransform3DMakeTranslation(0, 100, 0);
transform = CATransform3DRotate(transform, -M_PI_2, 1, 0, 0);
[self addFace:3 withTransform:transform];
// 添加face5 -- 平移+旋轉
transform = CATransform3DMakeTranslation(-100, 0, 0);
transform = CATransform3DRotate(transform, -M_PI_2, 0, 1, 0);
[self addFace:4 withTransform:transform];
// 添加face6 -- 平移z+旋轉y
transform = CATransform3DMakeTranslation(0, 0, -100);
transform = CATransform3DRotate(transform, M_PI, 0, 1, 0);
[self addFace:5 withTransform:transform];
}
- (void)addFace: (NSInteger)index withTransform: (CATransform3D)transform
{
// 擷取face視圖,并将其加入容器中
UIView *face = self.faces[index];
[self.containerView addSubview:face];
// 将face視圖放在容器的中心
CGSize containerSize = self.containerView.bounds.size;
face.center = CGPointMake(containerSize.width/2.0, containerSize.height/2.0);
// 添加tansform,tansform就是一個矩陣
face.layer.transform = transform;
}
- Swift版本
fileprivate func addFaces(){
faces = [view0, view1, view2, view3, view4, view5]
// 父view的layer圖層
var perspective: CATransform3D = CATransform3DIdentity
perspective.m34 = -1.0 / 500.0
perspective = CATransform3DRotate(perspective, -.pi/4, 1, 0, 0)
perspective = CATransform3DRotate(perspective, -.pi/4, 0, 1, 0)
self.containerView.layer.sublayerTransform = perspective
// 添加face1
var transform = CATransform3DMakeTranslation(0, 0, 100)
self.addFaceWithTransform(0, transform)
// 添加face2
transform = CATransform3DMakeTranslation(100, 0, 0)
transform = CATransform3DRotate(transform, .pi/2, 0, 1, 0)
self.addFaceWithTransform(1, transform)
// 添加face3
transform = CATransform3DMakeTranslation(0, -100, 0)
// transform = CATransform3DRotate(transform, .pi/2, 1, 0, 0)
// self.addFaceWithTransform(2, transform)
//
// 添加face4
transform = CATransform3DMakeTranslation(0, 100, 0)
transform = CATransform3DRotate(transform, -.pi/2, 1, 0, 0)
self.addFaceWithTransform(3, transform)
//
// 添加face5
transform = CATransform3DMakeTranslation(-100, 0, 0)
// transform = CATransform3DRotate(transform, -.pi/2, 0, 1, 0)
self.addFaceWithTransform(4, transform)
//
添加face6
// transform = CATransform3DMakeTranslation(0, 0, -100)
// transform = CATransform3DRotate(transform, .pi, 0, 1, 0)
// self.addFaceWithTransform(5, transform)
}
private func addFaceWithTransform(_ index: Int, _ transform: CATransform3D){
// 擷取face,并加入容器中
let face = self.faces[index]
self.containerView.addSubview(face)
// 将face視圖放入容器的中心
let containerSize = self.containerView.bounds.size
face.center = CGPoint(x: containerSize.width/2, y: containerSize.height/2)
// 添加transform
face.layer.transform = transform
}
addCADisplayLink函數
這部分主要初始化定時器,并将定時器加入runloop循環中
- OC版本
//添加定時器
- (void)addCADisplayLink{
self.angle = 0;
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
- Swift版本
fileprivate func addCADisplayLink(){
self.displayLink.add(to: RunLoop.main, forMode: .common)
}
update更新
主要是計算旋轉度數,并将容器的子layer圍繞任意方向旋轉
- OC版本
- (void)update{
// 計算旋轉度數
self.angle = (self.angle + 5) % 360;
// 将度數轉化為弧度
float deg = self.angle * (M_PI / 180);
CATransform3D temp = CATransform3DIdentity;
// 圍繞(0.3, 1, 0.7)方向旋轉
temp = CATransform3DRotate(temp, deg, 0.3, 1, 0.7);
// 旋轉容器的子layer
self.containerView.layer.sublayerTransform = temp;
}
- Swift版本
@objc fileprivate func update(){
self.angle = (self.angle+5).truncatingRemainder(dividingBy: 360)
let deg = self.angle * (.pi/180)
var temp = CATransform3DIdentity
temp = CATransform3DRotate(temp, CGFloat(deg), 0.3, 1, 0.7)
self.containerView.layer.sublayerTransform = temp
}
完整的代碼見github - 09_CoreAnimation_立方體+旋轉_OC、09_CoreAnimation_立方體+旋轉_Swift,分别提供了OC和Swift版本