美文网首页
OpenGL-- 纹理加载

OpenGL-- 纹理加载

作者: 照顾一下 | 来源:发表于2020-05-04 15:25 被阅读0次

    前言

    这一篇文章的主要内容是用OpenGL去加载纹理,也就是将图片加载到屏幕上。之前几篇文章已经讲解了OpenGL图形绘制的基本图元:点、线、三角形等七种。其实图片加载的过程与基本图元一样,只有一个步骤不同,那就是取色。基本图元绘制时我们给定了颜色值,而加载纹理时是从纹理中取每个像素点的颜色值。要真说区别,那就是颜色值的来源不一样。
    然而这篇文章也仅作为纹理加载的入门,该文章用了固定着色器:纹理替换着色器。而在OpenGL ES中我将会自己实现着色器程序,去取纹理中的颜色值,原理一样。

    纹理加载流程

    这一节实现一个完整的纹理加载过程。

    1.纹理坐标

    移动端的布局通常以屏幕左上角的点为坐标原点(0,0),而在纹理坐标中,原点是左下角的点,看图1对比一下。 图1-坐标系.png

    为什么要先说这个,因为纹理加载时,你告诉OpenGL的不是你的图片容器的尺寸,而是容器与纹理坐标的对应关系。改变映射关系就能够实现图片上下左右的颠倒。

    2.纹理相关专用名词

    a.临近过滤与线性过滤
    个人认为与其说是过滤还不如说是取值,下面用两张图片来解释。


    过滤方式.png

    很明显临近过滤是取对应像素点的颜色值,而线性过滤则是取它周围最近四个点的颜色混合值,这也是为什么有些图片看上去会模糊,与图片大小和容器大小有关,因为图片大小和容器大小差距太大时过滤方式不一样,导致效果不一样。

    b.环绕模式

    说到环绕模式这个词大家可能感动陌生,但是做过网页的小伙伴应该了解css中background的repeat属性,repeat、no-repeat会让图片不够撑满背景时进行循环平铺,而环绕模式与这个意义相同。这里通过示意图来枚举一下OpenGL中的环绕模式,仅作了解。 环绕模式.png

    3.纹理相关API

    a.绑定纹理

    // 用来生成纹理的函数。函数根据纹理参数返回n个纹理索引。纹理名称集合不必是一个连续的整数集合,
    //(glGenTextures就是用来产生你要操作的纹理对象的索引的,比如你告诉[OpenGL],我需要5个纹理对象,
    // 它会从没有用到的整数里返回5个给你)
    // params1:纹理对象个数
    // params2:纹理对象指针
    glGenTextures(1, &textureID);
    
    // 绑定纹理,GL_TEXTURE_2D:个人理解是OpenGL创建颜色缓冲区时创建的一个标识符
    // 将纹理名绑定至当前活动纹理单元目标
    // 将GL_TEXTURE_2D与textureID关联,后续需要用到textureID
    glBindTexture(GL_TEXTURE_2D, textureID);
    

    b.载入纹理

    bool loadTGATexture(const char *fileName) {
    
        GLbyte *pBits;
    
        int nWidth, nHeight, nComponents;
        GLenum eFormat;
        //1、读纹理位,读取像素
        //参数1:纹理文件名称
        //参数2:文件宽度地址
        //参数3:文件高度地址
        //参数4:文件组件地址
        //参数5:文件格式地址
        //返回值:pBits,指向图像数据的指针
        pBits = gltReadTGABits(fileName, &nWidth, &nHeight, &nComponents, &eFormat);
        if (pBits == NULL) {
            return false;
        }
    
        // 设置纹理参数
    
        // 环绕模式,可以试试不设置的效果
        // params1:纹理纬度
        // params2:OpenGL里面的横纵用s/t表示
        // params3:环绕模式,有多种,自行百度,例如:GL_REPEAT
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
        // 过滤方式
        // 纹理缩小时,用临近过滤
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        // 纹理放大时,用线性过滤
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
        // 载入纹理
        glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBits);
        // c,释放
        free(pBits);
        // 加载mip
        glGenerateMipmap(GL_TEXTURE_2D);
        return true;
    }
    

    c.设置纹理坐标

    GLfloat point00[] = {-0.5, -0.5, 0};
    GLfloat point10[] = { 0.5, -0.5, 0};
    GLfloat point01[] = {-0.5,  0.5, 0};
    GLfloat point11[] = { 0.5,  0.5, 0};
    
    GLBatch squareBatch;
    // 与之前画图元不一样
    /*
     参数1:类型
     参数2:顶点数
     参数3:这个批次中将会应用1个纹理
     */
    squareBatch.Begin(GL_TRIANGLE_FAN, 4, 1);
    
    // 设置顶点对应的纹理坐标
    // params1:texture,纹理层次,对于使用存储着色器来进行渲染,设置为0
    // params2:s: 对应顶点坐标中的x坐标
    // params3:t: 对应顶点坐标中的y
    squareBatch.MultiTexCoord2f(0, 0, 0);
    // 设置(0,0)对应的屏幕上的坐标点
    squareBatch.Vertex3fv(point00);
    
    squareBatch.MultiTexCoord2f(0, 1, 0);
    squareBatch.Vertex3fv(point10);
    
    squareBatch.MultiTexCoord2f(0, 1, 1);
    squareBatch.Vertex3fv(point11);
    
    squareBatch.MultiTexCoord2f(0, 0, 1);
    squareBatch.Vertex3fv(point01);
    
    squareBatch.End();
    

    d.着色器程序
    当前使用的着色器是固定着色器:纹理替换着色器(GLT_SHADER_TEXTURE_REPLACE)

    // 使用纹理替换矩阵
    shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformLine.GetModelViewProjectionMatrix(), 0);
    
    squareBatch.Draw();
    

    e.销毁

    // 删除纹理对象
    glDeleteTextures(1, &textureID);
    

    以上几个就是载入纹理的主要API。

    总结

    让我一起来,回顾那些快遗忘的纹理载入步骤。
    假设OpenGL的上下文已经初始化完毕,接下来:

    1.绑定:glGenTextures-> glBindTexture
    2.载入:gltReadTGABits-> glTexParameteri(4次,两次环绕两次过滤)-> glTexImage2D
    3.设置纹理坐标:MultiTexCoord2f->Vertex3fv
    4.使用着色器:shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformLine.GetModelViewProjectionMatrix(), 0);
    

    注意:因为这里用的是固定着色器程序,所以需要用到MVP模型视图矩阵,在OpenGL ES中加载纹理时,会手动实现着色器,流程与这篇文章中的流程略有不同。
    最后附上demo地址:https://github.com/zhaoguyixia/OpenGL.git
    祝各位生活愉快!!

    相关文章

      网友评论

          本文标题:OpenGL-- 纹理加载

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