Qt OPenGL 入门教程之六 基于QOpenGLWidget 3D立方体纹理贴图

纹理贴图是 opengl 极为重要的一个知识,相关知识点在此暂时不做介绍,这里只给出一个可运行的示例,

我对demo进行了一定的改动,其中在构造函数定义了一个PROGRAM_2D的宏,定义的时候为一个2个面的纹理贴图,注释掉该宏则会实现一个3d的贴图。同时给我们的例子添加键盘和鼠标动作,详细可以自行运行体验。

相比于前面几节,本节我们添加resources资源项,并添加图片。

Qt OPenGL 入门教程之六 基于QOpenGLWidget 3D立方体纹理贴图_第1张图片

具体代码如下:

//myopenglwidget.h
#ifndef MYOPENGLWIDGET_H
#define MYOPENGLWIDGET_H

#include 
#include 
#include 
#include 
#include 

class QOpenGLShaderProgram;
class QOpenGLTexture;

class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    explicit MyOpenGLWidget(QWidget *parent = 0);
    ~MyOpenGLWidget();
    QSize minimumSizeHint() const override;
    void keyPressEvent(QKeyEvent *event) override;
    QSize sizeHint() const override;
    void rotateBy(int xAngle, int yAngle, int zAngle);
    void setClearColor(const QColor &color);
signals:
    void clicked();

protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int width, int height) override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;

private:        
    void makeObject();
    void make2DObject();
    QColor clearColor;
    QPoint lastPos;
    GLfloat translate, xRot, yRot, zRot;
    void printContextInformation();
    QOpenGLShaderProgram *program;
    QOpenGLBuffer vbo;
    QOpenGLTexture *textures[6];
};

#endif // MYOPENGLWIDGET_H

//myopenglwidget.cpp
#include "myopenglwidget.h"
#include 
#include 
#include 
MyOpenGLWidget::MyOpenGLWidget(QWidget *parent)
    : QOpenGLWidget(parent),
      translate(-3),
      xRot(0),
      yRot(0),
      zRot(0)
{
    #define PROGRAM_2D  1; //可将该行注释掉观察程序的变化
    memset(textures, 0, sizeof(textures));
}

MyOpenGLWidget::~MyOpenGLWidget()
{
    makeCurrent();
    vbo.destroy();
    for (int i = 0; i < 6; ++i)
        delete textures[i];
    delete program;
    doneCurrent();
}

QSize MyOpenGLWidget::minimumSizeHint() const
{
    return QSize(200, 200);
}

void MyOpenGLWidget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Up:
        xRot += 10;
        break;
    case Qt::Key_Left:
        yRot += 10;
        break;
    case Qt::Key_Right:
        zRot += 10;
        break;
    case Qt::Key_Down:
        translate -= 1;
        break;
    case Qt::Key_Space:
        translate += 1;
        break;
    default:
        break;
    }
    update();
    QOpenGLWidget::keyPressEvent(event);
}

QSize MyOpenGLWidget::sizeHint() const
{
     return QSize(500, 500);
}

void MyOpenGLWidget::rotateBy(int xAngle, int yAngle, int zAngle)
{
    xRot += xAngle;
    yRot += yAngle;
    zRot += zAngle;
    update();
}

void MyOpenGLWidget::setClearColor(const QColor &color)
{
    clearColor = color;
    update();
}


void MyOpenGLWidget::initializeGL()
{

    // 为当前环境初始化OpenGL函数
    initializeOpenGLFunctions();
    printContextInformation();
#ifdef PROGRAM_2D
    for (int i = 0; i < 2; ++i)
        textures[i] = new QOpenGLTexture(QImage(QString("../myopengl/side%1.png")
                                               .arg(i + 1)).mirrored());
#else
    makeObject();
#endif
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_TEXCOORD_ATTRIBUTE 1

    // 创建顶点着色器
    QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
    const char *vsrc =
            "attribute highp vec4 vPosition;           \n"
            "attribute mediump vec4 vTexCoord;         \n"
            "varying mediump vec4 texCoord;            \n"
            "uniform mediump mat4 matrix;              \n"
            "void main() {                             \n"
            "   texCoord = vTexCoord;                  \n"
            "   gl_Position = matrix * vPosition;      \n"
            "}                                         \n";
    vshader->compileSourceCode(vsrc);
    // 创建片段着色器
    QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
    const char *fsrc =
            "uniform sampler2D tex;                     \n"
            "varying mediump vec4 texCoord;             \n"
            "void main() {                              \n"
            "   gl_FragColor = texture2D(tex, texCoord.st); \n"
            "}                                          \n";
    fshader->compileSourceCode(fsrc);
//    vshader->compileSourceFile(":/simple.vert");
//    fshader->compileSourceFile(":/simple.frag");


    // 创建着色器程序
    program = new QOpenGLShaderProgram;
//    program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vert.glsl");
//    program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/frag.glsl");

    program->addShader(vshader);
    program->addShader(fshader);
    program->bindAttributeLocation("vPosition", PROGRAM_VERTEX_ATTRIBUTE);
    program->bindAttributeLocation("vTexCoord", PROGRAM_TEXCOORD_ATTRIBUTE);

    program->link();
    program->bind();
    program->setUniformValue("texture", 0);

}

void MyOpenGLWidget::resizeGL(int width , int height)
{
    int side = qMin(width, height);
    glViewport((width - side) / 2, (height - side) / 2, side, side);
}


void MyOpenGLWidget::paintGL()
{
    int w = width();
    int h = height();
    int side = qMin(w, h);
    glViewport((w - side) / 2, (h - side) / 2, side, side);

    glClearColor(clearColor.redF(), clearColor.greenF(),
                 clearColor.blueF(), clearColor.alphaF());
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

#ifdef PROGRAM_2D
    // 顶点位置
    GLfloat vertices[2][4][3] = {
        { {-0.8f, 0.8f, 0.8f}, {-0.8f, -0.8f, 0.8f}, {0.8f, -0.8f, 0.8f}, {0.8f, 0.8f, 0.8f} },
        { {0.8f, 0.8f, 0.8f}, {0.8f, -0.8f, 0.8f}, {0.8f, -0.8f, -0.8f}, {0.8f, 0.8f, -0.8f} }
    };
    GLfloat vertices1[2][4][5] = {
        { {-0.8f, 0.8f, 0.8f,0.0f, 1.0f}, {-0.8f, -0.8f, 0.8f,0.0f, 0.0f},
          {0.8f, -0.8f, 0.8f,  1.0f, 0.0f}, {0.8f, 0.8f, 0.8f,  1.0f, 1.0f} },
        { {0.8f, 0.8f, 0.8f, 0.0f, 1.0f}, {0.8f, -0.8f, 0.8f, 0.0f, 0.0f},
          {0.8f, -0.8f, -0.8f, 1.0f, 0.0f}, {0.8f, 0.8f, -0.8f, 1.0f, 1.0f} }
    };
    vbo.create();
    vbo.bind();
    vbo.allocate(vertices1, 40*sizeof(GLfloat));

    GLuint attr = -1;
    attr = program->attributeLocation("vPosition");
//    program->setAttributeBuffer(vPosition, GL_FLOAT, 0, 3, 0);
    program->setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 5);
    glEnableVertexAttribArray(attr);

    attr = program->attributeLocation("vTexCoord");
    program->setAttributeBuffer(attr, GL_FLOAT, 3*sizeof(GLfloat), 2, sizeof(GLfloat) * 5);
    glEnableVertexAttribArray(attr);

//    GLuint vPosition = program->attributeLocation("vPosition");
//    program->setAttributeBuffer(vPosition, GL_FLOAT, 0, 3, 0);
//    glEnableVertexAttribArray(vPosition);
    // 纹理坐标
    GLfloat coords[2][4][2] = {
        { {0.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f} },
        { {0.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f} }
    };
//    vbo.write(24*sizeof(GLfloat), coords, 16*sizeof(GLfloat));
//    GLuint vTexCoord = program->attributeLocation("vTexCoord");
//    program->setAttributeBuffer(vTexCoord, GL_FLOAT, 24*sizeof(GLfloat), 2, 0);
//    glEnableVertexAttribArray(vTexCoord);

    program->setUniformValue("tex", 0);
#endif

    QMatrix4x4 matrix;
    matrix.perspective(45.0f, (GLfloat)w/(GLfloat)h, 0.1f, 100.0f);
    matrix.translate(0, 0, translate);
    matrix.rotate(-60, 0, 1, 0);  //绕Y轴逆时针旋转
    matrix.rotate(xRot / 16.0f, 1.0f, 0.0f, 0.0f);
    matrix.rotate(yRot / 16.0f, 0.0f, 1.0f, 0.0f);
    matrix.rotate(zRot / 16.0f, 0.0f, 0.0f, 1.0f);

    program->setUniformValue("matrix", matrix);
#ifdef PROGRAM_2D
#else
    program->enableAttributeArray(PROGRAM_VERTEX_ATTRIBUTE);
    program->enableAttributeArray(PROGRAM_TEXCOORD_ATTRIBUTE);
    program->setAttributeBuffer(PROGRAM_VERTEX_ATTRIBUTE, GL_FLOAT, 0, 3, 5 * sizeof(GLfloat));
    program->setAttributeBuffer(PROGRAM_TEXCOORD_ATTRIBUTE, GL_FLOAT, 3 * sizeof(GLfloat), 2, 5 * sizeof(GLfloat));
#endif

    // 绘制
#ifdef PROGRAM_2D
    for(int i=0; i<2; i++)
#else
    for(int i=0; i<6; i++)
#endif
    {
        textures[i]->bind();
        glDrawArrays(GL_TRIANGLE_FAN, i*4, 4);
    }
}


void MyOpenGLWidget::mousePressEvent(QMouseEvent *event)
{
    lastPos = event->pos();
}

void MyOpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{
    int dx = event->x() - lastPos.x();
    int dy = event->y() - lastPos.y();

    if (event->buttons() & Qt::LeftButton) {
        rotateBy(8 * dy, 8 * dx, 0);
    } else if (event->buttons() & Qt::RightButton) {
        rotateBy(8 * dy, 0, 8 * dx);
    }
    lastPos = event->pos();
}

void MyOpenGLWidget::mouseReleaseEvent(QMouseEvent *event)
{
    emit clicked();
}

void MyOpenGLWidget::makeObject()
{
    static const int coords[6][4][3] = {
        { { +1, -1, -1 }, { -1, -1, -1 }, { -1, +1, -1 }, { +1, +1, -1 } },
        { { +1, +1, -1 }, { -1, +1, -1 }, { -1, +1, +1 }, { +1, +1, +1 } },
        { { +1, -1, +1 }, { +1, -1, -1 }, { +1, +1, -1 }, { +1, +1, +1 } },
        { { -1, -1, -1 }, { -1, -1, +1 }, { -1, +1, +1 }, { -1, +1, -1 } },
        { { +1, -1, +1 }, { -1, -1, +1 }, { -1, -1, -1 }, { +1, -1, -1 } },
        { { -1, -1, +1 }, { +1, -1, +1 }, { +1, +1, +1 }, { -1, +1, +1 } }
    };

    for (int j = 0; j < 6; ++j)
        textures[j] = new QOpenGLTexture(QImage(QString(":/side%1.png").arg(j + 1)).mirrored());

    QVector vertData;
    for (int i = 0; i < 6; ++i) {
        for (int j = 0; j < 4; ++j) {
            // vertex position
            vertData.append(0.5 * coords[i][j][0]);
            vertData.append(0.5 * coords[i][j][1]);
            vertData.append(0.5 * coords[i][j][2]);
            // texture coordinate
            vertData.append(j == 0 || j == 3);
            vertData.append(j == 0 || j == 1);
        }
    }

    vbo.create();
    vbo.bind();
    vbo.allocate(vertData.constData(), vertData.count() * sizeof(GLfloat));
}

void MyOpenGLWidget::printContextInformation()
{
    QString glType;
    QString glVersion;
    QString glProfile;

    // Get Version Information
    glType = (context()->isOpenGLES()) ? "OpenGL ES" : "OpenGL";
    glVersion = reinterpret_cast(glGetString(GL_VERSION));

    // Get Profile Information
  #define CASE(c) case QSurfaceFormat::c: glProfile = #c; break
    switch (format().profile())
    {
      CASE(NoProfile);
      CASE(CoreProfile);
      CASE(CompatibilityProfile);
    }
  #undef CASE

    // qPrintable() will print our QString w/o quotes around it.
    qDebug() << qPrintable(glType) << qPrintable(glVersion) << "(" << qPrintable(glProfile) << ")";
}

#include 
#include "myopenglwidget.h"

int main(int argc, char *argv[])
{

    Q_INIT_RESOURCE(textures);
    QApplication app(argc,argv);

    QSurfaceFormat format;
    format.setDepthBufferSize(24);
    QSurfaceFormat::setDefaultFormat(format);

    MyOpenGLWidget w;
    w.rotateBy(+42 * 16, +42 * 16, -21 * 16);
    w.setFormat(format);
    w.resize(400, 300);
    w.show();
    return app.exec();
}



定义宏时的运行结果:

Qt OPenGL 入门教程之六 基于QOpenGLWidget 3D立方体纹理贴图_第2张图片

注释掉宏以后的运行效果:一个立方体

Qt OPenGL 入门教程之六 基于QOpenGLWidget 3D立方体纹理贴图_第3张图片

你可能感兴趣的:(opengl)