OpenGL-- 纹理加载

前言

这一篇文章的主要内容是用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
祝各位生活愉快!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,208评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,502评论 3 405
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,496评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,176评论 1 302
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,185评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,630评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,992评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,973评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,510评论 1 325
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,546评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,659评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,250评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,990评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,421评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,569评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,238评论 3 382
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,732评论 2 366