opengl png图片 qt_基于Qt的OpenGL学习(3)—— 纹理

简介

要学习OpenGL的话,强烈安利这个教程JoeyDeVries的learnopengl,这里是中文翻译好的版本。教程中使用OpenGL是通过GLFW这个库,而在Qt中对OpenGL封装得很好,并且和GUI以及IO相关的处理Qt更便捷,学习起来更轻松。这里就对每篇教程,在Qt在分别直接使用OpenGL的函数和Qt封装好的类以作对比。

教程中使用的OpenGL版本为3.3,在Qt中需要使用此版本的OpenGL只需要继承类QOpenGLFunctions_3_3_Core即可。如果为了在不同设备上都能用OpenGL的话,Qt提供了类QOpenGLFunctions,这个类包含了大部分公共的函数,可能会有个别函数不能用。

对比说明

教程地址

原教程地址,相关知识可以点击链接学习。

我的工程地址,准备后期每篇教程一个commit,可以切换着看,查看本篇代码 git checkout v1.3,喜欢就点个Star吧~

不同点 (仅列出新增)

Qt提供了QOpenGLTexture类来处理OpenGL中的Texture,并且创建的时候可以直接传递一个QImage给纹理对象,如果使用gl相关函数还要读取图片数据的data再设置,比较麻烦。

运行结果

273b7f960f3d

运行结果

使用OpenGL函数版

CoreFunctionWidget.h

#ifndef COREFUNCTIONWIDGET_H

#define COREFUNCTIONWIDGET_H

#include

#include

#include

#include

#include

class CoreFunctionWidget : public QOpenGLWidget

, protected /*QOpenGLExtraFunctions*/QOpenGLFunctions_3_3_Core

{

Q_OBJECT

public:

explicit CoreFunctionWidget(QWidget *parent = nullptr);

~CoreFunctionWidget();

protected:

virtual void initializeGL();

virtual void resizeGL(int w, int h);

virtual void paintGL();

private:

QOpenGLShaderProgram shaderProgram;

// QTimer* m_pTimer = nullptr;

// float m_uniformValue = 0.0f;

};

#endif // COREFUNCTIONWIDGET_H

CoreFunctionWidget.cpp

#include "CoreFunctionWidget.h"

#include

#include

static GLuint VBO, VAO, EBO, texture1, texture2;

CoreFunctionWidget::CoreFunctionWidget(QWidget *parent) : QOpenGLWidget(parent)

{

// m_pTimer = new QTimer(this);

// m_pTimer->setInterval(200);

// connect(m_pTimer, &QTimer::timeout, this, [=]{

// m_uniformValue += 0.1f;

// if (m_uniformValue > 1.5f) {

// m_uniformValue = -1.5f;

// }

// update();

// });

// m_pTimer->start();

}

CoreFunctionWidget::~CoreFunctionWidget()

{

glDeleteVertexArrays(1, &VAO);

glDeleteBuffers(1, &VBO);

glDeleteBuffers(1, &EBO);

}

void CoreFunctionWidget::initializeGL(){

this->initializeOpenGLFunctions();

bool success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/textures.vert");

if (!success) {

qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log();

return;

}

success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/textures.frag");

if (!success) {

qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log();

return;

}

success = shaderProgram.link();

if(!success) {

qDebug() << "shaderProgram link failed!" << shaderProgram.log();

}

//VAO,VBO 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 coord attribute

glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));

glEnableVertexAttribArray(2);

// texture 1

// ---------

glGenTextures(1, &texture1);

glBindTexture(GL_TEXTURE_2D, texture1);

// set the texture wrapping parameters

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

// set texture filtering 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 and generate mipmaps

QImage img1 = QImage(":/container.jpg").convertToFormat(QImage::Format_RGB888);

if (!img1.isNull()) {

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img1.width(), img1.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, img1.bits());

glGenerateMipmap(GL_TEXTURE_2D);

}

// texture 2

// ---------

glGenTextures(1, &texture2);

glBindTexture(GL_TEXTURE_2D, texture2);

// set the texture wrapping parameters

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

// set texture filtering 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 and generate mipmaps

QImage img2 = QImage(":/awesomeface.png").convertToFormat(QImage::Format_RGBA8888).mirrored(true, true);

if (!img2.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, img2.width(), img2.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img2.bits());

glGenerateMipmap(GL_TEXTURE_2D);

}

// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)

shaderProgram.bind(); // don't forget to activate/use the shader before setting uniforms!

glUniform1i(shaderProgram.uniformLocation("texture1"), 0);

glUniform1i(shaderProgram.uniformLocation("texture2"), 1);

shaderProgram.release();

// glBindBuffer(GL_ARRAY_BUFFER, 0);//取消VBO的绑定

// 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.

// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other

// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.

// glBindVertexArray(0); //取消VAO绑定

//线框模式,QOpenGLExtraFunctions没这函数, 3_3_Core有

// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

}

void CoreFunctionWidget::resizeGL(int w, int h){

glViewport(0, 0, w, h);

}

void CoreFunctionWidget::paintGL(){

glClearColor(0.2f, 0.3f, 0.3f, 1.0f);

glClear(GL_COLOR_BUFFER_BIT);

shaderProgram.bind();

{

// bind textures on corresponding texture units

glActiveTexture(GL_TEXTURE0);

glBindTexture(GL_TEXTURE_2D, texture1);

glActiveTexture(GL_TEXTURE1);

glBindTexture(GL_TEXTURE_2D, texture2);

// render container

glBindVertexArray(VAO);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

}

shaderProgram.release();

}

使用Qt相关函数版

QtFunctionWidget.h

#ifndef QTFUNCTIONWIDGET_H

#define QTFUNCTIONWIDGET_H

#include

#include

#include

#include

#include

#include

#include

#include

class QtFunctionWidget : public QOpenGLWidget, protected QOpenGLFunctions

{

public:

QtFunctionWidget(QWidget *parent = nullptr);

~QtFunctionWidget() 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 shaderProgram;

QOpenGLBuffer vbo, ebo;

QOpenGLVertexArrayObject vao;

QOpenGLTexture *texture1 = nullptr;

QOpenGLTexture *texture2 = nullptr;

// QTimer* m_pTimer = nullptr;

// float m_uniformValue = 0.0f;

};

#endif // QTFUNCTIONWIDGET_H

QtFunctionWidget.cpp

#include "QtFunctionWidget.h"

#include

#include

QtFunctionWidget::QtFunctionWidget(QWidget *parent) : QOpenGLWidget (parent),

vbo(QOpenGLBuffer::VertexBuffer),

ebo(QOpenGLBuffer::IndexBuffer)

{

// m_pTimer = new QTimer(this);

// m_pTimer->setInterval(200);

// connect(m_pTimer, &QTimer::timeout, this, [=]{

// m_uniformValue += 0.1f;

// if (m_uniformValue > 1.5f) {

// m_uniformValue = -1.5f;

// }

// update();

// });

// m_pTimer->start();

}

QtFunctionWidget::~QtFunctionWidget(){

makeCurrent();

vbo.destroy();

ebo.destroy();

vao.destroy();

delete texture1;

delete texture2;

doneCurrent();

}

void QtFunctionWidget::initializeGL(){

this->initializeOpenGLFunctions();

bool success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/textures.vert");

if (!success) {

qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log();

return;

}

success = shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/textures.frag");

if (!success) {

qDebug() << "shaderProgram addShaderFromSourceFile failed!" << shaderProgram.log();

return;

}

success = shaderProgram.link();

if(!success) {

qDebug() << "shaderProgram link failed!" << shaderProgram.log();

}

//VAO,VBO 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 = shaderProgram.attributeLocation("aPos");

shaderProgram.setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 8);

shaderProgram.enableAttributeArray(attr);

// color attribute

attr = shaderProgram.attributeLocation("aColor");

shaderProgram.setAttributeBuffer(attr, GL_FLOAT, sizeof(GLfloat) * 3, 3, sizeof(GLfloat) * 8);

shaderProgram.enableAttributeArray(attr);

// texture coord attribute

attr = shaderProgram.attributeLocation("aTexCoord");

shaderProgram.setAttributeBuffer(attr, GL_FLOAT, sizeof(GLfloat) * 6, 2, sizeof(GLfloat) * 8);

shaderProgram.enableAttributeArray(attr);

// texture 1

// ---------

texture1 = new QOpenGLTexture(QImage(":/container.jpg"), QOpenGLTexture::GenerateMipMaps); //直接生成绑定一个2d纹理, 并生成多级纹理MipMaps

if(!texture1->isCreated()){

qDebug() << "Failed to load texture";

}

// set the texture wrapping parameters

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);

// texture 2

// ---------

texture2 = new QOpenGLTexture(QImage(":/awesomeface.png").mirrored(true, true), QOpenGLTexture::GenerateMipMaps); //直接生成绑定一个2d纹理, 并生成多级纹理MipMaps

if(!texture2->isCreated()){

qDebug() << "Failed to load texture";

}

// set the texture wrapping parameters

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);

texture1->setMagnificationFilter(QOpenGLTexture::Linear);

// tell opengl for each sampler to which texture unit it belongs to (only has to be done once)

shaderProgram.bind(); // don't forget to activate/use the shader before setting uniforms!

shaderProgram.setUniformValue("texture1", 0);

shaderProgram.setUniformValue("texture2", 1);

shaderProgram.release();

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 QtFunctionWidget::resizeGL(int w, int h){

glViewport(0, 0, w, h);

}

void QtFunctionWidget::paintGL(){

glClearColor(0.2f, 0.3f, 0.3f, 1.0f);

glClear(GL_COLOR_BUFFER_BIT);

shaderProgram.bind();

{

glActiveTexture(GL_TEXTURE0);

texture1->bind();

// glBindTexture(GL_TEXTURE_2D, texture1->textureId());

glActiveTexture(GL_TEXTURE1);

texture2->bind();

// glBindTexture(GL_TEXTURE_2D, texture2->textureId());

// render container

QOpenGLVertexArrayObject::Binder vaoBind(&vao);

glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);

texture1->release();

texture2->release();

}

shaderProgram.release();

}

GLSL

textures.vert

#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;

void main()

{

gl_Position = vec4(aPos, 1.0);

ourColor = aColor;

TexCoord = aTexCoord;

}

textures.frag

#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);

}

main.cpp

#include

#include "MainWindow.h"

#include "QtFunctionWidget.h"

#include "CoreFunctionWidget.h"

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

{

QApplication a(argc, argv);

// MainWindow w;

QtFunctionWidget w1;

CoreFunctionWidget w2;

w1.setWindowTitle(QObject::tr("QtFunction"));

w2.setWindowTitle(QObject::tr("CoreFunction"));

w1.show();

w2.show();

return a.exec();

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值