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

欢迎关注我,一起交流!

相关推荐
再睡一夏就好21 分钟前
string.h头文件中strcpy、memset等常见函数的使用介绍与模拟实现
c语言·c++·笔记·string·内存函数·strcpy
('-')32 分钟前
《从根上理解MySQL是怎样运行的》第十三章笔记
数据库·笔记·mysql
LO嘉嘉VE1 小时前
学习笔记二十一:深度学习
笔记·深度学习·学习
代码游侠2 小时前
学习笔记——数据结构学习
linux·开发语言·数据结构·笔记·学习
摇滚侠2 小时前
零基础小白自学 Git_Github 教程,发现工具寻找灵感,笔记04
笔记·github
玦尘、2 小时前
《统计学习方法》第4章——朴素贝叶斯法【学习笔记】
笔记·机器学习
风123456789~2 小时前
【健康管理】第4章 常见慢性病 4.7慢阻肺 2/2
笔记·考证·健康管理
遇到困难睡大觉哈哈2 小时前
Harmonny os——《从 TypeScript 到 ArkTS 的适配规则》精简笔记
笔记·typescript·harmonyos·鸿蒙
Ccjf酷儿3 小时前
操作系统 李治军 1 操作系统基础
笔记
Ghost-Silver3 小时前
《星火》——关于Deepseek的进化速度
笔记·算法