简体   繁体   English

Qt5 OpenGL纹理采样

[英]Qt5 OpenGL Texture Sampling

I'm trying to render a QImage using OpenGL wrapper classes of Qt5 and shader programs. 我正在尝试使用Qt5和着色器程序的OpenGL包装器类渲染QImage I have the following shaders and a 3.3 core context. 我有以下着色器和3.3核心上下文。 I'm also using a VAO for the attributes. 我还在属性中使用VAO。 However, I keep getting a blank red frame (red is the background clear color that I set). 但是,我一直得到一个空白的红色框(红色是我设置的背景透明色)。 I'm not sure if it is a problem with the MVP matrices or something else. 我不确定MVP矩阵或其他问题。 Using a fragment shader which sets the output color to a certain fixed color (black) still resulted in a red frame. 使用片段着色器将输出颜色设置为某个固定颜色(黑色)仍会导致红框。 I'm totally lost here. 我在这里完全迷路了。

EDIT-1: I also noticed that attempting to get the location of texRGB uniform from the QOpenGLShaderProgram results in -1. EDIT-1:我还注意到,尝试从QOpenGLShaderProgram获取texRGB统一的位置QOpenGLShaderProgram导致-1。 But I'm not sure if that has anything to do with the problem I'm having. 但是我不确定这是否与我遇到的问题有关。 Uniforms defined in the vertex shader for the MVP matrices have the locations 0 and 1. 在顶点着色器中为MVP矩阵定义的均匀位置为0和1。

Vertex Shader 顶点着色器

#version 330

layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec2 inTexCoord;

out vec2 vTexCoord;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;


void main(void)
{
    gl_Position = projectionMatrix * modelViewMatrix * vec4(inPosition, 1.0);

    // pass the input texture coordinates to fragment shader
    vTexCoord = inTexCoord;    
}

Fragment Shader 片段着色器

#version 330

uniform sampler2DRect texRGB;

in vec2 vTexCoord;

out vec4 fColor;

void main(void)
{
    vec3 rgb = texture2DRect(texRGB, vTexCoord.st).rgb;
    fColor = vec4(rgb, 0.0);
}

OGLWindow.h OGLWindow.h

#include <QOpenGLWindow>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLTexture>

#include <QDebug>
#include <QString>

class OGLWindow : public QOpenGLWindow, protected QOpenGLFunctions
{
public:
    OGLWindow();
    ~OGLWindow();

    // OpenGL Events
    void initializeGL();
    void resizeGL(int width, int height);
    void paintGL();

    // a method for cleanup
    void teardownGL();

private:
    bool isInitialized;

    // OpenGL state information
    QOpenGLBuffer               m_vbo_position;
    QOpenGLBuffer               m_vbo_index;
    QOpenGLBuffer               m_vbo_tex_coord;
    QOpenGLVertexArrayObject    m_object;
    QOpenGLShaderProgram*       m_program;

    QImage                      m_image;
    QOpenGLTexture*             m_texture;

    QMatrix4x4                  m_projection_matrix;
    QMatrix4x4                  m_model_view_matrix;

};

OGLWindow.cpp OGLWindow.cpp

#include "OGLWindow.h"

// vertex data
static const QVector3D vertextData[] = {
                           QVector3D(-1.0f, -1.0f,  0.0f),
                           QVector3D( 1.0f, -1.0f,  0.0f),
                           QVector3D( 1.0f,  1.0f,  0.0f),
                           QVector3D(-1.0f,  1.0f,  0.0f)
};

// indices
static const GLushort indices[] = {
                           0,  1,  2,
                           0,  2,  3
};

OGLWindow::OGLWindow() :
    m_vbo_position      (QOpenGLBuffer::VertexBuffer),
    m_vbo_tex_coord     (QOpenGLBuffer::VertexBuffer),
    m_vbo_index         (QOpenGLBuffer::IndexBuffer),
    m_program           (nullptr),
    m_texture           (nullptr),
    isInitialized       (false)
{
}

OGLWindow::~OGLWindow()
{
    makeCurrent();
    teardownGL();
}

void OGLWindow::initializeGL()
{
    qDebug() << "initializeGL()";

    initializeOpenGLFunctions();
    isInitialized = true;

    QColor backgroundColor(Qt::red);
    glClearColor(backgroundColor.redF(), backgroundColor.greenF(), backgroundColor.blueF(), 1.0f);

    // load texture image
    m_image = QImage(":/images/cube.png");

    m_texture = new QOpenGLTexture(QOpenGLTexture::TargetRectangle);

    // set bilinear filtering mode for texture magnification and minification
    m_texture->setMinificationFilter(QOpenGLTexture::Nearest);
    m_texture->setMagnificationFilter(QOpenGLTexture::Nearest);

    // set the wrap mode
    m_texture->setWrapMode(QOpenGLTexture::ClampToEdge);

    m_texture->setData(m_image.mirrored(), QOpenGLTexture::MipMapGeneration::DontGenerateMipMaps);

    int imgWidth = m_image.width();
    int imgHeight = m_image.height();

    m_projection_matrix.setToIdentity();
    m_projection_matrix.ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
//    m_projection_matrix.ortho(0.0, (float) width(), (float) height(), 0.0f, -1.0f, 1.0f);

    m_model_view_matrix.setToIdentity();

    glViewport(0, 0, width(), height());

    m_program = new QOpenGLShaderProgram();
    m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vshader.glsl");
    m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fshader.glsl");
    m_program->link();
    m_program->bind();

    // texture coordinates
    static const QVector2D textureData[] = {
                               QVector2D(0.0f,              0.0f),
                               QVector2D((float) imgWidth,  0.0f),
                               QVector2D((float) imgWidth,  (float) imgHeight),
                               QVector2D(0.0f,              (float) imgHeight)
    };

    // create Vertex Array Object (VAO)
    m_object.create();
    m_object.bind();

    // create position VBO
    m_vbo_position.create();
    m_vbo_position.bind();
    m_vbo_position.setUsagePattern(QOpenGLBuffer::StaticDraw);
    m_vbo_position.allocate(vertextData, 4 * sizeof(QVector3D));

    // create texture coordinates VBO
    m_vbo_tex_coord.create();
    m_vbo_tex_coord.bind();
    m_vbo_tex_coord.setUsagePattern(QOpenGLBuffer::StaticDraw);
    m_vbo_tex_coord.allocate(textureData, 4 * sizeof(QVector2D));

    // create the index buffer
    m_vbo_index.create();
    m_vbo_index.bind();
    m_vbo_index.setUsagePattern(QOpenGLBuffer::StaticDraw);
    m_vbo_index.allocate(indices, 6 * sizeof(GLushort));

    // enable the two attributes that we have and set their buffers
    m_program->enableAttributeArray(0);
    m_program->enableAttributeArray(1);

    m_program->setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(QVector3D));
    m_program->setAttributeBuffer(1, GL_FLOAT, 0, 2, sizeof(QVector2D));

    // Set modelview-projection matrix
    m_program->setUniformValue("projectionMatrix", m_projection_matrix);
    m_program->setUniformValue("modelViewMatrix", m_model_view_matrix);

    // use texture unit 0 which contains our frame
    m_program->setUniformValue("texRGB", 0);

    // release (unbind) all
    m_object.release();
    m_vbo_position.release();
    m_vbo_tex_coord.release();
    m_vbo_index.release();
    m_program->release();    
}

void OGLWindow::resizeGL(int width, int height)
{
    qDebug() << "resizeGL(): width =" << width << ", height=" << height;
    if (isInitialized) {

        // avoid division by zero
        if (height == 0) {
            height = 1;
        }

        m_projection_matrix.setToIdentity();
        m_projection_matrix.perspective(60.0, (float) width / (float) height, -1, 1);

        glViewport(0, 0, width, height);
    }

}

void OGLWindow::paintGL()
{
    // clear
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // render using our shader
    m_program->bind();
    {
        m_texture->bind();

        m_object.bind();
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0) );
        m_object.release();
    }
    m_program->release();
}

void OGLWindow::teardownGL()
{
    // actually destroy our OpenGL information
    m_object.destroy();
    m_vbo_position.destroy();
    m_vbo_color.destroy();
    delete m_program;    
}

EDIT-2: I'm creating the context as follows: EDIT-2:我正在如下创建上下文:

QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3,3);

This line in your fragment shader code is invalid: 您的片段着色器代码中的这一行无效:

vec3 rgb = texture2DRect(texRGB, vTexCoord.st).rgb;

texture2DRect() is not a built-in function. texture2DRect()不是内置函数。

Since you're using the GLSL 3.30 core profile ( core is the default for the version unless compatibility is specified), you should be using the overloaded texture() function, which replaces the older type specific functions like texture2D() in the core profile. 由于您使用的是GLSL 3.30核心配置文件(除非指定了compatibility ,否则版本默认为core ),因此您应该使用重载的texture()函数,该函数将替换核心配置文件中较早类型的特定函数,例如texture2D()

Functions like texture2D() are still supported in GLSL 3.30 core unless a forward compatible core profile context is used. 除非使用了前向兼容的核心配置文件上下文,否则GLSL 3.30核心仍支持诸如texture2D()类的功能。 So depending on how the context is created, you can still use those functions. 因此,根据上下文的创建方式,您仍然可以使用这些功能。

However, sampler2DRect was only added as a sampler type in GLSL 1.40 as part of adding rectangular textures to the standard in OpenGL 3.1. 但是, sampler2DRect仅作为GLSL 1.40中的采样器类型添加,作为向OpenGL 3.1中的标准添加矩形纹理的一部分。 At the time, the legacy sampling functions were already marked as deprecated, and only the new texture() function was defined for rectangular textures. 当时,旧采样函数已被标记为已弃用,并且仅为矩形纹理定义了新的texture()函数。 This means that texture2DRect() does not exist in any GLSL version. 这意味着texture2DRect()任何 GLSL版本中都不存在。

The correct call is: 正确的呼叫是:

vec3 rgb = texture(texRGB, vTexCoord.st).rgb;

Another part of your code that can prevent it from rendering anything is this projection matrix: 您的代码的另一部分可以防止其呈现任何内容,是此投影矩阵:

m_projection_matrix.perspective(60.0, (float) width / (float) height, -1, 1);

The near and far planes for a standard projection matrix both need to be positive. 标准投影矩阵的近平面和远平面都必须为正。 This call will set up a projection transformation with a "camera" on the origin, looking down the negative z-axis. 此调用将建立投影变换,其原点带有“相机”,并沿负z轴向下看。 The near and far values are distances from the origin. 接近值和远端值是距原点的距离。 A valid call could look like this: 有效的呼叫可能如下所示:

m_projection_matrix.perspective(60.0, (float) width / (float) height, 1.0f, 10.0f);

You will then also need to set the model matrix to transform the coordinates of the object into this range on the negative z-axis. 然后,您还需要设置模型矩阵,以将对象的坐标转换为负z轴上的该范围。 You could for example apply a translation by (0.0f, 0.0f, -5.0f) . 例如,您可以应用(0.0f, 0.0f, -5.0f)

Or, if you just want to see something , the quad should also become visible if you simply use the identity matrix for the projection. 或者,如果您只想看一些东西 ,则只需将恒等矩阵用于投影,四边形也应可见。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM