- 着色器的渲染过程
在渲染过程中,必须存储2中着色器,分别是顶点着色器、片元着色器。顶点着色器是第一个着色器、片元着色器是最后一个。顶点着色器处理顶点、片元着色器处理像素点颜色。
//
// 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; //顶点坐标
GLKVector2 textureCoord; //纹理坐标
GLKVector3 normal; //法线
}SFVertex;
//顶点数
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设置背景色
self.view.backgroundColor = UIColor.lightGrayColor;
//2.OpenGL ES 相关初始化
[self commonInit];
//3.顶点、纹理坐标数据
[self vertexDataSetup];
//4. 添加CADisplayLink
[self addCADisplayLink];
}
-(void)commonInit{
//1.创建context
EAGLContext *context = [[EAGLContext alloc]initWithAPI:kEAGLRenderingAPIOpenGLES2];
//设置当前context
[EAGLContext setCurrentContext:context];
//2.创建GLKView 并设置代理
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。使用深度缓冲区
self.glkView.drawableDepthFormat = GLKViewDrawableDepthFormat24;
//默认是(0,1)这里用于翻转 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.设置参数
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 个点画一个三角形的方式,需要12个三角形,则需要36个顶点
以下的数据用来绘制(0,0,0)为中心,边长为1 的立方体
*/
//8,开辟顶点数据空间(数据结构SenceVertex大小 * 顶点个数 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}};
//开辟缓存区
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(SFVertex) * kCoordCount, self.vertices, GL_STATIC_DRAW);
//顶点数据
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(SFVertex), offsetof(SFVertex, positionCoord) + NULL);
//纹理数据
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.计算旋转的度数
self.angle = (self.angle + 5) % 360;
NSLog(@"self.angle:%ld",(long)self.angle);
//2.修改baseEffect.transfom.modeviewMatrix GLKMathDegreesToRadians 角度转弧度
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.开启深度测试
glEnable(GL_DEPTH_TEST);
//2.清楚颜色缓存区 & 深度缓存区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//3.准备绘制
[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
自定义着色器的实现
- 不使用GLKBaseEffect 使用编译链接自定义的着色器(shader)
- 用简单的glsl(Graphics library shader language)图形库着色器语言来实现顶点、片元着色器
实现步骤:
- 创建图层
- 创建上下文
- 清空缓存区
- 设置RenderBuffer
- 设置FrameBuffer
- 开始绘制
图片显示原理
- CPU: 计算视图frame,图片解码,需要绘制纹理图片通过数据总线交给GPU
- GPU:纹理混合,顶点变换与计算,像素点的填充计算,渲染到帧缓冲区
- 时钟信号:垂直同步信号V-Sync / 水平同步信号H-Sync
- iOS设备双缓冲机制:显示系统通常会引用两个帧缓冲区,双缓冲
图片显示到屏幕上市CPU和GPU的协作完成
图片滤镜实现思路:
- 前提:使用GLSL显示普通图片
思路:
1、 初始化上下文,顶点数组,顶点数据,顶点缓存区,CAEAGLLayer,绑定渲染缓存区、帧缓存区,获取图片路径并将图片-> 纹理,设置视口,link默认着色器
2、创建CADisplayLink 刷新图片