Qt和OpenGL:渲染2D纹理

时间:2018-10-29 17:56:47

标签: c++ qt opengl textures

我正在尝试使用Qt和OpenGL渲染我的第一个纹理。

这是代码。

initializeGL 函数

void OpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    glEnable(GL_DEBUG_OUTPUT);
    glDebugMessageCallback(debugCallback, nullptr);

    program = genProgram("../06_HelloTexture/vert.glsl", "../06_HelloTexture/frag.glsl");
    glUseProgram(program);

    glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
    glEnable(GL_DEPTH_TEST);

    // vertices is std::vector<QVector3D>
    vertices = {
        {-0.5f, -0.5f, 0.0f}, {0.0f, 0.0f, 0.0f},
        {-0.5f, +0.5f, 0.0f}, {0.0f, 1.0f, 0.0f},
        {+0.5f, -0.5f, 0.0f}, {1.0f, 0.0f, 0.0f},
        {+0.5f, +0.5f, 0.0f}, {1.0f, 1.0f, 0.0f},
    };

    // indices is std::vector<GLuint>
    indices = {
        0, 1, 2,
        1, 2, 3,
    };

    GLuint VAO, VBO, EBO;

    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(QVector3D), &vertices[0], GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size()*sizeof(GLuint), &indices[0], GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 2*sizeof(QVector3D), static_cast<void*>(nullptr));
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 2*sizeof(QVector3D), (void*)sizeof(QVector3D));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    QImage image("../lightbulb-solid.svg");
    // QImage image("../test.png");
    qDebug() << image;
    // this outputs
    // QImage(QSize(352, 512),format=6,depth=32,devicePixelRatio=1,bytesPerLine=1408,sizeInBytes=720896)

    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.constBits());
    // glGenerateMipmap(GL_TEXTURE_2D);

    lightbulbSolidLocation = glGetUniformLocation(program, "lightbulbSolid");
    glUniform1i(lightbulbSolidLocation, 0);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
}

paintGL 功能

void OpenGLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, nullptr);
}

顶点着色器

#version 450 core
layout (location = 0) in vec3 vertPosition;
layout (location = 1) in vec3 vertTexCoord;

out vec3 fragTexCoord;

void main()
{
    gl_Position = vec4(vertPosition, 1.0);
    fragTexCoord = vertTexCoord;
}

片段着色器

#version 450 core
in vec3 fragTexCoord;
out vec4 pixelColor;

uniform sampler2D lightbulbSolid;

void main()
{
    // pixelColor = vec4(fragColor, 1.0f);
    // pixelColor = texture(lightbulbSolid, vec2(fragTexCoord.x, fragTexCoord.y));

    vec4 temp = texture(lightbulbSolid, vec2(fragTexCoord.x, fragTexCoord.y));

    if (!all(equal(temp.xyz, vec3(0.0f))))
    {
        pixelColor = temp;
    }
    else
    {
        pixelColor = vec4(fragTexCoord, 1.0f);
    }
}

这就是结果

enter image description here

如您所见,片段着色器中纹理函数生成的所有颜色都是黑色,因此if语句选择纹理坐标作为颜色,而不是真实的纹理颜色。

我试图捕获一些错误,但是回调函数在代码中没有发现错误。我还尝试了另一张图像(PNG格式而不是SVG),但是结果是相同的。

1 个答案:

答案 0 :(得分:1)

如果要加载PNG文件,则可以直接将其加载到QImage

QImage image("../test.png");

但如果要渲染SVG文件,则必须使用QSvgRendererQPainter将内容绘制到QImage。您必须选择目标位图的格式,分辨率和背景色:

例如:

#include <Qtsvg/QSvgRenderer>

QSvgRenderer renderer(QString("../lightbulb-solid.svg"));

QImage image(512, 512, QImage::Format_RGBA8888);  // 512x512 RGBA
image.fill(0x00ffffff);                           // white background

QPainter painter(&image);
renderer.render(&painter);

const uchar *image_bits = image.constBits();
int          width      = image.width();
int          height     = image.height();

注意,您必须分别链接 qt5svgd.lib (调试) qt5svg.lib (发行版)。


默认缩小功能参数(GL_TEXTURE_MIN_FILTER)为GL_NEAREST_MIPMAP_LINEAR。参见glTexParameteri

这意味着您必须将GL_TEXTURE_MIN_FILTER参数更改为GL_LINEAR

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
             GL_RGBA, GL_UNSIGNED_BYTE, image_bits);

或者您必须创建mipmaps

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
             GL_RGBA, GL_UNSIGNED_BYTE, image_bits);

glGenerateMipmap(GL_TEXTURE_2D);

initializeGL方法中,纹理绑定到纹理单元0,但不能保证它仍然是paintGL方法中的当前状态。您必须使用paintGL方法绑定纹理:

void OpenGLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(indices.size()), GL_UNSIGNED_INT, nullptr);
}