第十六節(jié)—GLKit使用索引繪圖

本文為L_Ares個人寫作片迅,如需轉載請表明原文出處浪谴。

邏輯和GLSL是一樣的值骇,只不過GLKit提供了GLKBaseEffect道盏,所以不用自己來實現(xiàn)shader的代碼而柑,其他的邏輯是一模一樣的文捶。

直接上代碼,如果有需要的小伙伴記得仔細看備注媒咳,我覺得非常的詳細了粹排。

//
//  ViewController.m
//  06GLKit索引繪圖
//
//  Created by EasonLi on 2020/10/10.
//

#import "ViewController.h"

@interface ViewController ()

//圖形上下文
@property (nonatomic,strong) EAGLContext *myContext;

//渲染效果設置器
@property (nonatomic,strong) GLKBaseEffect *myEffect;

//要繪制的三角形的數(shù)量
@property (nonatomic,assign) GLint count;

//繞X軸的旋轉弧度
@property (nonatomic,assign) GLfloat xDegree;
//繞Y軸的旋轉弧度
@property (nonatomic,assign) GLfloat yDegree;
//繞Z軸的旋轉弧度
@property (nonatomic,assign) GLfloat zDegree;

//是否繞X軸旋轉
@property (nonatomic,assign) BOOL roundX;
//是否繞Y軸旋轉
@property (nonatomic,assign) BOOL roundY;
//是否繞Z軸旋轉
@property (nonatomic,assign) BOOL roundZ;

//定時器
@property (nonatomic,strong) dispatch_source_t timer;

@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    //初始化變量
    [self initialData];
    
    //設置圖層和上下文
    [self setUpContextAndLayer];
    
    [self toRenderScence];
    
    // Do any additional setup after loading the view.
}

#pragma mark - 初始化數(shù)據(jù)
- (void)initialData
{
    self.myContext = nil;
    self.myEffect = nil;
    self.count = 0;
    self.xDegree = 0.f;
    self.yDegree = 0.f;
    self.zDegree = 0.f;
    self.roundX = NO;
    self.roundY = NO;
    self.roundZ = NO;
    double seconds = 0.1;
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(self.timer, DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC, 0.0 * NSEC_PER_SEC);
}

#pragma mark - 設置圖層和上下文
- (void)setUpContextAndLayer
{
    //新建圖形上下文
    self.myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
    
    //將controller的view直接賦值給GLKView,創(chuàng)建GLKView
    GLKView *view = (GLKView *)self.view;
    //設置view的上下文
    view.context = self.myContext;
    //設置圖層的顏色格式
    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
    //設置圖層的深度緩沖區(qū)大小
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    
    //設置當前圖形的上下文是myContext
    [EAGLContext setCurrentContext:self.myContext];
    
    //開啟深度測試
    glEnable(GL_DEPTH_TEST);
    
}

#pragma mark - 渲染圖形
- (void)toRenderScence
{
    
    //設置頂點數(shù)組
    /**
     前3個數(shù)據(jù)是頂點坐標
     中間3個數(shù)據(jù)是頂點顏色
     最后2個是紋理坐標
     */
    GLfloat vertexArr[] =
    {
        //左上
        -0.5f,0.5f,0.f,   0.f,0.f,0.5f,   0.f,1.f,
        //右上
        0.5f,0.5f,0.f,    0.f,0.5f,0.f,   1.f,1.f,
        //左下
        -0.5f,-0.5f,0.f,  0.5f,0.f,0.f,   0.f,0.f,
        //右下
        0.5f,-0.5f,0.f,   0.5f,0.5f,0.f,  1.f,0.f,
        //中間頂點
        0.f,0.f,0.8f,      0.5f,0.5f,0.5f,  0.5f,0.5f
    };

    //索引數(shù)組
    GLuint indexArr[] =
    {
        0,3,2,
        0,1,3,
        0,2,4,
        0,4,1,
        1,4,3,
        2,3,4
    };
    
    //要繪制的三角形個數(shù)
    self.count = sizeof(indexArr) / sizeof(GLuint);
    
    //將頂點數(shù)組放入數(shù)組類型的頂點緩沖區(qū)
    GLuint vertexBuffer;
    //申請緩沖區(qū)
    glGenBuffers(1, &vertexBuffer);
    //綁定緩沖區(qū)
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    //創(chuàng)建并初始化緩沖區(qū)對象
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexArr), &vertexArr, GL_STATIC_DRAW);
    
    //將索引數(shù)組放入索引緩沖區(qū)
    GLuint indexBuffer;
    //申請緩沖區(qū)
    glGenBuffers(1, &indexBuffer);
    //綁定緩沖區(qū)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    //創(chuàng)建并初始化緩沖區(qū)對象
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexArr), indexArr, GL_STATIC_DRAW);
    
    //打開頂點屬性通道
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    //設置頂點數(shù)據(jù)的讀取方式
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, NULL);
    
    //打開顏色屬性通道
    glEnableVertexAttribArray(GLKVertexAttribColor);
    //設置顏色數(shù)據(jù)的讀取方式
    glVertexAttribPointer(GLKVertexAttribColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 3);
    
    //打開紋理屬性通道
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    //設置紋理數(shù)據(jù)的讀取方式
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (GLfloat *)NULL + 6);
    
    //載入紋理并且使用GLKBaseEffect
    [self loadTextureAndSetEffect];
    
    //設置投影矩陣和模型視圖矩陣
    [self setUpModelViewProjectionMatrix];
    
    //開啟GCD的定時器
    [self startGCDTimer];
    
}

- (void)loadTextureAndSetEffect
{
    //獲取紋理文件的路徑
    NSString *textureFile = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"png"];
    //設置紋理坐標的原點為左下角
    NSDictionary *optional = @{GLKTextureLoaderOriginBottomLeft:@1};
    //初始化紋理信息
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:textureFile options:optional error:nil];
    
    //初始化GLKBaseEffect對象
    self.myEffect = [[GLKBaseEffect alloc] init];
    //允許使用第一個紋理
    self.myEffect.texture2d0.enabled = GL_TRUE;
    //紋理名稱
    self.myEffect.texture2d0.name = textureInfo.name;
    
}

- (void)setUpModelViewProjectionMatrix
{
    //計算寬高比
    CGSize size = self.view.bounds.size;
    //fabs就是C中的返回絕對值
    float aspect = fabs(size.width/size.height);
    //計算投影矩陣
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(90.f), aspect, 0.1f, 10.f);
    /**
     就是設置縮放的涩澡,用不用都行顽耳,隨意,當然有想要翻轉各軸的的話筏养,可以使用
     projectionMatrix = GLKMatrix4Scale(projectionMatrix, 1.0f, 1.0f, 1.0f);
     */
    //設置透視投影的投影矩陣
    self.myEffect.transform.projectionMatrix = projectionMatrix;
    
    //設置模型視圖矩陣,可以選擇稍微平移一下斧抱,不想要平移一下的話常拓,可以直接初始化
    //那就是一個單元矩陣渐溶,平移用GLKMatrix4Translate函數(shù)
    GLKMatrix4 modelViewMatrix = GLKMatrix4Identity;
    
    //設置模型視圖矩陣
    self.myEffect.transform.modelviewMatrix = modelViewMatrix;
    
}

- (void)startGCDTimer
{
    dispatch_source_set_event_handler(self.timer, ^{
        self.xDegree += 0.1 * self.roundX;
        self.yDegree += 0.1 * self.roundY;
        self.zDegree += 0.1 * self.roundZ;
    });
    dispatch_resume(self.timer);
}

#pragma mark - GLKViewController的代理
//如果Controller是GLKViewController的子類,并且提供了實現(xiàn)弄抬,那么就用update茎辐,不然
//就用glkViewControllerUpdate
- (void)update
{
    //旋轉就是把模型視圖矩陣乘以旋轉矩陣,然后再把模型視圖矩陣重新賦值給
    //GLKBaseEffect的modelviewMatrix
    
    //所以先初始化一個新的modelview矩陣
    //把金字塔移動一些掂恕,不然看不到了
    GLKMatrix4 modelViewMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0f, 0.0f, -3.0f);
    //X軸變換
    modelViewMatrix = GLKMatrix4RotateX(modelViewMatrix, self.xDegree);
    //Y軸變換
    modelViewMatrix = GLKMatrix4RotateY(modelViewMatrix, self.yDegree);
    //Z軸變換
    modelViewMatrix = GLKMatrix4RotateZ(modelViewMatrix, self.zDegree);
    
    //賦值給GLKBaseEffect對象的modelViewMatrix
    self.myEffect.transform.modelviewMatrix = modelViewMatrix;
    
}

#pragma mark - GLKView的代理
//用來繪制的拖陆,就是渲染,按照渲染的步驟來
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    //設置清屏顏色
    glClearColor(0.3f, 0.3f, 0.3f, 1.f);
    //清空緩沖區(qū)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    //一定要記得GLKBaseEffect在繪制前要使用prepareToDraw
    [self.myEffect prepareToDraw];
    
    //利用索引繪圖開始繪制
    //最后一個參數(shù)是索引數(shù)組的地址懊亡,但是我們直接把索引都傳入了索引緩沖區(qū)里面了依啰,所以
    //直接寫0就得了,反正也不從那里獲取店枣。
    glDrawElements(GL_TRIANGLES, self.count, GL_UNSIGNED_INT, 0);
}

- (IBAction)xClick:(id)sender {
    self.roundX = !self.roundX;
}

- (IBAction)yClick:(id)sender {
    self.roundY = !self.roundY;
}

- (IBAction)zClick:(id)sender {
    self.roundZ = !self.roundZ;
}

#pragma mark - 銷毀
- (void)dealloc{
    
    if ([EAGLContext currentContext] == self.myContext) {
        [EAGLContext setCurrentContext:nil];
    }
    
    dispatch_source_cancel(_timer);
    _timer = nil;
    
}

@end

效果圖如下圖1.1所示:

1.1.png
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末速警,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸯两,更是在濱河造成了極大的恐慌闷旧,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钧唐,死亡現(xiàn)場離奇詭異忙灼,居然都是意外死亡,警方通過查閱死者的電腦和手機钝侠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門该园,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人帅韧,你說我怎么就攤上這事里初。” “怎么了弱匪?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵青瀑,是天一觀的道長璧亮。 經常有香客問我,道長斥难,這世上最難降的妖魔是什么枝嘶? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮哑诊,結果婚禮上群扶,老公的妹妹穿的比我還像新娘。我一直安慰自己镀裤,他們只是感情好竞阐,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著暑劝,像睡著了一般骆莹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上担猛,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天幕垦,我揣著相機與錄音,去河邊找鬼傅联。 笑死先改,一個胖子當著我的面吹牛,可吹牛的內容都是我干的蒸走。 我是一名探鬼主播仇奶,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼比驻!你這毒婦竟也來了该溯?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤嫁艇,失蹤者是張志新(化名)和其女友劉穎朗伶,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體步咪,經...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡论皆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了猾漫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片点晴。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖悯周,靈堂內的尸體忽然破棺而出粒督,到底是詐尸還是另有隱情,我是刑警寧澤禽翼,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布屠橄,位于F島的核電站族跛,受9級特大地震影響,放射性物質發(fā)生泄漏锐墙。R本人自食惡果不足惜礁哄,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望溪北。 院中可真熱鬧桐绒,春花似錦、人聲如沸之拨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蚀乔。三九已至烁竭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乙墙,已是汗流浹背颖变。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工生均, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留听想,地道東北人马胧。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓汉买,卻偏偏與公主長得像,于是被迫代替她去往敵國和親佩脊。 傳聞我的和親對象是個殘疾皇子蛙粘,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348