美文网首页
小白学opengl 第六课:纹理映射

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

作者: 技术喵 | 来源:发表于2019-07-10 07:32 被阅读0次

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

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

相关文章

网友评论

      本文标题:小白学opengl 第六课:纹理映射

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