小白学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
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值