索引绘图就是将图形中肉眼可见的定点,通过索引的方式建立定点之间的连接,绘制过程中将顶点重复利用
案例效果
索引绘图案例效果.gif 索引绘图流程图.png
本文主要讲解绘制图形相关,自定义着色器及着色器的加载
layoutSubViews
一、 准备工作
- 创建绘制图层:作为要绘制内容的载体
- 绘制上下文:用于记录状态(状态机)
- 清除缓存区:避免之前的缓存,对本次绘制造成影响
- 设置renderBuffer:用于存储颜色、顶点等的缓冲区
-
设置FrameBuffer:用于管理renderBuffer
准备流程.png
二、 绘制
- 初始化:设置清屏颜色、清理缓存区、设置视口大小等
- 加载自定义着色器(请参考)
- 设置顶点数据
- 构建矩阵并将顶点数据传递到顶点着色器
- 索引绘图
顶点数据的创建及传递流程如下:
1、设置顶点数组、所以数组
2、开辟缓存区,将顶点数据从内存拷贝到显存
3、打开attribute通道,将顶点坐标传入顶点着色器
4、打开attribute通道,将顶点颜色传入顶点着色器
构建矩阵
1、获取顶点着色器中uniform修饰的投影矩阵、模型视图矩阵的入口,方便后续将对应矩阵传入顶点着色器中,入口的获取与attribute入口获取类似,其中的name都需要与着色器中一模一样
GLuint projectionMatrixSlot = glGetUniformLocation(self.myPrograme, "projectionMatrix");
GLuint modelViewMatrixSlot = glGetUniformLocation(self.myPrograme, "modelViewMatrix");
2、获取屏幕的纵横比,用于设置透视投影
float width = self.frame.size.width;
float height = self.frame.size.height;
//获取纵横比
float aspect = width / height;
3、创建投影矩阵
- 定义一个4*4的投影矩阵
- 通过ksMatrixLoadIdentity将投影矩阵初始化为单元矩阵
- 通过ksPerspective设置投影矩阵
- 通过glUniformMatrix4fv将投影矩阵传递到顶点着色器
//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]);
索引绘图
glDrawElements(GL_TRIANGLES, sizeof(indices) / sizeof(indices[0]), GL_UNSIGNED_INT, indices);
glDrawElements方法的mode参数:设置要呈现的画图的模式
mode模式 | type 类型 |
---|---|
GL_POINTS | GL_BYTE |
GL_LINES | GL_UNSIGNED_BYTE |
GL_LINE_LOOP | GL_SHORT |
GL_LINE_STRIP | GL_UNSIGNED_SHORT |
GL_TRIANGLES | GL_INT |
GL_TRIANGLE_STRIP | GL_UNSIGNED_INT |
GL_TRIANGLE_FAN | ---- |
添加纹理
在以上内容的基础上,做如下操作
- 修改顶点数组,增加纹理坐标,具体如下
//前3个元素,是顶点数据;中间3个元素,是顶点颜色值,最后2个是纹理坐标
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,//顶点
};
- 修改自定义着色器(详情查看底部demo)
- 修改render函数,新增纹理处理及加载相关代码
// ---------处理纹理数据
GLuint textCoord = glGetAttribLocation(self.myPrograme, "textCoordinate");
glEnableVertexAttribArray(textCoord);
glVertexAttribPointer(textCoord, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*8, (float*)NULL+6);
// ------加载纹理
[self setupTexture:@"mouse"];
// ------设置纹理采样器
glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);
setupTexture函数
主要是将png/jpg图片解压成位图,然后进行绑定、加载
- (GLuint)setupTexture: (NSString *)fileName{
//将UIImage转换为CGImageRef
CGImageRef image = [UIImage imageNamed:fileName].CGImage;
if (!image) {
NSLog(@"failed to load image %@", fileName);
exit(1);
}
//获取图片的宽高
size_t width = CGImageGetWidth(image);
size_t height = CGImageGetHeight(image);
//获取图片的字节数
GLubyte *imageData = (GLubyte *)calloc(width*height*4, sizeof(GLubyte));
//创建context & 使用默认方式绘制图片,即纹理的加载就是重新绘制图片
CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width*4, CGImageGetColorSpace(image), kCGImageAlphaPremultipliedLast);
CGRect rect = CGRectMake(0, 0, width, height);
CGContextDrawImage(context, rect, image);
CGContextRelease(context);
//绑定纹理到默认的标识符0,0默认是激活状态
glBindTexture(GL_TEXTURE_2D, 0);
//设置纹理参数(过滤方式、环绕模式)
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;
//加载纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
return 0;
}
网友评论