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

 

最近的回复

  • ![0_1540211558178_20181022_202905 (1).gif](正在上传 100%)

    阅读更多
  • 随后在git for windows这个软件中输入

    git clone git@git.coding.net:jiangcaiyang1/qtdreamrelease_windows.git

    就可以获得一个空的项目了。其它的项目也是同样的操作方法。然后呢,将此作为自动构建的代码库吧。
    此次介绍就是这样~😘 😘 🐧

    阅读更多
  • 0_1540027445466_很好.jpg
    萌梦安装包的分发始终是一个难题。要有一个稳定并且有效的方法进行分包,才能让大家都能够享受到萌梦动作编辑器的最新功能。我们目前有两种分发的方法:

    离线安装包。通常的位置是
    1.1 百度云盘
    1.2 QQ群文件
    1.3 github
    其中百度云盘和QQ群文件不会定期地更新,只有github的文件会定期更新。因为构建脚本要求每次有更改,都让github的文件更新。

    在线安装包。通常的位置是
    2.1 百度云盘
    2.2 QQ群文件
    2.3 github
    这里在线安装包的代码库主要还是在github中,在线安装包非常依赖CDN加速。目前github这块儿在国内做得不太好,还是希望在国内找一个类似的加速。目前可以选的只有两家:

    码云

    coding

    因为以前做过coding的加速,目前coding已经和腾讯云战略合作,所有的代码都要迁移到腾讯云了。而且对于代码库的空间要求变高了。128M。目前我的一个账号显然满足不了要求。所以有必要再注册一个账号。

    下面记录一下新建coding代码库的方法,并且尝试将萌梦安装包的线上代码库部分移动到coding代码库中。

    注册

    到这个位置注册。

    https://coding.net/register

    相信很快就会带你跳转到腾讯云中。不过这里我选择的是邮箱的方式,因为我希望注册尽量多的账号。

    设置ssh密钥

    进入控制台后,是这样的:
    0_1540028446495_2eeb7e93-c15b-4c82-9b36-58e1c304ea3f-image.png
    这个时候,我们要先创建项目,然后ssh的公钥。
    0_1540028822318_b3e81b93-099c-42d5-820d-deaf8d445913-image.png

    创建以后,开始部署公钥。在这里:
    0_1540028925337_d8059b64-8535-45e5-ba4c-d7454505aa5a-image.png
    这期间最好用OpenSSL生成SSH密钥。
    我使用的是git for windows来生成密钥的。方法是

    ssh-keygen

    如果你生成好了密钥,可以直接打开密钥内容看看:

    cat ~/.ssh/id_rsa.pub

    然后粘贴到网站的文本框中。

    添加好了之后,勾选“准许推送权限”,需要推送代码到代码库中。

    阅读更多

关注我们

微博
QQ群











召唤伊斯特瓦尔