九慨亲、OpenGL ES/Core Animation立方體貼圖+旋轉(zhuǎn)

1.OpenGL ES

1.1 透視投影

GLfloat vertexData[] = {
    0.5, -0.5, 0.0f,    1.0f, 0.0f, //右下
    0.5, 0.5,  0.0f,    1.0f, 1.0f, //右上
    -0.5, 0.5, 0.0f,    0.0f, 1.0f, //左上
    
    0.5, -0.5, 0.0f,    1.0f, 0.0f, //右下
    -0.5, 0.5, 0.0f,    0.0f, 1.0f, //左上
    -0.5, -0.5, 0.0f,   0.0f, 0.0f, //左下
};

雖然我們的代碼看起來是繪制了一個正方形戈锻,但由于視口(視圖)寬高比的問題產(chǎn)生了拉伸問題。如下圖所示:

為了解決這個問題轩性,我們可以設置透視投影矩陣声登。又由于平截頭體可視范圍的問題,我們需要將頂點向后移4.0單位揣苏。

CGFloat aspect = fabs(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0), aspect, 0.1, 100.0);
_baseEffect.transform.projectionMatrix = projectionMatrix;
    
GLKMatrix4 modelviewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, -4.0);
_baseEffect.transform.modelviewMatrix = modelviewMatrix;

2.1 立方體貼圖+旋轉(zhuǎn)

解決了上面的問題悯嗓,完成立方體貼圖+旋轉(zhuǎn)就很簡單了。

  • 寫好立方體的頂點位置卸察。
  • - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect 會不斷回調(diào)脯厨,在里面更新模型視圖變換矩陣就可以了。
OpenGL ES
@interface DemoViewController ()
{
    EAGLContext *_context;
    GLKBaseEffect *_baseEffect;
    int _angle;
}
@end

@implementation DemoViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //1.OpenGL ES 相關(guān)初始化
    [self setUpConfig];
    //2.加載頂點/紋理坐標數(shù)據(jù)
    [self setUpVertexData];
    //3.加載紋理數(shù)據(jù)(使用GLBaseEffect)
    [self setUpTexture];
}

-(void)setUpTexture
{
    NSString *filePath = [[NSBundle mainBundle]pathForResource:@"qiyu" ofType:@"jpg"];
    
    NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft : @(YES)};
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
    // 紋理設置
    _baseEffect = [[GLKBaseEffect alloc] init];
    _baseEffect.texture2d0.enabled = GL_TRUE;
    _baseEffect.texture2d0.name = textureInfo.name;
    // 透視投影矩陣
    CGFloat aspect = fabs(self.view.bounds.size.width / self.view.bounds.size.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0), aspect, 0.1, 100.0);
    _baseEffect.transform.projectionMatrix = projectionMatrix;
}

-(void)setUpVertexData
{
    GLfloat vertices[] = {
        -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
        0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
        0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
        0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
        -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
        
        -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
        0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
        0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
        0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
        -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
        -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
        
        -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
        -0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
        -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
        -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
        -0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
        
        0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
        0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
        0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
        0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
        0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
        0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
        
        -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
        0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
        0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
        0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
        -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
        -0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
        
        -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
        0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
        0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
        0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
        -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
        -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
    };
    // 頂點緩存
    GLuint bufferID;
    glGenBuffers(1, &bufferID);
    glBindBuffer(GL_ARRAY_BUFFER, bufferID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    //頂點坐標數(shù)據(jù)
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 0);
    //紋理坐標數(shù)據(jù)
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
}

- (void)setUpConfig
{
    _context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES3];
    if (!_context) {
        NSLog(@"Create ES context Failed");
    }
    //設置當前上下文
    [EAGLContext setCurrentContext:_context];
    
    GLKView *view =(GLKView *) self.view;
    view.context = _context;
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat16;
    
    glClearColor(0.8, 0.8, 0.8, 1.0);
}

#pragma mark -- GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // 更新旋轉(zhuǎn)
    [self update];
    [_baseEffect prepareToDraw];
    glDrawArrays(GL_TRIANGLES, 0, 48);
}

- (void)update {
    _angle = (_angle + 2) % 360;
    GLKMatrix4 modelviewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0, 0, -4.0);
    modelviewMatrix = GLKMatrix4Rotate(modelviewMatrix, GLKMathDegreesToRadians(_angle), 0.3, 0.5, 0.7);
    _baseEffect.transform.modelviewMatrix = modelviewMatrix;
}

@end

2. Core Animation

使用 Core Animation 完成上面的功能也非常簡單坑质,利用layer.transform的數(shù)據(jù)結(jié)構(gòu)CATransform3D即可完成3D變換合武。

值得一提的是,為了實現(xiàn)立方體整體的旋轉(zhuǎn)動畫涡扼,我們不需要為為一個面都專門做變換稼跳。我們只需要將它們放在同一個父視圖中,利用父視圖的layer.sublayerTransform即可對所有子視圖進行統(tǒng)一變換吃沪。

Core Animation
@interface ViewController ()

@property (nonatomic, strong) UIView *containerView;

@end

@implementation ViewController

- (void)addFace:(int)index withTransform:(CATransform3D)transform
{
    NSString *filePath = [[NSBundle mainBundle]pathForResource:@"qiyu" ofType:@"jpg"];
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    imageView.image = [UIImage imageWithContentsOfFile:filePath];
    [self.containerView addSubview:imageView];
    CGSize containerSize = self.containerView.bounds.size;
    imageView.center = CGPointMake(containerSize.width / 2.0, containerSize.height / 2.0);
    // 變換
    imageView.layer.transform = transform;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = UIColor.lightGrayColor;
    
    self.containerView = [[UIView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:self.containerView];
    
    //add cube face 1
    CATransform3D transform = CATransform3DMakeTranslation(0, 0, 100);
    [self addFace:0 withTransform:transform];
    //add cube face 2
    transform = CATransform3DMakeTranslation(100, 0, 0);
    transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
    [self addFace:1 withTransform:transform];
    //add cube face 3
    transform = CATransform3DMakeTranslation(0, -100, 0);
    transform = CATransform3DRotate(transform, M_PI_2, 1, 0, 0);
    [self addFace:2 withTransform:transform];
    //add cube face 4
    transform = CATransform3DMakeTranslation(0, 100, 0);
    transform = CATransform3DRotate(transform, -M_PI_2, 1, 0, 0);
    [self addFace:3 withTransform:transform];
    //add cube face 5
    transform = CATransform3DMakeTranslation(-100, 0, 0);
    transform = CATransform3DRotate(transform, -M_PI_2, 0, 1, 0);
    [self addFace:4 withTransform:transform];
    //add cube face 6
    transform = CATransform3DMakeTranslation(0, 0, -100);
    transform = CATransform3DRotate(transform, M_PI, 0, 1, 0);
    [self addFace:5 withTransform:transform];
    
    __block int step = 0;
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0/60.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        step = (step + 2) % 360;
        self.containerView.layer.sublayerTransform = CATransform3DMakeRotation(M_PI / 180.0 * step, -0.3, 0.5, -0.7);
    }];
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

@end
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末汤善,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌红淡,老刑警劉巖不狮,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異在旱,居然都是意外死亡摇零,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門颈渊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遂黍,“玉大人,你說我怎么就攤上這事俊嗽∥砑遥” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵绍豁,是天一觀的道長芯咧。 經(jīng)常有香客問我,道長竹揍,這世上最難降的妖魔是什么敬飒? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮芬位,結(jié)果婚禮上无拗,老公的妹妹穿的比我還像新娘。我一直安慰自己昧碉,他們只是感情好英染,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著被饿,像睡著了一般四康。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狭握,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天闪金,我揣著相機與錄音,去河邊找鬼论颅。 笑死哎垦,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的恃疯。 我是一名探鬼主播漏设,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼澡谭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蛙奖,失蹤者是張志新(化名)和其女友劉穎潘酗,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雁仲,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡仔夺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了攒砖。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缸兔。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖吹艇,靈堂內(nèi)的尸體忽然破棺而出惰蜜,到底是詐尸還是另有隱情,我是刑警寧澤受神,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布抛猖,位于F島的核電站,受9級特大地震影響鼻听,放射性物質(zhì)發(fā)生泄漏财著。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一撑碴、第九天 我趴在偏房一處隱蔽的房頂上張望撑教。 院中可真熱鬧,春花似錦醉拓、人聲如沸伟姐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玫镐。三九已至,卻和暖如春怠噪,著一層夾襖步出監(jiān)牢的瞬間恐似,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工傍念, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矫夷,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓憋槐,卻偏偏與公主長得像双藕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子阳仔,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355