专栏首页Pou光明Qt5.12 + OpenGL 创建第一个多边形Core版

Qt5.12 + OpenGL 创建第一个多边形Core版

原教程地址:

https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/

程序参考地址:

https://blog.csdn.net/z136411501/article/details/79834381

这里介绍第二种方法,使用QOpenGLFunctions_3_3_Core类对象,Core类其实是一种Qt对OpenGL特定版本的包装类对象,可以直接使用该版本OpenGL的所有函数。

效果图如下:

代码和之前比“几乎”没变,只是把所有gl开头的函数都换成了

m_core->gl ******来调用了。

头文件如下:

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>

class MyGLWidget : public QOpenGLWidget
{
    Q_OBJECT

public:
    MyGLWidget();

    ~MyGLWidget();

protected:
    virtual void initializeGL();
    virtual void resizeGL(int w, int h);
    virtual void paintGL();

private:
    //顶点缓冲对象 Vertex Buffer Object,VBO,教程中第一个出现的OpenGL对象
    GLuint VBO;               
    GLuint VAO;

    GLuint EBO;

    GLuint m_shaderProgram;    //着色器程序对象
    QOpenGLFunctions_3_3_Core *m_core;

这里我们不再继承 QOpenGLExtraFunctions,对gl相关函数的调用则是通过m_core进行。

源文件如下:

//着色器语言GLSL(OpenGL Shading Language)编写的顶点着色器
static const char *vertexShaderSource =
        "#version 330 core\n"
        "layout(location = 0) in vec3 aPos;\n"
        "void main(){\n"
        "  gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
        "}\n\0";


//着色器语言GLSL(OpenGL Shading Language)编写的片段着色器
static const char *fragmentShaderSource =
        "#version 330 core\n"
        "out vec4 FragColor;\n"
        "void main(){\n"
        "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
        "}\n\0";

#if 0
    #define TRIANGLE
#elif 1
    #define RECTANGLE
#endif

MyGLWidget::MyGLWidget()
{

}

MyGLWidget::~MyGLWidget()
{

}

void MyGLWidget::initializeGL()
{

    m_core = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();//获取上下文

    //着色器部分
    GLuint vertexShader = m_core->glCreateShader(GL_VERTEX_SHADER);                //创建顶点着色器对象
    m_core->glShaderSource(GLuint(vertexShader), 1, &vertexShaderSource, nullptr); //着色器源码附加到着色器对象
    m_core->glCompileShader(GLuint(vertexShader));                                 //编译

    int is_success;                                             //检查是否编译成功,未成功则需返回错误
    char infoLog[512];
    m_core->glGetShaderiv(GLuint(vertexShader), GL_COMPILE_STATUS, &is_success);
    if (!is_success)
    {
        m_core->glGetShaderInfoLog(GLuint(vertexShader), 512, nullptr, infoLog);
        qDebug() << "ERROR::SHADER::VERTEX::COMPILATION_FAILED" << infoLog ;
    }


    GLuint fragmentShader = m_core->glCreateShader(GL_FRAGMENT_SHADER);  //创建片段着色器对象,与顶点着色器相似
    m_core->glShaderSource(GLuint(fragmentShader), 1, &fragmentShaderSource, nullptr);
    m_core->glCompileShader(GLuint(fragmentShader));

    m_core->glGetShaderiv(GLuint(fragmentShader), GL_COMPILE_STATUS, &is_success);
    if (!is_success)
    {
        m_core->glGetShaderInfoLog(GLuint(fragmentShader), 512, nullptr, infoLog);
        qDebug() << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED" << infoLog;
    }


    m_shaderProgram = m_core->glCreateProgram();                         //创建着色器程序对象
    m_core->glAttachShader(m_shaderProgram, GLuint(vertexShader));
    m_core->glAttachShader(m_shaderProgram, GLuint(fragmentShader));
    m_core->glLinkProgram(m_shaderProgram);                              //之前编译的着色器附加到程序对象上

    m_core->glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &is_success);//检查是否编译成功,未成功则需返回错误
    if (!is_success) {
        m_core->glGetProgramInfoLog(m_shaderProgram, 512, nullptr, infoLog);
        qDebug() << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog ;
    }

    m_core->glDeleteShader(vertexShader);                               //着色器对象链接到程序对象以后,删除着色器对象
    m_core->glDeleteShader(fragmentShader);

    //VAO,VBO数据部分

#ifdef TRIANGLE
    GLfloat vertices[] = {
        -0.5f, -0.5f, 0.0f, // left
        0.5f, -0.5f, 0.0f,  // right
        0.0f,  0.5f, 0.0f   // top
    };
#else                                      //绘制矩形
    GLfloat vertices[] = {
         0.5f,  0.5f, 0.0f,  // top right
         0.5f, -0.5f, 0.0f,  // bottom right
        -0.5f, -0.5f, 0.0f,  // bottom left
        -0.5f,  0.5f, 0.0f   // top left
    };

    unsigned int indices[] = { // 注意索引从0开始!
        0, 1, 3, // 第一个三角形
        1, 2, 3  // 第二个三角形
    };
#endif
//两个参数,第一个为需要创建的缓存数量。第二个为用于存储单一ID或多个ID的GLuint变量或数组的地址
    m_core->glGenVertexArrays(1, &VAO);          
    m_core->glGenBuffers(1, &VBO);               //顶点缓冲对象处理
    m_core->glGenBuffers(1, &EBO);
    m_core->glBindVertexArray(VAO);
    m_core->glBindBuffer(GL_ARRAY_BUFFER, VBO);  //使用glBindBuffer函数把新创建的缓冲绑定到GL_ARRAY_BUFFER目标上
    //之前定义的顶点数据复制到缓冲的内存中
    m_core->glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);      
#ifdef RECTANGLE
    m_core->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    m_core->glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
#endif
//glVertexAttribPointer函数告诉OpenGL该如何解析顶点数据(应用到逐个顶点属性上)
    m_core->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), nullptr);  
    m_core->glEnableVertexAttribArray(0);        //以顶点属性位置值作为参数,启用顶点属性;顶点属性默认是禁用的

    m_core->glBindBuffer(GL_ARRAY_BUFFER, 0);
    m_core->glBindVertexArray(0);

}

void MyGLWidget::resizeGL(int w, int h)
{
    m_core->glViewport(0, 0, w, h);
}

void MyGLWidget::paintGL()
{
    m_core->glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    m_core->glClear(GL_COLOR_BUFFER_BIT);

    m_core->glUseProgram(m_shaderProgram); //激活程序对象
    m_core->glBindVertexArray(VAO);
#ifdef TRIANGLE
    m_core->glDrawArrays(GL_TRIANGLES, 0, 3);
#else                                         //绘制矩形
    m_core->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
#endif
//    glUseProgram(0);

}

小结:

对于程序中 文字解释的排版欢迎大家多提出宝贵的意见,感谢!

本文分享自微信公众号 - Pou光明(pou0230),作者:PouG

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 编程这么久, 它们了解多少(一)

    对于日志,一般情况下可以设置日志输出等级、输出到终端或文件、输出到每个文件的大小、日志被覆盖的策略,还有的可以在程序运行过程中更改日志的等级,或者将日志输出到远...

    用户5908113
  • Qt线程中使用Socket客户端通信

    在编写一般程序中,通常将通信部分与数据处理部分单独放到一个线程或进程(Python由于GIL锁需要使用进程),这样可保证程序的快速响应,数据处理不会对其他部分造...

    用户5908113
  • Python Socket传输图片

    我们在传输数据时,经常使用tcp/ip的服务器和客户端模型,很多设备也经常将网口作为硬件接口预留出来。可以使用tcp/ip传输图像、大的文件等,如果图片过大,还...

    用户5908113
  • linux下core file size设置笔记

    现象说明:突然发现一台测试机器的java程序莫名其妙地没了,但是没有core dump!这就需要打开服务器的core文件生成的功能了,(即core dump文件...

    洗尽了浮华
  • linux core文件机制

    在程序不寻常退出时,内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息)。使用gdb来查看core文件,可以指示出导致程序出错的代码所...

    一见
  • Linux下使用gdb调试core文件

    当程序运行过程中出现Segmentation fault (core dumped)错误时,程序停止运行,并产生core文件。core文件是程序运行状态的内存映...

    Dabelv
  • linux 下 core 相关知识总结

    在以往的测试过程中,每当遇到程序出现coredump的状况,我的第一反应就是有bug,让开发定位原因,但是如果自己能够去挖掘原因,在与开发沟通的过程中能明确指出...

    易惠芳
  • CMake 进行调试

    在 Linux 下开发,可以用 gdb 进行调试,但是如果工程是用 CMake 构建的,那么需要在 CMakeLists.txt 中加入如下代码:

    Frank909
  • Linux下core文件的使用方法详解

    有时候程序会异常退出而不带任何日志,此时就可以使用 code 文件进行分析,它会记录程序运行的内存,寄存器,堆栈指针等信息

    砸漏
  • 如何快速定位找出SEGV内存错误的程序Bug

    通过查看php日志/usr/local/php/var/log/php-fpm.log,有如下警告信息:

    sunsky

扫码关注云+社区

领取腾讯云代金券