OpenGL多纹理处理
一、纹理处理流程
-
纹理加载与配置
通过QImage
加载图片并生成纹理对象:QImage image(":/texture.jpg"); image = image.convertToFormat(QImage::Format_RGBA8888); glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits()); glGenerateMipmap(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
2. 多纹理支持
若需不同纹理,可创建多个纹理对象并使用glActiveTexture
切换或者调用纹理对象bind(0)切换。// 绑定纹理 m_texture->bind(0); m_program.setUniformValue("texture1", 0); // 绘制矩形 glBindVertexArray(VAO[0]); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
二、代码
#ifndef GLWIDGET_H
#define GLWIDGET_H
// 头文件 GLWidget.h
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QPainter>
class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions_4_5_Core {
public:
explicit GLWidget(QWidget *parent = nullptr): QOpenGLWidget(parent){
};
~GLWidget(){
makeCurrent();
delete m_texture;
delete m_texture_text;
glDeleteBuffers(2, VBO);
glDeleteBuffers(2, EBO);
glDeleteVertexArrays(2, VAO);
doneCurrent();
};
protected:
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
QImage createTextTexture(const QString& text, int width, int height);
private:
QOpenGLShaderProgram m_program;
QOpenGLTexture *m_texture;
QOpenGLTexture *m_texture_text;
GLuint VAO[2], VBO[2], EBO[2];
QMatrix4x4 m_modelMatrix;
};
QImage GLWidget::createTextTexture(const QString& text, int width, int height) {
QImage image(width, height, QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.setPen(Qt::white);
painter.setFont(QFont("Arial", 24));
painter.drawText(image.rect(), Qt::AlignCenter, text);
painter.end();
// OpenGL 纹理坐标系原点在左下角,需垂直翻转图像
return image.mirrored(false, true);
}
// 实现文件 GLWidget.cpp
void GLWidget::initializeGL() {
initializeOpenGLFunctions();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
// 编译着色器
m_program.addShaderFromSourceCode(QOpenGLShader::Vertex,
"#version 450 core\n"
"layout (location=0) in vec3 aPos;\n"
"layout (location=1) in vec2 aTexCoord;\n"
"out vec2 TexCoord;\n"
"uniform mat4 model;\n"
"void main() {\n"
" gl_Position = model * vec4(aPos, 1.0);\n"
" TexCoord = aTexCoord;\n"
"}");
m_program.addShaderFromSourceCode(QOpenGLShader::Fragment,
"#version 450 core\n"
"in vec2 TexCoord;\n"
"in float vPosY;\n"
"out vec4 FragColor;\n"
"uniform sampler2D texture1;\n"
"void main() {\n"
" FragColor = texture(texture1, TexCoord);\n"
"}");
bool b = m_program.link();
if(!b){
qDebug() << "Shader Error:" << m_program.log();
}
// 顶点数据(包含位置和纹理坐标)
float vertices1[] = {
// positions // texture coords
-0.8f, -0.8f, 0.0f, 0.0f, 0.0f,
0.0f, -0.8f, 0.0f, 1.0f, 0.0f,
-0.8f, 0.8f, 0.0f, 0.0f, 1.0f,
0.0f, 0.8f, 0.0f, 1.0f, 1.0f
};
float vertices2[] = {
// positions // texture coords
0.0f, -0.8f, 0.0f, 0.0f, 0.0f,
0.8f, -0.8f, 0.0f, 1.0f, 0.0f,
0.0f, 0.8f, 0.0f, 0.0f, 1.0f,
0.8f, 0.8f, 0.0f, 1.0f, 1.0f
};
// 创建VBO和VAO
glGenVertexArrays(2, VAO);
glGenBuffers(2, VBO);
glGenBuffers(2, EBO); // 可选(用于索引绘制)
//配置VAO
glBindVertexArray(VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices1), vertices1, GL_STATIC_DRAW);
// 将索引数据复制到 EBO(如果有)
unsigned int indices1[] = {0, 1, 2,
1, 3, 2};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices1), indices1, GL_STATIC_DRAW);
// 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
//配置VAO
glBindVertexArray(VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices2), vertices2, GL_STATIC_DRAW);
// 将索引数据复制到 EBO(如果有)
unsigned int indices2[] = {0, 1, 2,
1, 3, 2};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2), indices2, GL_STATIC_DRAW);
// 设置顶点属性指针
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(3*sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
// 加载纹理
m_texture = new QOpenGLTexture(QImage(":/textures/wood.jpg").mirrored());
m_texture->setWrapMode(QOpenGLTexture::Repeat);
m_texture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
QImage textImage = createTextTexture("Hello OpenGL!", 256, 32);
m_texture_text = new QOpenGLTexture(textImage);
m_texture_text->setWrapMode(QOpenGLTexture::Repeat);
m_texture_text->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
}
void GLWidget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT);
m_program.bind();
// 设置模型矩阵(平移变换)
m_modelMatrix.setToIdentity();
m_modelMatrix.translate(0.0f, 0.0f, 0.0f);
m_program.setUniformValue("model", m_modelMatrix);
// 绑定纹理
m_texture->bind(0);
m_program.setUniformValue("texture1", 0);
// 绘制矩形
glBindVertexArray(VAO[0]);
//glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// 绑定纹理
m_texture_text->bind(0);
m_program.setUniformValue("texture1", 0);
// 绘制矩形
glBindVertexArray(VAO[1]);
//glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
m_program.release();
}
void GLWidget::resizeGL(int w, int h) {
glViewport(0, 0, w, h);
}
#endif // GLWIDGET_H