基于Qt的OPenGL可编程管线学习之Hello Triangle

 

之前学习过OpenGL的固定管线,后来了解到现在大部分公司都用可编程管线(programmable pipeline)。所以决定开始研究学习可编程管线。Qt5.*之后对OPenGL的支持更好了。经过一番学习,写了一个基于Qt 的OpenGL例子—— Hello Triangle Demo,在此记录一下加深一下印象,同时让像我一样的新手快速入门。本文假定您对OPenGL 的固定管线有所了解。

一、GLSL(OPenGL Shading Language)初探

现在只需要理解该语言用于编写运行在GPU上程序——“着色器”。下文会介绍如何编写着色器程序。现在先看看一些基本的语法特点。

$1.1类型修饰符

1> uniform:被uniform修饰的变量是在CPU程序中设置好的变量,对于着色器(vertex shader/fragment shader)只可以读。我们的CPU程序通过调用glUniform*()函数来对该变量赋值。例如下文中我们会使用代码来设置与平接头体(frustum)相关的矩阵供着色器使用。

// CPU Application 代码片段
_program->setUniformValue(_matrixUniform, matrix);

// shader代码片段
uniform highp mat4 matrix;

2> attribute:被attribute修饰的变量是只能在vertex shader中使用的变量。不能在fragment shader中声明attribute变量,也不能被fragment shader使用。attribute表示一些顶点的数据比如:顶点坐标,法线,纹理坐标,顶点颜色等。

// CPU 顶点与颜色属性设置;
glVertexAttribPointer(_posAttr, 2, GL_FLOAT, GL_FALSE,0, vertexs);
glVertexAttribPointer(_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors);

// vertex shader代码片段,位置(posAttr)、颜色(colAttr)属性;
layout (location = 0) in vec4 posAttr;
attribute lowp vec4 colAttr;

3> varying :被varying修饰的变量是vertex和fragment shader之间做数据传递用的。一般vertex shader修改该变量的值,然后fragment shader使用该变量的值。因此变量在vertex和fragment shader二者之间的声明必须是一致的。CPU 程序不能使用此变量。

// vertex sharder
varying lowp vec4 col;
col = colAttr; // 赋值;

// fragment sharder
varying lowp vec4 col;
gl_FragColor = col; // 读取到gl_FragColor[shader build-in]

二、CPU程序编码流程

这里简单列出Qt5OPenGL的使用方法,具体的OPenGL函数使用方式,将在下一篇与VAO一起陈述,基本流程如下图所示:

1.子类化QOpenGLWidget,重写下边函数。

2.初始化:初始化opengl函数(Qt 要求)——》编写着色器——》编译着色器——》链接着色器——》获取属性等的位置

3. 视口映射。

4.绘制

class QOpenGLShaderProgram;

class OpenGLWidget : public QOpenGLWidget,
        protected QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    explicit OpenGLWidget(QWidget *parent = nullptr);

protected:
    void initializeGL() override;
    void resizeGL(int widget, int height) override;
    void paintGL() override;

private:
    QOpenGLShaderProgram *_program;
    GLuint _posAttr;
    GLuint _colAttr;
    GLuint _matrixUniform;
};
void OpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0.f, 0.f, 0.f,1.f);

    const static char *vertexShaderStr =
        "#version 330 core\n"
        "layout (location = 0) in vec4 posAttr;\n"
         "attribute lowp vec4 colAttr;\n"
        "varying lowp vec4 col;\n"
        "uniform highp mat4 matrix;\n"
        "void main()\n"
        "{\n"
         "  col = colAttr;\n"
        "   gl_Position = matrix * posAttr;\n"
        "}\n";

    const static char *fragmentShaderStr =
        "#version 330 core\n"
        "varying lowp vec4 col;\n"
        "void main()\n"
         "{\n"
            "gl_FragColor = col;\n"
         "}\n";

    QOpenGLShader *vertexShader =
            new QOpenGLShader(QOpenGLShader::Vertex, this);
    vertexShader->compileSourceCode(vertexShaderStr);

    QOpenGLShader *fragmentShader =
            new QOpenGLShader(QOpenGLShader::Fragment, this);
    fragmentShader->compileSourceCode(fragmentShaderStr);

    _program = new QOpenGLShaderProgram(this);
    _program->addShader(vertexShader);
    _program->addShader(fragmentShader);
    _program->link();


    _posAttr = _program->attributeLocation("posAttr");
    _colAttr = _program->attributeLocation("colAttr");
    _matrixUniform = _program->uniformLocation("matrix");
}

 

void OpenGLWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}
void OpenGLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);

    static GLfloat vertexs[] = {
        0.0f, 0.707f,
        -0.5f, -0.5f,
        0.5f, -0.5f
    };

    static GLfloat colors[] = {
        1.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 1.0f
    };

    _program->bind();

    QMatrix4x4 matrix;
    matrix.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f);
    matrix.translate(0, 0, -2);


    _program->setUniformValue(_matrixUniform, matrix);
    glVertexAttribPointer(_posAttr, 2, GL_FLOAT, GL_FALSE,0, vertexs);
    glVertexAttribPointer(_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors);

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glDrawArrays(GL_TRIANGLES, 0, 3);

    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(0);

    _program->release();

}

三、运行结果

 

四、参考文献

Qt document

《OPenGL编程指南 9th edition》

下一篇将记录如何使用VAO以及介绍OPenGL绘制三角形的细节。 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值