小白学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



  • 我跑起来这个代码有点问题



  • 0_1526738252238_深度录屏_opengl_OpenGLFunctions_20180519215653.gif



  • @大黄老鼠 画面裁剪的感觉



  • 此回复已被删除!


  • @大黄老鼠 要启用深度测试:

    glEnable( GL_DEPTH_TEST );
    

 

最近的回复

  • 很棒!求软件,我要摆在我的桌面上。

    阅读更多
  • 这个很有意思 ^_^

    阅读更多
  • 思路:
    1.把官方时钟demo改了,加了秒针,加了壁纸,加了小萝莉
    2.QWindow窗口嵌入到桌面

    0_1533891238039_20180810_164211.gif

    改版

    去掉秒针,把小萝莉正过来,沿着表盘走

    0_1533893719543_20180810_173309.gif

    源代码

    Fork me on Gitee

    阅读更多

关注我们

微博
QQ群











召唤伊斯特瓦尔