OpenGL ES 之 GLSL和濾鏡

  • 著色器的渲染過(guò)程
    在渲染過(guò)程中,必須存儲(chǔ)2中著色器,分別是頂點(diǎn)著色器、片元著色器。頂點(diǎn)著色器是第一個(gè)著色器、片元著色器是最后一個(gè)。頂點(diǎn)著色器處理頂點(diǎn)、片元著色器處理像素點(diǎn)顏色。
//
//  ViewController.m
//  OpenGL ES GLKitView
//
//  Created by apple on 2019/11/27.
//  Copyright ? 2019年 apple. All rights reserved.
//

#import "ViewController.h"
#import <GLKit/GLKit.h>

typedef struct {
    GLKVector3  positionCoord;  //頂點(diǎn)坐標(biāo)
    GLKVector2  textureCoord;   //紋理坐標(biāo)
    GLKVector3  normal;         //法線
}SFVertex;

//頂點(diǎn)數(shù)
static NSInteger const kCoordCount = 36;

@interface ViewController ()<GLKViewDelegate>
@property (nonatomic, strong)   GLKView             *glkView;
@property (nonatomic, strong)   GLKBaseEffect       *baseEffect;
@property (nonatomic, assign)   SFVertex            *vertices;

@property (nonatomic, strong)   CADisplayLink       *displayLink;
@property (nonatomic, assign)   NSInteger           angle;
@property (nonatomic, assign)   GLuint              vertexBuffer;



@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //1設(shè)置背景色
    self.view.backgroundColor = UIColor.lightGrayColor;
    //2.OpenGL ES 相關(guān)初始化
    [self commonInit];
    
    //3.頂點(diǎn)、紋理坐標(biāo)數(shù)據(jù)
    [self vertexDataSetup];
    
    //4. 添加CADisplayLink
    [self addCADisplayLink];
}
-(void)commonInit{
    //1.創(chuàng)建context
    EAGLContext *context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
    //設(shè)置當(dāng)前context
    [EAGLContext setCurrentContext:context];
    //2.創(chuàng)建GLKView 并設(shè)置代理
    CGRect frame = CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.width);
    self.glkView = [[GLKView alloc] initWithFrame:frame context:context];
    self.glkView.backgroundColor = UIColor.clearColor;
    self.glkView.delegate = self;
    
    //3。使用深度緩沖區(qū)
    self.glkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;
    //默認(rèn)是(0,1)這里用于翻轉(zhuǎn) z軸 使正方形屏幕朝外
    //4.將GLKView 添加self.view 上
    [self.view addSubview:self.glkView];
    
    //5.獲取紋理圖片
    NSString *imagePath  = [[[NSBundle mainBundle]resourcePath] stringByAppendingPathComponent:@"girl.png"];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    //6.設(shè)置參數(shù)
    NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft : @(YES)};
    GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithCGImage:[image CGImage] options:options error:nil];
    
    //7.使用baseEffect
    self.baseEffect = [[GLKBaseEffect alloc]init];
    self.baseEffect.texture2d0.name = textureInfo.name;
    self.baseEffect.texture2d0.target = textureInfo.target;
}
- (void)vertexDataSetup{
    /*
     使用每 3 個(gè)點(diǎn)畫一個(gè)三角形的方式,需要12個(gè)三角形,則需要36個(gè)頂點(diǎn)
     以下的數(shù)據(jù)用來(lái)繪制(0,0,0)為中心,邊長(zhǎng)為1 的立方體
     */
    
    //8,開辟頂點(diǎn)數(shù)據(jù)空間(數(shù)據(jù)結(jié)構(gòu)SenceVertex大小 * 頂點(diǎn)個(gè)數(shù) kCoordCount)
    self.vertices =malloc(sizeof(SFVertex) * kCoordCount);
    
    //前面
    self.vertices[0] = (SFVertex){{-0.5,0.5,0.5},{0,1}}; //左上角
    self.vertices[1] = (SFVertex){{-0.5,-0.5,0.5},{0,0}};//左下角
    self.vertices[2] = (SFVertex){{0.5,0.5,0.5},{1,1}};//右上角
    
    self.vertices[3] = (SFVertex){{-0.5, -0.5, 0.5}, {0, 0}};
    self.vertices[4] = (SFVertex){{0.5, 0.5, 0.5},   {1, 1}};
    self.vertices[5] = (SFVertex){{0.5, -0.5, 0.5},  {1, 0}};
    
    // 上面
    self.vertices[6] = (SFVertex){{0.5, 0.5, 0.5},    {1, 1}};
    self.vertices[7] = (SFVertex){{-0.5, 0.5, 0.5},   {0, 1}};
    self.vertices[8] = (SFVertex){{0.5, 0.5, -0.5},   {1, 0}};
    self.vertices[9] = (SFVertex){{-0.5, 0.5, 0.5},   {0, 1}};
    self.vertices[10] = (SFVertex){{0.5, 0.5, -0.5},  {1, 0}};
    self.vertices[11] = (SFVertex){{-0.5, 0.5, -0.5}, {0, 0}};
    
    // 下面
    self.vertices[12] = (SFVertex){{0.5, -0.5, 0.5},    {1, 1}};
    self.vertices[13] = (SFVertex){{-0.5, -0.5, 0.5},   {0, 1}};
    self.vertices[14] = (SFVertex){{0.5, -0.5, -0.5},   {1, 0}};
    self.vertices[15] = (SFVertex){{-0.5, -0.5, 0.5},   {0, 1}};
    self.vertices[16] = (SFVertex){{0.5, -0.5, -0.5},   {1, 0}};
    self.vertices[17] = (SFVertex){{-0.5, -0.5, -0.5},  {0, 0}};
    
    // 左面
    self.vertices[18] = (SFVertex){{-0.5, 0.5, 0.5},    {1, 1}};
    self.vertices[19] = (SFVertex){{-0.5, -0.5, 0.5},   {0, 1}};
    self.vertices[20] = (SFVertex){{-0.5, 0.5, -0.5},   {1, 0}};
    self.vertices[21] = (SFVertex){{-0.5, -0.5, 0.5},   {0, 1}};
    self.vertices[22] = (SFVertex){{-0.5, 0.5, -0.5},   {1, 0}};
    self.vertices[23] = (SFVertex){{-0.5, -0.5, -0.5},  {0, 0}};
    
    // 右面
    self.vertices[24] = (SFVertex){{0.5, 0.5, 0.5},    {1, 1}};
    self.vertices[25] = (SFVertex){{0.5, -0.5, 0.5},   {0, 1}};
    self.vertices[26] = (SFVertex){{0.5, 0.5, -0.5},   {1, 0}};
    self.vertices[27] = (SFVertex){{0.5, -0.5, 0.5},   {0, 1}};
    self.vertices[28] = (SFVertex){{0.5, 0.5, -0.5},   {1, 0}};
    self.vertices[29] = (SFVertex){{0.5, -0.5, -0.5},  {0, 0}};
    
    // 后面
    self.vertices[30] = (SFVertex){{-0.5, 0.5, -0.5},   {0, 1}};
    self.vertices[31] = (SFVertex){{-0.5, -0.5, -0.5},  {0, 0}};
    self.vertices[32] = (SFVertex){{0.5, 0.5, -0.5},    {1, 1}};
    self.vertices[33] = (SFVertex){{-0.5, -0.5, -0.5},  {0, 0}};
    self.vertices[34] = (SFVertex){{0.5, 0.5, -0.5},    {1, 1}};
    self.vertices[35] = (SFVertex){{0.5, -0.5, -0.5},   {1, 0}};
    
    //開辟緩存區(qū)
    glGenBuffers(1, &_vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(SFVertex) * kCoordCount, self.vertices, GL_STATIC_DRAW);
    
    //頂點(diǎn)數(shù)據(jù)
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(SFVertex), offsetof(SFVertex, positionCoord) + NULL);
    
    //紋理數(shù)據(jù)
    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(SFVertex), offsetof(SFVertex, textureCoord) + NULL);
    
    
}
-(void) addCADisplayLink{
    
    self.angle = 0;
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
    [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    
}
#pragma mark -- update --
- (void)update{
    //1.計(jì)算旋轉(zhuǎn)的度數(shù)
    self.angle = (self.angle + 5) % 360;
    NSLog(@"self.angle:%ld",(long)self.angle);
    //2.修改baseEffect.transfom.modeviewMatrix  GLKMathDegreesToRadians 角度轉(zhuǎn)弧度
    self.baseEffect.transform.modelviewMatrix = GLKMatrix4MakeRotation(GLKMathDegreesToRadians(self.angle) , 0.3, 1, -0.7);
    
    //3.重新渲染
    [self.glkView display];
}
#pragma mark - GLKViewDelegate
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
    
    //1.開啟深度測(cè)試
    glEnable(GL_DEPTH_TEST);
    //2.清楚顏色緩存區(qū) & 深度緩存區(qū)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //3.準(zhǔn)備繪制
    [self.baseEffect prepareToDraw];
    
    //4.繪圖
    glDrawArrays(GL_TRIANGLES, 0, kCoordCount);
    
}
-(void)dealloc{
    if ([EAGLContext currentContext] == self.glkView.context) {
        [EAGLContext setCurrentContext: nil];
    }
    if (self.vertices) {
        free(self.vertices);
        self.vertices = nil;
    }
    if (self.vertexBuffer) {
        glDeleteBuffers(1, &_vertexBuffer);
        _vertexBuffer = 0;
    }
    //displayLink 失效
    [self.displayLink invalidate];
    self.displayLink = nil;
}

@end

紋理加載的具體效果圖

自定義著色器的實(shí)現(xiàn)

  • 不使用GLKBaseEffect 使用編譯鏈接自定義的著色器(shader)
  • 用簡(jiǎn)單的glsl(Graphics library shader language)圖形庫(kù)著色器語(yǔ)言來(lái)實(shí)現(xiàn)頂點(diǎn)、片元著色器
    實(shí)現(xiàn)步驟:
  1. 創(chuàng)建圖層
  2. 創(chuàng)建上下文
  3. 清空緩存區(qū)
  4. 設(shè)置RenderBuffer
  5. 設(shè)置FrameBuffer
  6. 開始繪制

圖片顯示原理

  • CPU: 計(jì)算視圖frame,圖片解碼,需要繪制紋理圖片通過(guò)數(shù)據(jù)總線交給GPU
  • GPU:紋理混合,頂點(diǎn)變換與計(jì)算,像素點(diǎn)的填充計(jì)算,渲染到幀緩沖區(qū)
  • 時(shí)鐘信號(hào):垂直同步信號(hào)V-Sync / 水平同步信號(hào)H-Sync
  • iOS設(shè)備雙緩沖機(jī)制:顯示系統(tǒng)通常會(huì)引用兩個(gè)幀緩沖區(qū),雙緩沖
    圖片顯示到屏幕上市CPU和GPU的協(xié)作完成

圖片濾鏡實(shí)現(xiàn)思路:

  • 前提:使用GLSL顯示普通圖片
    思路:
    1、 初始化上下文,頂點(diǎn)數(shù)組,頂點(diǎn)數(shù)據(jù),頂點(diǎn)緩存區(qū),CAEAGLLayer,綁定渲染緩存區(qū)、幀緩存區(qū),獲取圖片路徑并將圖片-> 紋理,設(shè)置視口,link默認(rèn)著色器
    2、創(chuàng)建CADisplayLink 刷新圖片
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容