OpenGl实战笔记(2)基于qt5.15.2+mingw64+opengl实现纹理贴图

一、作用原理

1、作用:将一张图片(纹理)映射到几何体表面,提升视觉真实感,不增加几何复杂度。

2、原理:加载图片为纹理 → 上传到 GPU;为顶点设置纹理坐标(如 0~1 范围);GPU 在渲染时 插值纹理坐标;片元着色器中采样纹理颜色 → 显示图案。简单说,就是"把图贴上去"。

二、实现效果

三、参考代码

读取本地的png图片贴到四边形几何体表面

cpp 复制代码
//TextureRenderer 类
#pragma once
#include "RenderModuleInterface.h"
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QImage>
#include <QMatrix4x4>

// 简单纹理渲染器:负责初始化 OpenGL 资源、加载纹理并进行屏幕渲染
class TextureRenderer : public RenderModuleInterface, protected QOpenGLFunctions
{
public:
    TextureRenderer();
    ~TextureRenderer();

    // 初始化 OpenGL 状态与资源,只执行一次
    void initialize() override;

    // 设置视口大小(通常来自窗口resize事件)
    void resize(int w, int h) override;

    // 执行渲染流程(清屏、绑定shader和纹理、绘制)
    void render() override;

    // 设置外部纹理图像(功能扩展)
    void setTextureImage(const QImage& image);

    // 设置 MVP(模型视图投影)矩阵,可用于变换控制
    void setModelMatrix(const QMatrix4x4& model);

private:
    QOpenGLShaderProgram shader;      // 着色器程序
    QOpenGLTexture* texture = nullptr;// 纹理对象
    QOpenGLBuffer vbo;                // 顶点缓冲对象
    QOpenGLVertexArrayObject vao;     // 顶点数组对象

    QMatrix4x4 mvpMatrix;             // 模型视图投影矩阵
    int viewportWidth = 0;            // 视口宽度
    int viewportHeight = 0;           // 视口高度
    bool isInitialized = false;       // 初始化标志
};
#include "TextureRenderer.h"
#include <QDebug>

// 顶点着色器源码:传递位置与纹理坐标,并应用 MVP 变换
static const char* vertexShaderSrc = R"(
#version 330 core
layout(location = 0) in vec2 position;
layout(location = 1) in vec2 texCoord;
out vec2 TexCoord;
uniform mat4 u_mvp;
void main()
{
    TexCoord = texCoord;
    gl_Position = u_mvp * vec4(position, 0.0, 1.0);
})";
// 片段着色器源码:根据纹理坐标采样颜色输出
static const char* fragmentShaderSrc = R"(
#version 330 core
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D u_texture;
void main()
{
    FragColor = texture(u_texture, TexCoord);
})";
TextureRenderer::TextureRenderer() {}
TextureRenderer::~TextureRenderer()
{
    if (texture) {
        delete texture;
        texture = nullptr;
    }
    vao.destroy();
    vbo.destroy();
}
void TextureRenderer::initialize()
{
    if (isInitialized) return;
    initializeOpenGLFunctions();

    if (shader.isLinked()) return;

    // 设置清除背景色
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

    // 默认创建蓝色纹理(128x128)
    QImage img(128, 128, QImage::Format_RGBA8888);
    img.fill(QColor(0, 0, 255, 255));
    texture = new QOpenGLTexture(img.mirrored());

    // 编译并链接着色器
    bool vs = shader.addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSrc);
    bool fs = shader.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSrc);
    if (!vs || !fs || !shader.link()) {
        qDebug() << "Shader Compile Error:" << shader.log();
        return;
    }

    // 顶点数据(位置 + 纹理坐标)
    GLfloat vertices[] = {
        -0.5f, -0.5f,  0.0f, 0.0f,
        0.5f, -0.5f,  1.0f, 0.0f,
        0.5f,  0.5f,  1.0f, 1.0f,
        0.5f,  0.5f,  1.0f, 1.0f,
        -0.5f,  0.5f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.0f, 0.0f
    };

    shader.bind();
    vao.create();
    vao.bind();

    vbo.create();
    vbo.bind();
    vbo.allocate(vertices, sizeof(vertices));

    // 配置顶点属性指针
    shader.enableAttributeArray(0); // position
    shader.setAttributeBuffer(0, GL_FLOAT, 0, 2, 4 * sizeof(float));
    shader.enableAttributeArray(1); // texCoord
    shader.setAttributeBuffer(1, GL_FLOAT, 2 * sizeof(float), 2, 4 * sizeof(float));

    vao.release();
    vbo.release();
    shader.release();

    // 设置默认正交投影矩阵
    mvpMatrix.ortho(-1, 1, -1, 1, -1, 1);

    isInitialized = true;
}
void TextureRenderer::resize(int w, int h)
{
    glViewport(0, 0, w, h);
    viewportWidth = w;
    viewportHeight = h;
}
void TextureRenderer::render()
{
    if (!isInitialized) return;

    glClear(GL_COLOR_BUFFER_BIT);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    shader.bind();
    vao.bind();

    // 设置变换矩阵
    shader.setUniformValue("u_mvp", mvpMatrix);

    // 绑定纹理并设置纹理单元
    glActiveTexture(GL_TEXTURE0);
    texture->bind();
    shader.setUniformValue("u_texture", 0);

    glDrawArrays(GL_TRIANGLES, 0, 6);

    texture->release();
    vao.release();
    shader.release();
}
void TextureRenderer::setTextureImage(const QImage& image)
{
    if (!image.isNull()) {
        if (texture) {
            delete texture;
            texture = nullptr;
        }
        texture = new QOpenGLTexture(image.mirrored());
    }
}
void TextureRenderer::setModelMatrix(const QMatrix4x4& model)
{
    mvpMatrix = model;
}

//使用,这里默认创建的是蓝色纹理,设置图片后将其覆盖了
modules["纹理贴图"] = new TextureRenderer();
// 加载砖墙纹理图片
QImage image(":/images/wall.png");
modules["纹理贴图"]->initialize();
if (!image.isNull()) {
     dynamic_cast<TextureRenderer*>(modules["纹理贴图"])->setTextureImage(image);
}

欢迎关注我,一起交流!

相关推荐
觉醒大王3 分钟前
AI写的青基中了
人工智能·笔记·深度学习·学习·职场和发展·学习方法
明月醉窗台12 分钟前
qt使用笔记六之 Qt Creator、Qt Widgets、Qt Quick 详细解析
开发语言·笔记·qt
Hello_Embed3 小时前
libmodbus 移植 STM32(USB 串口后端篇)
笔记·stm32·单片机·嵌入式·freertos·libmodbus
alvin_20053 小时前
python之OpenGL应用(二)Hello Triangle
python·opengl
张祥6422889043 小时前
RTKLIB源码和理论结合分析笔记三
笔记
日更嵌入式的打工仔3 小时前
0欧电阻作用
笔记
R_.L3 小时前
【QT】常用控件(按钮类控件、显示类控件、输入类控件、多元素控件、容器类控件、布局管理器)
开发语言·qt
wdfk_prog4 小时前
[Linux]学习笔记系列 -- [drivers][I2C]I2C
linux·笔记·学习
觉醒大王4 小时前
哪些文章会被我拒稿?
论文阅读·笔记·深度学习·考研·自然语言处理·html·学习方法
方安乐5 小时前
科普:股票 vs 债券的区别
笔记