小白学opengl 第六课:纹理映射

终于我们可以把图片贴到我们的图形上了

0_1526631569328_QQ截图20180518161627.png

纹理坐标

当我们把图片贴到我们的正方形上,需要指定四个角的对应关系,这就是纹理坐标,通常,我们希望图片左下角对应正方形左下角,图片右上角对应正方形右上角,如果对应错了,图片就会上下颠倒,左右颠倒

0_1526631721822_cube1.png

把原来顶点颜色数组改为,顶点纹理坐标数组

//VAO数据,顶点与颜色
    VertexData1 vcs[] = {
        //正面
        {QVector3D(-0.5f, 0.0f, 0.5f), QVector2D(0.0f, 0.0f)},     //1
        {QVector3D(0.5f, 0.0f, 0.5f), QVector2D(1.0f, 0.0f)},      //2
        {QVector3D(0.5f, 1.0f, 0.5f), QVector2D(1.0f, 1.0f)},      //3
        {QVector3D(-0.5f, 1.0f, 0.5f), QVector2D(0.0f, 1.0f)},     //4
}

索引

//索引
    GLuint indices[] = { // 起始于0!
        0, 1, 2, 3,// face 1
}

常用步骤

//1 使用glGenBuffers函数生成一个缓冲ID    
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);
    //2 绑定vao
    glBindVertexArray(VAO);
    //3 使用glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER缓冲类型上
    glBindBuffer(GL_ARRAY_BUFFER, VBO); //(绑定和解绑的顺序很重要,勿更改)
    //4 把用户定的义数据复制到当前绑定缓冲的函数
    glBufferData(GL_ARRAY_BUFFER, sizeof(vcs), vcs, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    //5 链接顶点属性
    //indx: 属性名
    //size: 顶点大小
    //type: 数据类型
    //normalized:数据被标准化
    //stride: 步长
    //ptr: 数据在缓冲中起始位置的偏移量
    glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData1), (GLvoid*)0);
    glVertexAttribPointer(m_texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData1), (GLvoid*)(sizeof(QVector3D)));
//(GLvoid*)(sizeof(QVector3D)
    //6 解绑缓存着色器(绑定和解绑的顺序很重要,勿更改)
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    //7 解绑VAO
    glBindVertexArray(0);

创建纹理

用一张图片生成纹理,我们使用QOpenGLTexture来很方便的实现

//使用图片的垂直镜像来创建纹理
    m_texture = new QOpenGLTexture(QImage(":/cube1.png").mirrored());

    //设置纹理过滤器的滤波方式
    //当图片缩小的比原始纹理小的时候 滤波方式为 mip层之间使用线性插值和使用线性过滤
    m_texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
    //当图片放大的比原始纹理大的时候 滤波方式为 mip基层上使用线性过滤
    m_texture->setMagnificationFilter(QOpenGLTexture::Linear);

    //设置图片格式
    m_texture->setFormat(QOpenGLTexture::RGBFormat);
    //纹理绑定
    m_texture->bind();

    //使用纹理单元
    m_program->setUniformValue("texture", 0);

绘制

//纹理绑定
    m_texture->bind();

    //1 绑定vao
    glBindVertexArray(VAO);

    //2 开启顶点属性
    glEnableVertexAttribArray(0);
    //颜色值
    glEnableVertexAttribArray(2);

    //3 绘制四边形
    //24个索引值
//    glDrawArrays(GL_QUADS, 0, 24);
    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, (GLvoid*)0);

    //4 停用对应的顶点属性数组
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(0);

    //5 解绑VAO
    glBindVertexArray(0);

    //纹理释放
    m_texture->release();

注意

  • 启用2D纹理映射,否则显示白色
//启用2D纹理映射
    glEnable(GL_TEXTURE_2D);
  • 启用纹理对应的属性,否则显示白色
glEnableVertexAttribArray(2);

六面纹理-单一

思考了一下,每个面对应一个图片,如果用索引,只有8个点,死活对应不上,只好放弃索引,重新使用24个点

struct VertexData
{
    QVector3D position;
    QVector3D color;
    QVector3D texture;
};
VertexData vc[] = {
        //正面
        {QVector3D(-0.5f, 0.0f, 0.5f), QVector3D(1.0f, 0.0f, 0.0f), QVector2D(0.0f, 0.0f)},     //1
        {QVector3D(0.5f, 0.0f, 0.5f),  QVector3D(0.0f, 1.0f, 0.0f), QVector2D(1.0f, 0.0f)},      //2
        {QVector3D(0.5f, 1.0f, 0.5f),  QVector3D(0.0f, 0.0f, 1.0f), QVector2D(1.0f, 1.0f)},      //3
        {QVector3D(-0.5f, 1.0f, 0.5f), QVector3D(1.0f, 1.0f, 1.0f), QVector2D(0.0f, 1.0f)},     //4

        //右面
        {QVector3D(0.5f, 0.0f, 0.5f),  QVector3D(0.0f, 1.0f, 0.0f), QVector2D(0.0f, 0.0f)},     //2
        {QVector3D(0.5f, 0.0f, -0.5f), QVector3D(1.0f, 1.0f, 0.0f), QVector2D(1.0f, 0.0f)},     //5
        {QVector3D(0.5f, 1.0f, -0.5f), QVector3D(0.0f, 1.0f, 1.0f), QVector2D(1.0f, 1.0f)},     //6
        {QVector3D(0.5f, 1.0f, 0.5f),  QVector3D(0.0f, 0.0f, 1.0f), QVector2D(0.0f, 1.0f)},     //3

        //左面
        {QVector3D(-0.5f, 0.0f, -0.5f),QVector3D(1.0f, 0.0f, 1.0f), QVector2D(0.0f, 0.0f)},     //8
        {QVector3D(-0.5f, 0.0f, 0.5f), QVector3D(1.0f, 0.0f, 0.0f), QVector2D(1.0f, 0.0f)},     //1
        {QVector3D(-0.5f, 1.0f, 0.5f), QVector3D(1.0f, 1.0f, 1.0f), QVector2D(1.0f, 1.0f)},     //4
        {QVector3D(-0.5f, 1.0f, -0.5f),QVector3D(1.0f, 0.6f, 0.0f), QVector2D(0.0f, 1.0f)},     //7

        //背面
        {QVector3D(0.5f, 0.0f, -0.5f),   QVector3D(1.0f, 1.0f, 0.0f), QVector2D(0.0f, 0.0f)},   //5
        {QVector3D(-0.5f, 0.0f, -0.5f),  QVector3D(1.0f, 0.0f, 1.0f), QVector2D(1.0f, 0.0f)},   //8
        {QVector3D(-0.5f, 1.0f, -0.5f),  QVector3D(1.0f, 0.6f, 0.0f), QVector2D(1.0f, 1.0f)},   //7
        {QVector3D(0.5f, 1.0f, -0.5f),   QVector3D(0.0f, 1.0f, 1.0f), QVector2D(0.0f, 1.0f)},   //6

        //顶面
        {QVector3D(-0.5f, 1.0f, 0.5f),   QVector3D(1.0f, 1.0f, 1.0f), QVector2D(0.0f, 0.0f)},   //4
        {QVector3D(0.5f, 1.0f, 0.5f),    QVector3D(0.0f, 0.0f, 1.0f), QVector2D(1.0f, 0.0f)},   //3
        {QVector3D(0.5f, 1.0f, -0.5f),   QVector3D(0.0f, 1.0f, 1.0f), QVector2D(1.0f, 1.0f)},   //6
        {QVector3D(-0.5f, 1.0f, -0.5f),  QVector3D(1.0f, 0.6f, 0.0f), QVector2D(0.0f, 1.0f)},   //7

        //底面        
        {QVector3D(-0.5f, 0.0f, -0.5f),  QVector3D(1.0f, 0.0f, 1.0f), QVector2D(0.0f, 0.0f)},   //8
        {QVector3D(0.5f, 0.0f, -0.5f),   QVector3D(1.0f, 1.0f, 0.0f), QVector2D(1.0f, 0.0f)},   //5
        {QVector3D(0.5f, 0.0f, 0.5f),    QVector3D(0.0f, 1.0f, 0.0f), QVector2D(1.0f, 1.0f)},   //2
        {QVector3D(-0.5f, 0.0f, 0.5f),   QVector3D(1.0f, 0.0f, 0.0f), QVector2D(0.0f, 1.0f)},   //1
    };

纹理坐标链接时候注意要跳过两个QVector3D大小

//5 链接顶点属性
    //indx: 属性名
    //size: 顶点大小
    //type: 数据类型
    //normalized:数据被标准化
    //stride: 步长
    //ptr: 数据在缓冲中起始位置的偏移量
    glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)0);    //(GLvoid*)0
    glVertexAttribPointer(m_texcoordLocation, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)(sizeof(QVector3D)*2));

使用 glDrawArrays(GL_QUADS, 0, 24);绘制

0_1526634110381_240b60a8-fed1-4579-9a2c-058fd780e40a-image.png

下次我们做个骰子出来

先说一个坑

同样的代码拿回家就不好用,研究发现,绘制时候没启用颜色顶点,所以一直是黑屏

//颜色值
    glEnableVertexAttribArray(1);

骰子的六面

要贴6次纹理,所以用指针数组, 管理全部纹理

声明数组

//纹理对象 数组
    QVector<QOpenGLTexture *> m_vTexture;

创建数组

for(int i=0; i<6; i++)
    {
        //使用图片的垂直镜像来创建纹理
        QString path = QString(":/cube%1.png").arg(QString::number(i+1));
        QOpenGLTexture *_texture = new QOpenGLTexture(QImage(path).mirrored());
        //设置纹理过滤器的滤波方式
        //当图片缩小的比原始纹理小的时候 滤波方式为 mip层之间使用线性插值和使用线性过滤
        _texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear);
        //当图片放大的比原始纹理大的时候 滤波方式为 mip基层上使用线性过滤
        _texture->setMagnificationFilter(QOpenGLTexture::Linear);

        m_vTexture.append(_texture);
    }

绘制注意问题

开启顶点属性

//2 开启顶点属性
    glEnableVertexAttribArray(0);
    //颜色值
    glEnableVertexAttribArray(1);
    //纹理
    glEnableVertexAttribArray(2);

6个面要依次绘制一遍,绘制的起点也要依次往后移动

//纹理绑定
    for(int i=0; i<6; i++)
    {
        m_vTexture.at(i)->bind();
        //3 绘制四边形
        //24个索引值
        glDrawArrays(GL_QUADS, i*4, 4);
        //    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, (GLvoid*)0);

        m_vTexture.at(i)->release();
    }

停用顶点属性

//4 停用对应的顶点属性数组
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(0);
0_1526684517642_fcb07104-1ebe-4306-bcf9-3c21aa8793cb-image.png

同时显示颜色和纹理

gl_FragColor = col*texture2D(texture, v_texcoord);


0_1526684652591_a7df691b-cf8d-42df-a6eb-2cfbaf93e898-image.png

源代码

https://gitee.com/chen227/opengl_OpenGLFunctions6

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

推荐阅读更多精彩内容