1、OpenGL ES 公共的相初始化
// 1、初始化上下文
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if(!context) {
NSLog(@"context 创建失败");
}
//2、设置当前上下文
[EAGLContext setCurrentContext:context];
//3、获取GLView
GLKView *view = (GLKView *)self.view;
view.context = context;
// 渲染缓冲区
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
//4、设置背景颜色
glClearColor(0.3, 0.4, 0.7, 1);
2、加载顶点/纹理相关数据
(1)设置顶点和纹理坐标
(2)开辟顶点缓冲区
(3)顶点数组的数据copy到顶点缓冲区(内存-> 显存),顶点缓冲区 是存在显存中的数据
(4)默认情况下,出于性能考虑,所有定点着色器的属性(Attribute)变量都是关闭的,所以即使使用glBufferData,
(5)设置OpenGL ES读取顶点缓冲区数据的方式
(6)处理纹理坐标-打开纹理坐标通道
glEnableVertexAttribArray(GLKVertexAttribTexCoord0)
(7)OpenGL ES读取纹理数据的方式
// 设置定点数据
-(void)setUpVertexData
{
// 定点数据,纹理坐标,都放在一个数组
// 前面x、y、z(顶点坐标)中心点是(0,0)
// s、t 纹理坐标 左下角是 (0 0)
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, //左下
};
//2、开辟顶点缓冲区(显存),将顶点数组的数据copy到顶点缓冲区,为了让gpu可以调用得到
//(1)创建顶点缓存区标识符ID,相当于顶点缓冲区指针
GLuint bufferID;
glGenBuffers(1, &bufferID);
//(2)绑定缓冲区(明确缓冲区的作用 GL_ARRAY_BUFFER 代表存储的是数组)
glBindBuffer(GL_ARRAY_BUFFER , &bufferID);
/**
3、顶点数组的数据copy到顶点缓冲区(内存-> 显存),顶点缓冲区 是存在显存中的数据
GL_ARRAY_BUFFER : 明确作用,说明顶点缓冲区是数组缓冲区
sizeof(vertexData) 说明缓冲区大小
&vertexData : 指定数据在哪里,把数组内存首地址传递进去
GL_STATIC_DRAW : 绘制方式为静态绘制
*/
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), &vertexData, GL_STATIC_DRAW);
/**
* 4、默认情况下,出于性能考虑,所有定点着色器的属性(Attribute)变量都是关闭的,所以即使使用glBufferData,
* 也没法讲顶点数据从内存拷贝到顶点缓存区中,用了glEnableVertexAttribArray,打开通道,制定访问属性,
* 才能让定点着色器能够访问到从CPU复制到GPU的数据
* GLKVertexAttribPosition, 顶点
* GLKVertexAttribNormal, 法线
* GLKVertexAttribColor, 颜色值
* GLKVertexAttribTexCoord0, 纹理1
* GLKVertexAttribTexCoord 纹理2
*/
glEnableVertexAttribArray(GLKVertexAttribPosition);
// 5、OpenGL ES读取顶点缓冲区数据的方式
/**
glVertexAttribPointer(GLuint indx, <#GLint size#>, <#GLenum type#>, <#GLboolean normalized#>, <#GLsizei stride#>, <#const GLvoid *ptr#>)
参数1 GLuint indx 所以指定的顶点属性索引值 GLKVertexAttribPosition ...
参数2 size 每次读取的步长(如position 由3个x、y、z组成,如颜色值由四个 r g b a 组成, 纹理是2个组成: s、t),这个例子是每次读取3个
参数3 type 数据类型 glfloat
参数4 normalized 归一化 GL_FALSE
参数5 stride 偏移量 ,连续顶点属性之间的偏移,,初始值为0
参数6: ptr 顶点数组读取的首地址,初始值为0
*/
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 5, 0);
// 6、处理纹理坐标-打开纹理坐标通道
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
// 7、OpenGL ES读取纹理数据的方式
//参数6: ptr 纹理数组读取的首地址,从3开始
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 5, (GLfloat *)NULL + 3);
}
3、设置纹理相关
// 设置纹理
-(void)setUpTextture
{
//1获取纹理图片路径
NSString *filePaht = [[NSBundle mainBundle] pathForResource:@"123456" ofType:@"PNG"];
// 2、设置纹理相关参数,解决纹理翻转在GLKit里的方法
//纹理的原点:左下角(0,0);
//view的原点:左上角(0,0);
NSDictionary *optioss = [NSDictionary dictionaryWithObjectsAndKeys:@(1), GLKTextureLoaderOriginBottomLeft,nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePaht options:optioss error:nil];
//3、GLBaseEffect 完成着色器工作 ,GLBaseEffect 可以包括三个光照,两个纹理
cEffect = [[GLKBaseEffect alloc] init];
cEffect.texture2d0.enabled = GL_TRUE;
cEffect.texture2d0.name = textureInfo.name;
}
4、 绘制视图内容
// 绘制视图内容
/**
GLKView 对象使OpenGL ES上下文成为当前上下文,并将其framebuffer绑定为OpenGL ES 呈现命令的目标,然后,委托方法绘制视图的内容
*/
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
//1、清理颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//2、准备绘制
[cEffect prepareToDraw];
//3、开始绘制
//GL_TRIANGLES 图元类型:三角形
//0 从第0个顶点开始
//6 6个顶点
glDrawArrays(GL_TRIANGLES, 0, 6);
}
最后效果图
完整代码:
//
// ViewController.m
// GLKitTest01
//
// Created by kemuchao on 2022/9/3.
//
#import "ViewController.h"
#import <OpenglES/ES3/gl.h>
#import <OpenglES/ES3/glext.h>
@interface ViewController ()
{
// 管理OpenGL ES 状态
EAGLContext *context;
GLKBaseEffect *cEffect;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1、OpenGL ES 公共的相初始化
[self setUpConfig];
// 2、加载顶点/纹理相关数据
[self setUpVertexData];
// 设置纹理相关
[self setUpTextture];
}
// 设置纹理
-(void)setUpTextture
{
//1获取纹理图片路径
NSString *filePaht = [[NSBundle mainBundle] pathForResource:@"123456" ofType:@"PNG"];
// 2、设置纹理相关参数,解决纹理翻转在GLKit里的方法
//纹理的原点:左下角(0,0);
//view的原点:左上角(0,0);
NSDictionary *optioss = [NSDictionary dictionaryWithObjectsAndKeys:@(1), GLKTextureLoaderOriginBottomLeft,nil];
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePaht options:optioss error:nil];
//3、GLBaseEffect 完成着色器工作 ,GLBaseEffect 可以包括三个光照,两个纹理
cEffect = [[GLKBaseEffect alloc] init];
cEffect.texture2d0.enabled = GL_TRUE;
cEffect.texture2d0.name = textureInfo.name;
}
// 设置定点数据
-(void)setUpVertexData
{
// 定点数据,纹理坐标,都放在一个数组
// 前面x、y、z(顶点坐标)中心点是(0,0)
// s、t 纹理坐标 左下角是 (0 0)
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, //左下
};
//2、开辟顶点缓冲区(显存),将顶点数组的数据copy到顶点缓冲区,为了让gpu可以调用得到
//(1)创建顶点缓存区标识符ID,相当于顶点缓冲区指针
GLuint bufferID;
glGenBuffers(1, &bufferID);
//(2)绑定缓冲区(明确缓冲区的作用 GL_ARRAY_BUFFER 代表存储的是数组)
glBindBuffer(GL_ARRAY_BUFFER , &bufferID);
/**
3、顶点数组的数据copy到顶点缓冲区(内存-> 显存),顶点缓冲区 是存在显存中的数据
GL_ARRAY_BUFFER : 明确作用,说明顶点缓冲区是数组缓冲区
sizeof(vertexData) 说明缓冲区大小
&vertexData : 指定数据在哪里,把数组内存首地址传递进去
GL_STATIC_DRAW : 绘制方式为静态绘制
*/
glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), &vertexData, GL_STATIC_DRAW);
/**
* 4、默认情况下,出于性能考虑,所有定点着色器的属性(Attribute)变量都是关闭的,所以即使使用glBufferData,
* 也没法讲顶点数据从内存拷贝到顶点缓存区中,用了glEnableVertexAttribArray,打开通道,制定访问属性,
* 才能让定点着色器能够访问到从CPU复制到GPU的数据
* GLKVertexAttribPosition, 顶点
* GLKVertexAttribNormal, 法线
* GLKVertexAttribColor, 颜色值
* GLKVertexAttribTexCoord0, 纹理1
* GLKVertexAttribTexCoord 纹理2
*/
glEnableVertexAttribArray(GLKVertexAttribPosition);
// 5、OpenGL ES读取顶点缓冲区数据的方式
/**
glVertexAttribPointer(GLuint indx, <#GLint size#>, <#GLenum type#>, <#GLboolean normalized#>, <#GLsizei stride#>, <#const GLvoid *ptr#>)
参数1 GLuint indx 所以指定的顶点属性索引值 GLKVertexAttribPosition ...
参数2 size 每次读取的步长(如position 由3个x、y、z组成,如颜色值由四个 r g b a 组成, 纹理是2个组成: s、t),这个例子是每次读取3个
参数3 type 数据类型 glfloat
参数4 normalized 归一化 GL_FALSE
参数5 stride 偏移量 ,连续顶点属性之间的偏移,,初始值为0
参数6: ptr 顶点数组读取的首地址,初始值为0
*/
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 5, 0);
// 6、处理纹理坐标-打开纹理坐标通道
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
// 7、OpenGL ES读取纹理数据的方式
//参数6: ptr 纹理数组读取的首地址,从3开始
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 5, (GLfloat *)NULL + 3);
}
// 设置基本配置
-(void)setUpConfig
{
// 1、初始化上下文
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
if(!context) {
NSLog(@"context 创建失败");
}
//2、设置当前上下文
[EAGLContext setCurrentContext:context];
//3、获取GLView
GLKView *view = (GLKView *)self.view;
view.context = context;
// 渲染缓冲区
view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
//4、设置背景颜色
glClearColor(0.3, 0.4, 0.7, 1);
}
// 绘制视图内容
/**
GLKView 对象使OpenGL ES上下文成为当前上下文,并将其framebuffer绑定为OpenGL ES 呈现命令的目标,然后,委托方法绘制视图的内容
*/
-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect {
//1、清理颜色缓冲区
glClear(GL_COLOR_BUFFER_BIT);
//2、准备绘制
[cEffect prepareToDraw];
//3、开始绘制
//GL_TRIANGLES 图元类型:三角形
//0 从第0个顶点开始
//6 6个顶点
glDrawArrays(GL_TRIANGLES, 0, 6);
}
@end