opengl es 第六课(马赛克)

马赛克

把单个马赛克颗粒内所有像素设置成颗粒内某一个颜色

顶点着色器

1
2
3
4
5
6
7
8
9

attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

void main (void) {
gl_Position = Position;
TextureCoordsVarying = TextureCoords;
}

片源-正方形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
precision mediump float;

varying vec2 TextureCoordsVarying;
uniform sampler2D Texture;
const vec2 TexSize = vec2(400.0, 400.0);
const vec2 mosaicSize = vec2(16.0, 16.0);

void main()
{
vec2 intXY = vec2(TextureCoordsVarying.x*TexSize.x, TextureCoordsVarying.y*TexSize.y);
vec2 XYMosaic = vec2(floor(intXY.x/mosaicSize.x)*mosaicSize.x, floor(intXY.y/mosaicSize.y)*mosaicSize.y);
vec2 UVMosaic = vec2(XYMosaic.x/TexSize.x, XYMosaic.y/TexSize.y);
vec4 color = texture2D(Texture, UVMosaic);
gl_FragColor = color;
}

片源-六边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
precision highp float;
uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

const float mosaicSize = 0.03;

void main (void)
{
float length = mosaicSize;

float TR = 0.866025;
float TB = 1.5;

float x = TextureCoordsVarying.x;
float y = TextureCoordsVarying.y;

int wx = int(x / TB / length);
int wy = int(y / TR / length);
vec2 v1, v2, vn;

if (wx/2 * 2 == wx) {
if (wy/2 * 2 == wy) {
//(0,0),(1,1)
v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));
v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));
} else {
//(0,1),(1,0)
v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));
v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));
}
}else {
if (wy/2 * 2 == wy) {
//(0,1),(1,0)
v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy + 1));
v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy));
} else {
//(0,0),(1,1)
v1 = vec2(length * 1.5 * float(wx), length * TR * float(wy));
v2 = vec2(length * 1.5 * float(wx + 1), length * TR * float(wy + 1));
}
}

float s1 = sqrt(pow(v1.x - x, 2.0) + pow(v1.y - y, 2.0));
float s2 = sqrt(pow(v2.x - x, 2.0) + pow(v2.y - y, 2.0));
if (s1 < s2) {
vn = v1;
} else {
vn = v2;
}
vec4 color = texture2D(Texture, vn);

gl_FragColor = color;

}

opengl es 第五课(分解图片)

进入 GLSL 阶段

把kunkun大卸4块的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
precision highp float;
uniform sampler2D Texture;
varying highp vec2 TextureCoordsVarying;

void main() {
vec2 uv = TextureCoordsVarying.xy;
// if (uv.x < 1.0 / 3.0) {
// uv.x = uv.x * 3.0;
// } else if (uv.x < 2.0 / 3.0) {
// uv.x = (uv.x - 1.0 / 3.0) * 3.0;
// } else {
// uv.x = (uv.x - 2.0 / 3.0) * 3.0;
// }
// if (uv.y <= 1.0 / 3.0) {
// uv.y = uv.y * 3.0;
// } else if (uv.y < 2.0 / 3.0) {
// uv.y = (uv.y - 1.0 / 3.0) * 3.0;
// } else {
// uv.y = (uv.y - 2.0 / 3.0) * 3.0;
// }

if (uv.x - uv.y <= 0.04 && uv.x - uv.y >= -0.04) {
if (uv.x - uv.y <= 0.01 && uv.x - uv.y >= -0.01){
// gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
else{
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}
else if(uv.x + uv.y <= 1.04 && uv.x + uv.y >= 0.96){
if(uv.x + uv.y <= 1.01 && uv.x + uv.y >= 0.99){
// gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
else{
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}
else{

if(uv.x + uv.y < 1.0){
uv.x = uv.x + 0.025;
uv.y = uv.y + 0.025;
}
else{
uv.x = uv.x - 0.025;
uv.y = uv.y - 0.025;
}
gl_FragColor = texture2D(Texture, uv);
}
}

顶点着色

1
2
3
4
5
6
7
8
9

attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

void main (void) {
gl_Position = Position;
TextureCoordsVarying = TextureCoords;
}

opengl es 第二课(无情的glsl语法提示)

顶点着色器、片源着色器

没有语法提示;
纯文本字符串,无法调试;
处理逻辑简单,计算重的特性;

顶点着色器
attributes(属性通道)
顶点数据、投影矩阵、模型矩阵
纹理坐标(映射关系)
uniform(统一批次,只设置一次的)
变换矩阵、
texture(一般不这么传递)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 接收 vec4 类型的值(如顶点坐标)
attribute vec4 position;

// 接收 vec2 类型的值(如纹理坐标)
attribute vec2 textCoordinate;

// 关联片源着色器里的属性(必须与片源着色器定义的一模一样)
varying lowp vec2 varyTextCoord;

void main()
{
// 往片源着色器传递
varyTextCoord = textCoordinate;

// 返回顶点数据
gl_Position = position;
}

片源着色器
varying 来自vsh顶点着色器
uniform *
*texture 纹理数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 声明float为高精度
precision highp float;
// 接受顶点着色器的传递的值(必须与顶点着色器定义的一模一样)
varying lowp vec2 varyTextCoord;
// 接收简单的2D纹理
uniform sampler2D colorMap;

void main()
{
//lowp vec4 temp = texture2D(colorMap, varyTextCoord);
//gl_FragColor = temp;

// 获取纹理颜色数据(根据纹理、纹理坐标)
gl_FragColor = texture2D(colorMap, varyTextCoord);

}

编译加载shader文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 加载 shader 文件
-(GLuint)loadShaders:(NSString *)vert Withfrag:(NSString *)frag
{
//1.定义2个零时着色器对象
GLuint verShader, fragShader;
//创建program
GLint program = glCreateProgram();

//2.编译顶点着色程序、片元着色器程序
//参数1:编译完存储的底层地址
//参数2:编译的类型,GL_VERTEX_SHADER(顶点)、GL_FRAGMENT_SHADER(片元)
//参数3:文件路径
[self compileShader:&verShader type:GL_VERTEX_SHADER file:vert];
[self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:frag];

//3.创建最终的程序
glAttachShader(program, verShader);
glAttachShader(program, fragShader);

//4.释放不需要的shader
glDeleteShader(verShader);
glDeleteShader(fragShader);

return program;
}

// 编译 shader
- (void)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file{

//1.读取文件路径字符串
NSString* content = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];
const GLchar* source = (GLchar *)[content UTF8String];

//2.创建一个shader(根据type类型)
*shader = glCreateShader(type);

//3.将着色器源码附加到着色器对象上。
//参数1:shader,要编译的着色器对象 *shader
//参数2:numOfStrings,传递的源码字符串数量 1个
//参数3:strings,着色器程序的源码(真正的着色器程序源码)
//参数4:lenOfStrings,长度,具有每个字符串长度的数组,或NULL,这意味着字符串是NULL终止的
glShaderSource(*shader, 1, &source,NULL);

//4.把着色器源代码编译成目标代码
glCompileShader(*shader);

}

opengl es 第三课(加载一个纹理)

图片转纹理数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199


//从图片中加载纹理
- (GLuint)setupTexture:(NSString *)fileName {

//1、将 UIImage 转换为 CGImageRef
CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;

//判断图片是否获取成功
if (!spriteImage) {
NSLog(@"Failed to load image %@", fileName);
exit(1);
}

//2、读取图片的大小,宽和高
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);

//3.获取图片字节数 宽*高*4(RGBA)
GLubyte * spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));

//4.创建上下文
/*
参数1:data,指向要渲染的绘制图像的内存地址
参数2:width,bitmap的宽度,单位为像素
参数3:height,bitmap的高度,单位为像素
参数4:bitPerComponent,内存中像素的每个组件的位数,比如32位RGBA,就设置为8
参数5:bytesPerRow,bitmap的没一行的内存所占的比特数
参数6:colorSpace,bitmap上使用的颜色空间 kCGImageAlphaPremultipliedLast:RGBA
*/
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);


//5、在CGContextRef上--> 将图片绘制出来
/*
CGContextDrawImage 使用的是Core Graphics框架,坐标系与UIKit 不一样。UIKit框架的原点在屏幕的左上角,Core Graphics框架的原点在屏幕的左下角。
CGContextDrawImage
参数1:绘图上下文
参数2:rect坐标
参数3:绘制的图片
*/
CGRect rect = CGRectMake(0, 0, width, height);

//6.使用默认方式绘制
CGContextDrawImage(spriteContext, rect, spriteImage);

//7、画图完毕就释放上下文
CGContextRelease(spriteContext);

//8、绑定纹理到默认的纹理ID(
glBindTexture(GL_TEXTURE_2D, 0);

//9.设置纹理属性
/*
参数1:纹理维度
参数2:线性过滤、为s,t坐标设置模式
参数3:wrapMode,环绕模式
*/
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

float fw = width, fh = height;

//10.载入纹理2D数据
/*
参数1:纹理模式,GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
参数2:加载的层次,一般设置为0
参数3:纹理的颜色值GL_RGBA
参数4:宽
参数5:高
参数6:border,边界宽度
参数7:format
参数8:type
参数9:纹理数据
*/
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);

//11.释放spriteData
free(spriteData);
return 0;
}

//6.开始绘制
-(void)renderLayer
{
//设置清屏颜色
glClearColor(0.3f, 0.45f, 0.5f, 1.0f);
//清除屏幕
glClear(GL_COLOR_BUFFER_BIT);

//1.设置视口大小
CGFloat scale = [[UIScreen mainScreen]scale];
glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, self.frame.size.height * scale);

//2.读取顶点着色程序、片元着色程序
NSString *vertFile = [[NSBundle mainBundle]pathForResource:@"shaderv" ofType:@"vsh"];
NSString *fragFile = [[NSBundle mainBundle]pathForResource:@"shaderf" ofType:@"fsh"];

NSLog(@"vertFile:%@",vertFile);
NSLog(@"fragFile:%@",fragFile);

//3.加载shader
self.myPrograme = [self loadShaders:vertFile Withfrag:fragFile];

//4.链接
glLinkProgram(self.myPrograme);
GLint linkStatus;
//获取链接状态
glGetProgramiv(self.myPrograme, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE) {
GLchar message[512];
glGetProgramInfoLog(self.myPrograme, sizeof(message), 0, &message[0]);
NSString *messageString = [NSString stringWithUTF8String:message];
NSLog(@"Program Link Error:%@",messageString);
return;
}

NSLog(@"Program Link Success!");
//5.使用program
glUseProgram(self.myPrograme);

//6.设置顶点、纹理坐标
//前3个是顶点坐标,后2个是纹理坐标
GLfloat attrArr[] =
{
0.5f, -0.5f, -1.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -1.0f, 0.0f, 0.0f,

0.5f, 0.5f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -1.0f, 0.0f, 1.0f,
0.5f, -0.5f, -1.0f, 1.0f, 0.0f,
};


//7.-----处理顶点数据--------
//(1)顶点缓存区
GLuint attrBuffer;
//(2)申请一个缓存区标识符
glGenBuffers(1, &attrBuffer);
//(3)将attrBuffer绑定到GL_ARRAY_BUFFER标识符上
glBindBuffer(GL_ARRAY_BUFFER, attrBuffer);
//(4)把顶点数据从CPU内存复制到GPU上
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);

//8.将顶点数据通过myPrograme中的传递到顶点着色程序的position
//1.glGetAttribLocation,用来获取vertex attribute的入口的.
//2.告诉OpenGL ES,通过glEnableVertexAttribArray,
//3.最后数据是通过glVertexAttribPointer传递过去的。

//(1)注意:第二参数字符串必须和shaderv.vsh中的输入变量:position保持一致
GLuint position = glGetAttribLocation(self.myPrograme, "position");

//(2).设置合适的格式从buffer里面读取数据
glEnableVertexAttribArray(position);

//(3).设置读取方式
//参数1:index,顶点数据的索引
//参数2:size,每个顶点属性的组件数量,1,2,3,或者4.默认初始值是4.
//参数3:type,数据中的每个组件的类型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT。默认初始值为GL_FLOAT
//参数4:normalized,固定点数据值是否应该归一化,或者直接转换为固定值。(GL_FALSE)
//参数5:stride,连续顶点属性之间的偏移量,默认为0;
//参数6:指定一个指针,指向数组中的第一个顶点属性的第一个组件。默认为0
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, NULL);


//9.----处理纹理数据-------
//(1).glGetAttribLocation,用来获取vertex attribute的入口的.
//注意:第二参数字符串必须和shaderv.vsh中的输入变量:textCoordinate保持一致
GLuint textCoor = glGetAttribLocation(self.myPrograme, "textCoordinate");

//(2).设置合适的格式从buffer里面读取数据
glEnableVertexAttribArray(textCoor);

//(3).设置读取方式
//参数1:index,顶点数据的索引
//参数2:size,每个顶点属性的组件数量,1,2,3,或者4.默认初始值是4.
//参数3:type,数据中的每个组件的类型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT。默认初始值为GL_FLOAT
//参数4:normalized,固定点数据值是否应该归一化,或者直接转换为固定值。(GL_FALSE)
//参数5:stride,连续顶点属性之间的偏移量,默认为0;
//参数6:指定一个指针,指向数组中的第一个顶点属性的第一个组件。默认为0
glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL + 3);

//10.加载纹理
[self setupTexture:@"kunkun"];

//11. 设置纹理采样器 sampler2D
glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);

//12.绘图
glDrawArrays(GL_TRIANGLES, 0, 6);

//13.从渲染缓存区显示到屏幕上
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];


}

清空缓存区、设置 RenderBuffer,FrameBuffer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//5.设置FrameBuffer
-(void)setupFrameBuffer
{
//1.定义一个缓存区ID
GLuint buffer;

//2.申请一个缓存区标志
//glGenRenderbuffers(1, &buffer);
//glGenFramebuffers(1, &buffer);
glGenBuffers(1, &buffer);

//3.
self.myColorFrameBuffer = buffer;

//4.
glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer);

/*生成帧缓存区之后,则需要将renderbuffer跟framebuffer进行绑定,
调用glFramebufferRenderbuffer函数进行绑定到对应的附着点上,后面的绘制才能起作用
*/

//5.将渲染缓存区myColorRenderBuffer 通过glFramebufferRenderbuffer函数绑定到 GL_COLOR_ATTACHMENT0上。
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);

}

//4.设置RenderBuffer
-(void)setupRenderBuffer
{
//1.定义一个缓存区ID
GLuint buffer;

//2.申请一个缓存区标志
glGenRenderbuffers(1, &buffer);

//3.
self.myColorRenderBuffer = buffer;

//4.将标识符绑定到GL_RENDERBUFFER
glBindRenderbuffer(GL_RENDERBUFFER, self.myColorRenderBuffer);

//5.将可绘制对象drawable object's CAEAGLLayer的存储绑定到OpenGL ES renderBuffer对象
[self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer];


}

//3.清空缓存区
-(void)deleteRenderAndFrameBuffer
{
/*
buffer分为frame buffer 和 render buffer2个大类。
其中frame buffer 相当于render buffer的管理者。
frame buffer object即称FBO。
render buffer则又可分为3类。colorBuffer、depthBuffer、stencilBuffer。
*/

glDeleteBuffers(1, &_myColorRenderBuffer);
self.myColorRenderBuffer = 0;

glDeleteBuffers(1, &_myColorFrameBuffer);
self.myColorFrameBuffer = 0;

}

opengl es 第四课(来个MVP变换)

在上一节课的基础上修改

加载多个纹理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
GLuint tex0 = 0;
GLuint tex1 = 1;

//从图片中加载纹理
- (GLuint)setupTexture:(NSString *)fileName tex:(GLuint)tex{

//1、将 UIImage 转换为 CGImageRef
CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;

//判断图片是否获取成功
if (!spriteImage) {
NSLog(@"Failed to load image %@", fileName);
exit(1);
}

//2、读取图片的大小,宽和高
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);

//3.获取图片字节数 宽*高*4(RGBA)
GLubyte * spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));

//4.创建上下文
/*
参数1:data,指向要渲染的绘制图像的内存地址
参数2:width,bitmap的宽度,单位为像素
参数3:height,bitmap的高度,单位为像素
参数4:bitPerComponent,内存中像素的每个组件的位数,比如32位RGBA,就设置为8
参数5:bytesPerRow,bitmap的没一行的内存所占的比特数
参数6:colorSpace,bitmap上使用的颜色空间 kCGImageAlphaPremultipliedLast:RGBA
*/
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);


//5、在CGContextRef上--> 将图片绘制出来
/*
CGContextDrawImage 使用的是Core Graphics框架,坐标系与UIKit 不一样。UIKit框架的原点在屏幕的左上角,Core Graphics框架的原点在屏幕的左下角。
CGContextDrawImage
参数1:绘图上下文
参数2:rect坐标
参数3:绘制的图片
*/
CGRect rect = CGRectMake(0, 0, width, height);

//6.使用默认方式绘制
CGContextDrawImage(spriteContext, rect, spriteImage);

//7、画图完毕就释放上下文
CGContextRelease(spriteContext);

//8、绑定纹理到默认的纹理ID(
glBindTexture(GL_TEXTURE_2D, tex);

//9.设置纹理属性
/*
参数1:纹理维度
参数2:线性过滤、为s,t坐标设置模式
参数3:wrapMode,环绕模式
*/
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

float fw = width, fh = height;

//10.载入纹理2D数据
/*
参数1:纹理模式,GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
参数2:加载的层次,一般设置为0
参数3:纹理的颜色值GL_RGBA
参数4:宽
参数5:高
参数6:border,边界宽度
参数7:format
参数8:type
参数9:纹理数据
*/
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);

//11.释放spriteData
free(spriteData);
return 0;
}

渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//6.绘制
-(void)render
{
//1.清屏颜色
glClearColor(0, 0.0, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);


CGFloat scale = [[UIScreen mainScreen] scale];
//2.设置视口
glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, self.frame.size.height * scale);

//3.获取顶点着色程序、片元着色器程序文件位置
NSString* vertFile = [[NSBundle mainBundle] pathForResource:@"shaderv" ofType:@"glsl"];
NSString* fragFile = [[NSBundle mainBundle] pathForResource:@"shaderf" ofType:@"glsl"];

//4.判断self.myProgram是否存在,存在则清空其文件
if (self.myProgram) {

glDeleteProgram(self.myProgram);
self.myProgram = 0;
}

//5.加载程序到myProgram中来。
self.myProgram = [self loadShader:vertFile frag:fragFile];

//6.链接
glLinkProgram(self.myProgram);
GLint linkSuccess;

//7.获取链接状态
glGetProgramiv(self.myProgram, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(self.myProgram, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSLog(@"error%@", messageString);

return ;
}else {
glUseProgram(self.myProgram);
}

//8.创建顶点数组 & 索引数组
//(1)顶点数组 前3顶点值(x,y,z),后3位颜色值(RGB)
// GLfloat attrArr[] =
// {
// -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //左上0
// 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, //右上1
// -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //左下2
//
// 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, //右下3
// 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, //顶点4
// };

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

0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,//右下
0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f,//顶点
};


//(2).索引数组
GLuint indices[] =
{
0, 3, 2,
0, 1, 3,
0, 2, 4,
0, 4, 1,
2, 3, 4,
1, 4, 3,
};

//(3).判断顶点缓存区是否为空,如果为空则申请一个缓存区标识符
if (self.myVertices == 0) {
glGenBuffers(1, &_myVertices);
}


//9.-----处理顶点数据-------
//(1).将_myVertices绑定到GL_ARRAY_BUFFER标识符上
glBindBuffer(GL_ARRAY_BUFFER, _myVertices);
//(2).把顶点数据从CPU内存复制到GPU上
glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);

//(3).将顶点数据通过myPrograme中的传递到顶点着色程序的position
//1.glGetAttribLocation,用来获取vertex attribute的入口的.
//2.告诉OpenGL ES,通过glEnableVertexAttribArray,
//3.最后数据是通过glVertexAttribPointer传递过去的。
//注意:第二参数字符串必须和shaderv.vsh中的输入变量:position保持一致
GLuint position = glGetAttribLocation(self.myProgram, "position");

//(4).打开position
glEnableVertexAttribArray(position);

//(5).设置读取方式
//参数1:index,顶点数据的索引
//参数2:size,每个顶点属性的组件数量,1,2,3,或者4.默认初始值是4.
//参数3:type,数据中的每个组件的类型,常用`的有GL_FLOAT,GL_BYTE,GL_SHORT。默认初始值为GL_FLOAT
//参数4:normalized,固定点数据值是否应该归一化,或者直接转换为固定值。(GL_FALSE)
//参数5:stride,连续顶点属性之间的偏移量,默认为0;
//参数6:指定一个指针,指向数组中的第一个顶点属性的第一个组件。默认为0
glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, NULL);


//10.--------处理顶点颜色值-------
//(1).glGetAttribLocation,用来获取vertex attribute的入口的.
//注意:第二参数字符串必须和shaderv.glsl中的输入变量:positionColor保持一致
GLuint positionColor = glGetAttribLocation(self.myProgram, "positionColor");

//(2).设置合适的格式从buffer里面读取数据
glEnableVertexAttribArray(positionColor);

//(3).设置读取方式
//参数1:index,顶点数据的索引
//参数2:size,每个顶点属性的组件数量,1,2,3,或者4.默认初始值是4.
//参数3:type,数据中的每个组件的类型,常用的有GL_FLOAT,GL_BYTE,GL_SHORT。默认初始值为GL_FLOAT
//参数4:normalized,固定点数据值是否应该归一化,或者直接转换为固定值。(GL_FALSE)
//参数5:stride,连续顶点属性之间的偏移量,默认为0;
//参数6:指定一个指针,指向数组中的第一个顶点属性的第一个组件。默认为0
glVertexAttribPointer(positionColor, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (float *)NULL + 3);


GLuint positionTexture = glGetAttribLocation(self.myProgram, "positionTexture");
glEnableVertexAttribArray(positionTexture);
glVertexAttribPointer(positionTexture, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 8, (float *)NULL + 6);


//10.加载纹理
[self setupTexture:@"green.png" tex:tex0];
//11. 设置纹理采样器 sampler2D
glUniform1i(glGetUniformLocation(self.myProgram, "texUp"), tex0);

[self setupTexture:@"kunkun.jpg" tex:tex1];
glUniform1i(glGetUniformLocation(self.myProgram, "texDown"), tex1);


//11.找到myProgram中的projectionMatrix、modelViewMatrix 2个矩阵的地址。如果找到则返回地址,否则返回-1,表示没有找到2个对象。
GLuint projectionMatrixSlot = glGetUniformLocation(self.myProgram, "projectionMatrix");
GLuint modelViewMatrixSlot = glGetUniformLocation(self.myProgram, "modelViewMatrix");

float width = self.frame.size.width;
float height = self.frame.size.height;

//12.创建4 * 4投影矩阵
KSMatrix4 _projectionMatrix;
//(1)获取单元矩阵
ksMatrixLoadIdentity(&_projectionMatrix);
//(2)计算纵横比例 = 长/宽
float aspect = width / height; //长宽比
//(3)获取透视矩阵
/*
参数1:矩阵
参数2:视角,度数为单位
参数3:纵横比
参数4:近平面距离
参数5:远平面距离
参考PPT
*/
ksPerspective(&_projectionMatrix, 30.0, aspect, 5.0f, 20.0f); //透视变换,视角30°
//(4)将投影矩阵传递到顶点着色器
/*
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
参数列表:
location:指要更改的uniform变量的位置
count:更改矩阵的个数
transpose:是否要转置矩阵,并将它作为uniform变量的值。必须为GL_FALSE
value:执行count个元素的指针,用来更新指定uniform变量
*/
glUniformMatrix4fv(projectionMatrixSlot, 1, GL_FALSE, (GLfloat*)&_projectionMatrix.m[0][0]);


//13.创建一个4 * 4 矩阵,模型视图矩阵
KSMatrix4 _modelViewMatrix;
//(1)获取单元矩阵
ksMatrixLoadIdentity(&_modelViewMatrix);
//(2)平移,z轴平移-10
ksTranslate(&_modelViewMatrix, 0.0, 0.0, -10.0);
//(3)创建一个4 * 4 矩阵,旋转矩阵
KSMatrix4 _rotationMatrix;
//(4)初始化为单元矩阵
ksMatrixLoadIdentity(&_rotationMatrix);
//(5)旋转
ksRotate(&_rotationMatrix, xDegree, 1.0, 0.0, 0.0); //绕X轴
ksRotate(&_rotationMatrix, yDegree, 0.0, 1.0, 0.0); //绕Y轴
ksRotate(&_rotationMatrix, zDegree, 0.0, 0.0, 1.0); //绕Z轴
//(6)把变换矩阵相乘.将_modelViewMatrix矩阵与_rotationMatrix矩阵相乘,结合到模型视图
ksMatrixMultiply(&_modelViewMatrix, &_rotationMatrix, &_modelViewMatrix);
//(7)将模型视图矩阵传递到顶点着色器
/*
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
参数列表:
location:指要更改的uniform变量的位置
count:更改矩阵的个数
transpose:是否要转置矩阵,并将它作为uniform变量的值。必须为GL_FALSE
value:执行count个元素的指针,用来更新指定uniform变量
*/
glUniformMatrix4fv(modelViewMatrixSlot, 1, GL_FALSE, (GLfloat*)&_modelViewMatrix.m[0][0]);


//14.开启剔除操作效果
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);



//15.使用索引绘图
/*
void glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices);
参数列表:
mode:要呈现的画图的模型
GL_POINTS
GL_LINES
GL_LINE_LOOP
GL_LINE_STRIP
GL_TRIANGLES
GL_TRIANGLE_STRIP
GL_TRIANGLE_FAN
count:绘图个数
type:类型
GL_BYTE
GL_UNSIGNED_BYTE
GL_SHORT
GL_UNSIGNED_SHORT
GL_INT
GL_UNSIGNED_INT
indices:绘制索引数组

*/
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices);


//16.要求本地窗口系统显示OpenGL ES渲染<目标>
[self.myContext presentRenderbuffer:GL_RENDERBUFFER];


}

顶点着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
attribute vec4 position;
attribute vec4 positionColor;
attribute vec2 positionTexture;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

varying lowp vec4 varyColor;
varying lowp vec2 varyTexPos;

void main()
{
varyColor = positionColor;
varyTexPos = positionTexture;

vec4 vPos;

//4*4 * 4*4 * 4*1
vPos = projectionMatrix * modelViewMatrix * position;

//ERROR
//vPos = position * modelViewMatrix * projectionMatrix ;
gl_Position = vPos;
}

片源着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
varying lowp vec4 varyColor;
varying lowp vec2 varyTexPos;
uniform sampler2D texUp;
uniform sampler2D texDown;
void main()
{

lowp vec4 t1 = texture2D(texUp, varyTexPos);
lowp vec4 t2 = texture2D(texDown, varyTexPos);
// float appha = 0.2;
// float alpha = 0.5;
// float alpha1 = 1.0 - alpha;
// lowp vec4 tt = alpha1 * t1 + alpha * t2
gl_FragColor = t1 * 0.4 + t2 * 0.6;

}