美文网首页
GLSL索引绘图并设置纹理案例

GLSL索引绘图并设置纹理案例

作者: CrazySnow | 来源:发表于2020-08-20 15:02 被阅读0次

索引绘图就是将图形中肉眼可见的定点,通过索引的方式建立定点之间的连接,绘制过程中将顶点重复利用

案例效果


索引绘图案例效果.gif 索引绘图流程图.png

本文主要讲解绘制图形相关,自定义着色器及着色器的加载

layoutSubViews

一、 准备工作

  • 创建绘制图层:作为要绘制内容的载体
  • 绘制上下文:用于记录状态(状态机)
  • 清除缓存区:避免之前的缓存,对本次绘制造成影响
  • 设置renderBuffer:用于存储颜色、顶点等的缓冲区
  • 设置FrameBuffer:用于管理renderBuffer


    准备流程.png

二、 绘制

  • 初始化:设置清屏颜色、清理缓存区、设置视口大小等
  • 加载自定义着色器(请参考
  • 设置顶点数据
  • 构建矩阵并将顶点数据传递到顶点着色器
  • 索引绘图

顶点数据的创建及传递流程如下:

image.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 ----

完整demo

添加纹理

在以上内容的基础上,做如下操作

  • 修改顶点数组,增加纹理坐标,具体如下
//前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;
}

设置纹理demo

相关文章

网友评论

      本文标题:GLSL索引绘图并设置纹理案例

      本文链接:https://www.haomeiwen.com/subject/yqlsjktx.html