Qt5 OpenGL纹理采样

时间:2015-06-23 22:41:48

标签: qt opengl shader qt5 texture-mapping

我尝试使用Qt5和着色器程序的OpenGL包装类渲染QImage。我有以下着色器和3.3核心上下文。我也使用VAO作为属性。但是,我不断得到一个空白的红框(红色是我设置的背景清晰颜色)。我不确定它是否是MVP矩阵或其他问题。使用片段着色器将输出颜色设置为某个固定颜色(黑色)仍然会产生红色框。我完全迷失在这里。

EDIT-1:我还注意到,尝试从texRGB获取QOpenGLShaderProgram统一的位置会导致-1。但我不确定这与我遇到的问题有什么关系。在顶点着色器中为MVP矩阵定义的制服具有位置0和1。

顶点着色器

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

片段着色器

#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

#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

#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:我按如下方式创建了上下文:

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

1 个答案:

答案 0 :(得分:0)

片段着色器代码中的这一行无效:

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

texture2DRect()不是内置函数。

由于您使用的是GLSL 3.30核心配置文件(core是版本的默认值,除非指定了compatibility),您应该使用重载的texture()函数,它取代了核心配置文件中的texture2D()等旧类型特定功能。

除非使用前向兼容的核心配置文件上下文,否则GLSL 3.30核心仍支持texture2D()等功能。因此,根据上下文的创建方式,您仍然可以使用这些函数。

但是,sampler2DRect仅作为GLSL 1.40中的采样器类型添加,作为在OpenGL 3.1中向标准添加矩形纹理的一部分。当时,旧的采样函数已经标记为已弃用,并且仅为矩形纹理定义了新的texture()函数。这意味着任何 GLSL版本中都不存在texture2DRect()

正确的电话是:

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

代码的另一部分可以防止它呈现任何内容:这个投影矩阵:

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

标准投影矩阵的近和远平面都需要为正。此调用将使用&#34;相机&#34;设置投影转换。在原点上,向下看负z轴。 near far 值是距离原点的距离。有效的通话可能如下所示:

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

然后,您还需要设置模型矩阵,以将对象的坐标转换为负z轴上的此范围。例如,您可以按(0.0f, 0.0f, -5.0f)应用翻译。

或者,如果你只想看某事,如果你只是使用单一矩阵进行投影,那么四边形也应该可见。