OpenGL中的纹理

作者: 黑眼豆豆_ | 来源:发表于2020-07-22 15:28 被阅读0次

    什么是纹理

    纹理(texture),通常来说,纹理就是一张二维的图片。给一个模型贴一个纹理,就像在iOS代码中添加UIImage一样。

    • 像素包装

    图像存储空间 = 图像的宽度 * 图像的长度 * 每个像素的字节数

    • tga文件
      在OpenGL中,我们使用.tga文件作为纹理的素材,该格式支持压缩,使用不失真的压缩算法,可以带通道图,另外还支持行程编码压缩。
      但是在OpenGL ES里面,我们就可以使用正常的图片了,例如.png,.jpg等等了。

    其实任何图片在绘制的时候都会被解压成位图,最终以位图的形式“贴在”模型上。

    常用纹理函数

    • 从颜色缓冲区读取像素
      该方法就是把图片从帧缓冲区中读取出来并进行写入
    //参数1:x,矩形左下⻆的窗⼝坐标
    //参数2:y,矩形左下⻆的窗⼝坐标
    //参数3:width,矩形的宽,以像素为单位
    //参数4:height,矩形的⾼,以像素为单位
    //参数5:format,OpenGL 的像素格式,参考图一
    //参数6:type,解释参数pixels指向的数据,告诉OpenGL 使⽤缓存区中的什么数据类型来存储颜⾊分量,像素数据的数据类型,参考 图二
    //参数7:pixels,指向图形数据的指针
    void glReadPixels(GLint x,GLint y,GLSizei width,GLSizei height, GLenum format, GLenum type,const void * pixels);
    

    glReadBuffer(mode);—> 指定读取的缓存
    glWriteBuffer(mode);—> 指定写⼊的缓存

    • 载入纹理
      载入纹理有以下3个方法
    //纹理为1D格式
    void glTexImage1D(GLenum target,GLint level,GLint 
    internalformat,GLsizei width,GLint border,GLenum 
    format,GLenum type,void *data);
    
    //纹理为2D格式
    void glTexImage2D(GLenum target,GLint level,GLint 
    internalformat,GLsizei width,GLsizei height,GLint 
    border,GLenum format,GLenum type,void * data);
    
    //纹理为3D格式
    void glTexImage3D(GLenum target,GLint level,GLint 
    internalformat,GLSizei width,GLsizei height,GLsizei 
    depth,GLint border,GLenum format,GLenum type,void *data);
    

    这3个方法很类似,从方法名我们可以得知,3个方法的区别在于载入纹理的格式,究竟是1D,2D还是3D。函数每个参数的意义如下:

    • target为别对应GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D
    • Level指定所加载的mip贴图层次。⼀般我们都把这个参数设置为0。
    • width、height、depth参数:指加载纹理的宽度、⾼度、深度。==注意!==这些值必须是2的整数次⽅。(这是因为OpenGL 旧版本上的遗留下的⼀个要求。当然现在已经可以⽀持不是2的整数次⽅。但是开发者们还是习惯使⽤以2的整数次⽅去设置这些参数。)
    • border允许为纹理贴图指定⼀个边界宽度。
    • format、type、data参数:与我们在讲glDrawPixels 函数对于的参数相同。

    由于,图片通常为2D的,即有宽度和高度,所以我们通常使用** glTexImage2D**这个方法

    • 分配纹理对象
    //参数1:使用了几个纹理,n就填几
    //参数2:纹理对象指针,表示申请了一个纹理对象
    void glGenTextures(GLsizei n,GLuint * textTures);
    
    • 绑定纹理
    //参数1有以下几个类型GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D,需要结合我们的纹理使用,一般使用GL_TEXTURE_2D。
    //参数2表示需要绑定的纹理对象
    void GLAPIENTRY glBindTexture (GLenum target, GLuint texture)
    
    • 删除纹理
    //参数1表示需要删除的纹理的个数。
    //参数2表示需要删除的纹理对象,这是一个数组,表示可以删除多个纹理。
    void glDeleteTextures (GLsizei n, const GLuint *textures);
    

    设置纹理参数

    设置纹理参数有以下几个方法:

    GLAPI void GLAPIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
    GLAPI void GLAPIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);
    GLAPI void GLAPIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
    GLAPI void GLAPIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params);
    

    上面的方法很类似,参数分别代表

    • target有以下几个类型GL_TEXTURE_1D,GL_TEXTURE_2D,GL_TEXTURE_3D,需要结合我们的纹理使用,一般使用GL_TEXTURE_2D。
    • pname指定需要设置哪个纹理参数
    • params表示具体的参数的值

    设置过滤方式

    在OpenGL中过滤方式有2各种,一种叫做临近过滤(GL_NEAREST),一种叫做线性过滤(GL_LINEAR)

    • 临近过滤(GL_NEAREST)表示某个像素点会取当前位置上的颜色。
    • 线性过滤(GL_NEAREST)表情会取附近的颜色综合值,做混合后展示在屏幕上。
      临近过滤.png
      线性过滤.png
      用上图可以看出,图1就是选取的它所在位置的颜色,图2就是对它周围取了一个综合值,计算后得出一个最接近的值。
      接下来,我们可以看一个实际的图片:
    临近过滤和线性过滤

    我们可以看到,临近过去看起来会更加清晰,但是有锯齿状;而线性过滤则有点模糊的感觉,但是会平滑许多。
    所以究竟选临近过滤还是线性过滤,其实需要根据当前的实际情况来判断。而且,在真实的案例中,2者并不会有太大差别。

    • 用法
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    
    • GL_TEXTURE_MAG_FILTER指当纹理图象被使用到一个大于它的形状上时的状态。
    • GL_TEXTURE_MIN_FILTER 指当纹理图象被使用到一个小于或等于它的形状上时的状态。

    设置环绕方式,

    当一个纹理坐标超出默认范围时,我们需要设置环绕方式,举个例子,假如我们的纹理为(44)的大小,但是我们的模型是(88),那么图片肯定不能铺满,那么就需要进行设置。

    环绕方式.png
    我们来看下具体效果:
    • GL_REPEAT
      GL_REPEAT.png
      此时,图片会进行复制,然后铺满屏幕。
    • GL_MIRRORED_REPEAT
      GL_MIRRORED_REPEAT.png
      此时,图片会进行复制,然后进行翻转,就像照镜子一样,然后铺满屏幕。
    • GL_CLAMP_TO_EDGE
      GL_CLAMP_TO_EDGE.png

    此时,固定图片中心的位置,边缘部分会被拉伸。

    • GL_CLAMP_TO_BORDER
      GL_CLAMP_TO_BORDER.png

    此时,固定图片中心的位置,超出部分用用户指定的颜色进行填充。

    • 用法
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    • GL_TEXTURE_WRAP_SGL_TEXTURE_WRAP_RGL_TEXTURE_WRAP_T分别代表s,t,r坐标。而这里的s,t,r坐标分别对应x,y,z坐标
    • 如果不设置,OpenGL默认使用** GL_REPEAT**。

    纹理坐标系

    对于一纹理来说,默认左下角为(0,0),右上角为(1,1)。


    坐标系

    如图所示,整个图片在[0,1]的区间中。

    但是,我们也可以对图片进行翻转


    翻转.png

    如图,我们把图片翻转了180度之后仍然可以使用。

    Mip贴图

    Mip贴图这项材质贴图的技术,是依据不同精度的要求,而使用不同版本的材质图样进行贴图,可以提高渲染性能和显示质量。
    例如:当物体移近使用者时,程序会在物体表面贴上较精细、清晰度较高的材质图案,于是让物体呈现出更高层、更加真实的效果;而当物体远离使用者时,程序就会贴上较单纯、清晰度较低的材质图样,进而提升图形处理的整体效率。

    • 用法
    // 设置mip贴图基层
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_BASE_LEVEL,0);
    //设置mip贴图最⼤层 
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_BASE_LEVEL,0);
    
    • Mip贴图的纹理过滤方式
      Mip贴图的纹理过滤.png

    下图为OpenGL的像素格式,我们常用GL_RGBGL_RGBA这两种格式。

    图1.png

    下图为OpenGL的像素数据的数据类型。我们常用GL_UNSIGNED_BYTE

    图2.png

    相关文章

      网友评论

        本文标题:OpenGL中的纹理

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