原文:https://www.jianshu.com/p/62fb681df39c
Qt中有对应的QMatrix4x4处理4维矩阵
使用OpenGL函数版
#include "widget.h" #include "ui_widget.h" #include <QTImer> #include <QDebug> static GLuint VBO, VAO, EBO, texture1, texture2; Widget::Widget(QWidget *parent) : QOpenGLWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); m_timer = new QTimer(this); m_nTimeValue = 0; connect(m_timer,&QTimer::timeout,this,&slotTimer); m_timer->start(50); } void Widget::slotTimer() { m_nTimeValue += 5; update(); } Widget::~Widget() { delete ui; } void Widget::initializeGL() { this->initializeOpenGLFunctions(); int success = m_program.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/textures.vert"); if (!success) { qDebug() << "program addShaderFromSourceFile Failed." << m_program.log(); return; } success = m_program.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/textures.frag"); if (!success) { qDebug() << "program addShaderFromSourceFile Failed." << m_program.log(); return; } success = m_program.link(); if (!success) { qDebug() << "program link Failed." << m_program.log(); } // VAO VBO VEO data float vertices[] = { // positions // colors // texture coords 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left }; unsigned int indices[] = { // note that we start from 0! 0, 1, 3, // first Triangle 1, 2, 3 // second Triangle }; glGenVertexArrays(1,&VAO); glGenBuffers(1,&VBO); glGenBuffers(1,&EBO); // bind the Vertex Array Object first, then bind and set vertex buffer(s), // and then configure vertex attributes(s). glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER,VBO); glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(indices),indices,GL_STATIC_DRAW); // position attribute glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)0); glEnableVertexAttribArray(0); // color attribute glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)(3*sizeof(float))); glEnableVertexAttribArray(1); // texture coords glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,8*sizeof(float),(void*)(6*sizeof(float))); glEnableVertexAttribArray(2); // texture1 glGenTextures(1,&texture1); glBindTexture(GL_TEXTURE_2D,texture1); // set texture wrapping parameters glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); // SET texture filting parameters glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // load image,create texture,generate mipmaps QImage image1 = QImage(":/image/image/container.jpg").convertToFormat(QImage::Format_RGB888); if (!image1.isNull()){ glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,image1.width(),image1.height(),0,GL_RGB,GL_UNSIGNED_BYTE,image1.bits()); glGenerateMipmap(GL_TEXTURE_2D); } // texture2 glGenTextures(1,&texture2); glBindTexture(GL_TEXTURE_2D,texture2); // set texture wrapping parameters glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); // SET texture filting parameters glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); // load image,create texture,generate mipmaps QImage image2 = QImage(":/image/image/awesomeface.png").convertToFormat(QImage::Format_RGBA8888).mirrored(true, true); if (!image2.isNull()){ // note that the awesomeface.png has transparency and thus an alpha channel, so make sure to tell OpenGL the data type is of GL_RGBA glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,image2.width(),image2.height(),0,GL_RGBA,GL_UNSIGNED_BYTE,image2.bits()); glGenerateMipmap(GL_TEXTURE_2D); } // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) m_program.bind(); // don't forget to activate/use the shader before setting uniforms! glUniform1i(m_program.uniformLocation("texture1"),0); glUniform1i(m_program.uniformLocation("texture2"),1); m_program.release(); } void Widget::resizeGL(int w, int h) { glViewport(0,0,w,h); } void Widget::paintGL() { glClearColor(0.2f,0.3f,0.3f,1.0f); glClear(GL_COLOR_BUFFER_BIT); // bind textures on corresponding texture units glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,texture1); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D,texture2); // create transformations QMatrix4x4 transform; transform.translate(QVector3D(0.5f, -0.5f, 0.0f)); transform.rotate(m_nTimeValue, QVector3D(0.0f, 0.0f, 1.0f)); // get matrix's uniform location and set matrix m_program.bind(); int transformLoc = m_program.uniformLocation("transform"); glUniformMatrix4fv(transformLoc, 1, GL_FALSE, transform.data()); glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_INT,NULL); m_program.release(); }
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QOpenGLWidget> #include <QOpenGLFunctions_3_3_Core> #include <QOpenGLShader> #include <QOpenGLShaderProgram> namespace Ui { class Widget; } class Widget : public QOpenGLWidget,protected QOpenGLFunctions_3_3_Core { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); protected: virtual void initializeGL(); virtual void resizeGL(int w,int h); virtual void paintGL(); public slots: void slotTimer(); private: QOpenGLShaderProgram m_program; QTimer* m_timer; int m_nTimeValue; private: Ui::Widget *ui; }; #endif // WIDGET_H
析构函数要记得释放 glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteBuffers(1, &EBO);
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aColor; layout (location = 2) in vec2 aTexCoord; out vec3 ourColor; out vec2 TexCoord; uniform mat4 transform; void main() { gl_Position = transform * vec4(aPos, 1.0f); ourColor = aColor; TexCoord = aTexCoord; //TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y); }
#version 330 core out vec4 FragColor; in vec3 ourColor; in vec2 TexCoord; uniform sampler2D texture1; uniform sampler2D texture2; void main() { //FragColor = texture(texture1, TexCoord) * vec4(ourColor, 1.0); FragColor = mix(texture(texture1, TexCoord), texture(texture2, TexCoord), 0.2); }
使用Qt相关函数版
尝试再次调用glDrawElements画出第二个箱子,只使用变换将其摆放在不同的位置。让这个箱子被摆放在窗口的左上角,并且会不断的缩放(而不是旋转)
#include "qtfunwidget.h" #include <QTimer> QtFunWidget::QtFunWidget(QWidget *parent) : QOpenGLWidget(parent) ,vbo(QOpenGLBuffer::VertexBuffer) ,ebo(QOpenGLBuffer::IndexBuffer) { m_timer = new QTimer(this); connect(m_timer,&QTimer::timeout,this,[=]{ m_timeValue += 5; update(); }); m_timer->start(50); } QtFunWidget::~QtFunWidget() { /*Prepares for rendering OpenGL content for this widget by making * the corresponding context current and binding the framebuffer object in that context. It is not necessary to call this function in most cases, because it is called automatically before invoking paintGL(). */ makeCurrent(); vbo.destroy(); ebo.destroy(); if(texture1) delete texture1; if(texture2) delete texture2; doneCurrent(); } void QtFunWidget::initializeGL() { this->initializeOpenGLFunctions(); int success = m_program.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/textures.vert"); if (!success) { qDebug() << "program addShaderFromSourceFile Failed." << m_program.log(); return; } success = m_program.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/textures.frag"); if (!success) { qDebug() << "program addShaderFromSourceFile Failed." << m_program.log(); return; } success = m_program.link(); if (!success) { qDebug() << "program link Failed." << m_program.log(); } // VAO VBO VEO data float vertices[] = { // positions // colors // texture coords 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left }; unsigned int indices[] = { // note that we start from 0! 0, 1, 3, // first Triangle 1, 2, 3 // second Triangle }; QOpenGLVertexArrayObject::Binder vaobind(&vao); vbo.create(); vbo.bind(); vbo.allocate(vertices,sizeof(vertices)); ebo.create(); ebo.bind(); ebo.allocate(indices,sizeof(indices)); // position attribute int attr = -1; attr = m_program.attributeLocation("aPos"); m_program.setAttributeBuffer(attr,GL_FLOAT,0,3,8*sizeof(GL_FLOAT)); m_program.enableAttributeArray(attr); // color attribute attr = m_program.attributeLocation("aColor"); m_program.setAttributeBuffer(attr,GL_FLOAT,3*sizeof(GL_FLOAT),3,8*sizeof(GL_FLOAT)); m_program.enableAttributeArray(attr); // texture coord attribute attr = m_program.attributeLocation("aTexCoord"); m_program.setAttributeBuffer(attr,GL_FLOAT,6*sizeof(GL_FLOAT),2,8*sizeof(GL_FLOAT)); m_program.enableAttributeArray(attr); // texture1 //直接生成绑定一个2d纹理, 并生成多级纹理MipMaps texture1 = new QOpenGLTexture(QImage(":/image/container.jpg"),QOpenGLTexture::GenerateMipMaps); if(!texture1->isCreated()){ qDebug() << "failed to load texture."; } texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);// 等于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters texture1->setMinificationFilter(QOpenGLTexture::Linear); //等价于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); texture1->setMagnificationFilter(QOpenGLTexture::Linear); // texture2 //直接生成绑定一个2d纹理, 并生成多级纹理MipMaps texture2 = new QOpenGLTexture(QImage(":/image/awesomeface.png").mirrored(true,true),QOpenGLTexture::GenerateMipMaps); if(!texture2->isCreated()){ qDebug() << "failed to load texture."; } texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);// 等于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters texture2->setMinificationFilter(QOpenGLTexture::Linear); //等价于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); texture2->setMagnificationFilter(QOpenGLTexture::Linear); m_program.bind(); m_program.setUniformValue("texture1",0); m_program.setUniformValue("texture2",1); vbo.release(); // remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound. // ebo.release(); } void QtFunWidget::resizeGL(int w, int h) { glViewport(0,0,w,h); } void QtFunWidget::paintGL() { glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // bind textures on corresponding texture units glActiveTexture(GL_TEXTURE0); texture1->bind(); glActiveTexture(GL_TEXTURE1); texture2->bind(); // create transformations QMatrix4x4 transform; transform.translate(QVector3D(0.5f, -0.5f, 0.0f)); transform.rotate(m_timeValue, QVector3D(0.0f, 0.0f, 1.0f)); m_program.bind(); m_program.setUniformValue("transform", transform); {// render container QOpenGLVertexArrayObject::Binder vaoBind(&vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); } // create transformations QMatrix4x4 transform2; transform2.translate(QVector3D(-0.5f, 0.5f, 0.0f)); float scaleAmount = sin(m_timeValue); transform2.scale(QVector3D(scaleAmount, scaleAmount, scaleAmount)); //m_program.bind(); m_program.setUniformValue("transform", transform2); {// render container QOpenGLVertexArrayObject::Binder vaoBind(&vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); } texture1->release(); texture2->release(); m_program.release(); }
#include "qtfunwidget.h" #include <QTimer> QtFunWidget::QtFunWidget(QWidget *parent) : QOpenGLWidget(parent) ,vbo(QOpenGLBuffer::VertexBuffer) ,ebo(QOpenGLBuffer::IndexBuffer) { m_timer = new QTimer(this); connect(m_timer,&QTimer::timeout,this,[=]{ m_timeValue += 5; update(); }); m_timer->start(50); } QtFunWidget::~QtFunWidget() { /*Prepares for rendering OpenGL content for this widget by making * the corresponding context current and binding the framebuffer object in that context. It is not necessary to call this function in most cases, because it is called automatically before invoking paintGL(). */ makeCurrent(); vbo.destroy(); ebo.destroy(); if(texture1) delete texture1; if(texture2) delete texture2; doneCurrent(); } void QtFunWidget::initializeGL() { this->initializeOpenGLFunctions(); int success = m_program.addShaderFromSourceFile(QOpenGLShader::Vertex,":/shader/textures.vert"); if (!success) { qDebug() << "program addShaderFromSourceFile Failed." << m_program.log(); return; } success = m_program.addShaderFromSourceFile(QOpenGLShader::Fragment,":/shader/textures.frag"); if (!success) { qDebug() << "program addShaderFromSourceFile Failed." << m_program.log(); return; } success = m_program.link(); if (!success) { qDebug() << "program link Failed." << m_program.log(); } // VAO VBO VEO data float vertices[] = { // positions // colors // texture coords 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left }; unsigned int indices[] = { // note that we start from 0! 0, 1, 3, // first Triangle 1, 2, 3 // second Triangle }; QOpenGLVertexArrayObject::Binder vaobind(&vao); vbo.create(); vbo.bind(); vbo.allocate(vertices,sizeof(vertices)); ebo.create(); ebo.bind(); ebo.allocate(indices,sizeof(indices)); // position attribute int attr = -1; attr = m_program.attributeLocation("aPos"); m_program.setAttributeBuffer(attr,GL_FLOAT,0,3,8*sizeof(GL_FLOAT)); m_program.enableAttributeArray(attr); // color attribute attr = m_program.attributeLocation("aColor"); m_program.setAttributeBuffer(attr,GL_FLOAT,3*sizeof(GL_FLOAT),3,8*sizeof(GL_FLOAT)); m_program.enableAttributeArray(attr); // texture coord attribute attr = m_program.attributeLocation("aTexCoord"); m_program.setAttributeBuffer(attr,GL_FLOAT,6*sizeof(GL_FLOAT),2,8*sizeof(GL_FLOAT)); m_program.enableAttributeArray(attr); // texture1 //直接生成绑定一个2d纹理, 并生成多级纹理MipMaps texture1 = new QOpenGLTexture(QImage(":/image/container.jpg"),QOpenGLTexture::GenerateMipMaps); if(!texture1->isCreated()){ qDebug() << "failed to load texture."; } texture1->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);// 等于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); texture1->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters texture1->setMinificationFilter(QOpenGLTexture::Linear); //等价于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); texture1->setMagnificationFilter(QOpenGLTexture::Linear); // texture2 //直接生成绑定一个2d纹理, 并生成多级纹理MipMaps texture2 = new QOpenGLTexture(QImage(":/image/awesomeface.png").mirrored(true,true),QOpenGLTexture::GenerateMipMaps); if(!texture2->isCreated()){ qDebug() << "failed to load texture."; } texture2->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);// 等于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); texture2->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // set texture filtering parameters texture2->setMinificationFilter(QOpenGLTexture::Linear); //等价于glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); texture2->setMagnificationFilter(QOpenGLTexture::Linear); m_program.bind(); m_program.setUniformValue("texture1",0); m_program.setUniformValue("texture2",1); vbo.release(); // remember: do NOT unbind the EBO while a VAO is active as the bound element buffer object IS stored in the VAO; keep the EBO bound. // ebo.release(); } void QtFunWidget::resizeGL(int w, int h) { glViewport(0,0,w,h); } void QtFunWidget::paintGL() { glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); // bind textures on corresponding texture units glActiveTexture(GL_TEXTURE0); texture1->bind(); glActiveTexture(GL_TEXTURE1); texture2->bind(); // create transformations QMatrix4x4 transform; transform.translate(QVector3D(0.5f, -0.5f, 0.0f)); transform.rotate(m_timeValue, QVector3D(0.0f, 0.0f, 1.0f)); m_program.bind(); m_program.setUniformValue("transform", transform); {// render container QOpenGLVertexArrayObject::Binder vaoBind(&vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); } texture1->release(); texture2->release(); m_program.release(); }
#ifndef QTFUNWIDGET_H #define QTFUNWIDGET_H #include <QWidget> #include <QOpenGLWidget> #include <QOpenGLShader> #include <QOpenGLShaderProgram> #include <QOpenGLFunctions> #include <QOpenGLVertexArrayObject> #include <QOpenGLBuffer> #include <QOpenGLTexture> class QtFunWidget : public QOpenGLWidget,protected QOpenGLFunctions { Q_OBJECT public: QtFunWidget(QWidget *parent = 0); ~QtFunWidget() Q_DECL_OVERRIDE; protected: virtual void initializeGL() Q_DECL_OVERRIDE; virtual void resizeGL(int w,int h) Q_DECL_OVERRIDE; virtual void paintGL() Q_DECL_OVERRIDE; private: QOpenGLShaderProgram m_program; QOpenGLBuffer vbo,ebo; QOpenGLVertexArrayObject vao; QOpenGLTexture *texture1{nullptr}; QOpenGLTexture *texture2{nullptr}; QTimer *m_timer{nullptr}; int m_timeValue{0}; }; #endif // QTFUNWIDGET_H