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



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



  • This post is deleted!


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

    glEnable( GL_DEPTH_TEST );
    

Log in to reply
 

走马观花

最近的回复

  • 萌梦 男孩,女孩,和蛋

    menghome.png

    read more
  • 设计模式-工厂模式

    使用qt/qml来演示设计模式效果,便于学习理解

    1)定义创建对象的接口,封装对象的创建
    2)使具体化类的工作延迟到工厂子类中

    bg.png
    image.png

    1. 工厂类

    createProduct使用了参数来选择要创建哪个产品

    #ifndef FACTORY_H #define FACTORY_H #include <QObject> class Product; class QString; class Factory: public QObject { Q_OBJECT public: virtual ~Factory() = 0; virtual Product* createProduct(QString type) = 0; protected: Factory(); }; class ConcreteFactory: public Factory { Q_OBJECT public: ~ConcreteFactory(); ConcreteFactory(); public slots: Product* createProduct(QString type); }; #endif // FACTORY_H #include "factory.h" #include "product.h" #include <QtQml/qqml.h> Factory::~Factory() { } Factory::Factory() { qmlRegisterType<Product>("Product", 1, 0, "Product"); } ConcreteFactory::~ConcreteFactory() { } ConcreteFactory::ConcreteFactory() { } Product *ConcreteFactory::createProduct(QString type) { if(type == "boy") return static_cast<Product *>(new ConcreteProduct1()); else if(type == "girl") return static_cast<Product *>(new ConcreteProduct2()); return static_cast<Product *>(new ConcreteProduct1()); } 2 产品类

    一个产品是萌梦男,一个产品是萌梦女

    #ifndef PRODUCT_H #define PRODUCT_H #include <QObject> class Product: public QObject { Q_OBJECT public: virtual ~Product() = 0; Q_PROPERTY(QString icon READ icon NOTIFY iconChanged) QString m_icon; QString icon() const { return m_icon; } signals: void iconChanged(QString icon); protected: Product(); signals: public slots: }; class ConcreteProduct1: public Product { Q_OBJECT public: ~ConcreteProduct1(); ConcreteProduct1(); }; class ConcreteProduct2: public Product { Q_OBJECT public: ~ConcreteProduct2(); ConcreteProduct2(); }; #endif // PRODUCT_H #include "product.h" Product::~Product() { } Product::Product() { } ConcreteProduct1::~ConcreteProduct1() { } ConcreteProduct1::ConcreteProduct1() { m_icon = "qrc:/images/boy.png"; } ConcreteProduct2::~ConcreteProduct2() { } ConcreteProduct2::ConcreteProduct2() { m_icon = "qrc:/images/girl.png"; } 3. main.qml

    使用timer,canvas,listview等实现一个自动化生产的动画效果

    源代码

    Fork me on Gitee

    read more
  • blender建模 章鱼
    捕获2.PNG 😵

    read more

关注我们

微博
QQ群