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

一、作用原理

1、作用:将一张图片(纹理)映射到几何体表面,提升视觉真实感,不增加几何复杂度。
2、原理:加载图片为纹理 → 上传到 GPU;为顶点设置纹理坐标(如 0~1 范围);GPU 在渲染时 插值纹理坐标;片元着色器中采样纹理颜色 → 显示图案。简单说,就是“把图贴上去”。

二、实现效果
在这里插入图片描述
三、参考代码

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

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

欢迎关注我,一起交流!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星火撩猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值