簡體   English   中英

Qt 和 OpenGL:渲染 2D 紋理

[英]Qt & OpenGL : render a 2D texture

我正在嘗試使用 Qt 和 OpenGL 渲染我的第一個紋理。

這是代碼。

初始化GL函數

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

這就是結果

在此處輸入圖片說明

如您所見,片段着色器中紋理函數生成的所有顏色都是黑色,因此if語句選擇紋理坐標作為顏色而不是真實的紋理顏色。

我試圖捕捉一些錯誤,但回調函數沒有發現代碼中的錯誤。 我還嘗試了另一個圖像(PNG 格式而不是 SVG),但結果是一樣的。

如果你想加載一個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);

或者你必須創建 mipmap

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM