QT中学习Opengl---(基本创建与绘制三角形)

前言:

很久没有更新博客,打算用最近的一段时间来完成Opengl的学习,如果大家也想学习的话,可以跟我一起学习。本学习内容为 LearnOpenGL 中的知识点,在qt中编程,因为QT已经封装好了对应的东西,我们不需要glfw 与 glad 。

简单说明:

  • glfw   是配合 OpenGL 使用的轻量级工具程序库,缩写自 Graphics Library Framework(图形库框架)。GLFW 的主要功能是创建并管理窗口和 OpenGL 上下文,同时还提供了处理手柄、键盘、鼠标输入的功能。
  • glad  是glfw的升级版本,经常使用gladLoadGLLoader 来获取gpu中的指针函数,这样就可以使用Opengl 中的api。

然后我们在qt中可以不用考虑这样一件事。

qt基本布局使用:

QT中学习Opengl---(基本创建与绘制三角形)_第1张图片

 中间黑色的部分对应控件为:

QT中学习Opengl---(基本创建与绘制三角形)_第2张图片

 这里我界面为了好看些吧,添加了样式,这个你自己看着办吧。

然后我把这个控件提升为我自己写的类中。

QT中学习Opengl---(基本创建与绘制三角形)_第3张图片

 不会提升类的小伙伴们,还是把qt基础学习好了,在说吧。或者可以看我博客qt对应的基础学习。

https://blog.csdn.net/weixin_42126427/category_9666776.html?spm=1001.2014.3001.5482

 然后在类中我们要这样写

#ifndef BKQOPENGLW_H
#define BKQOPENGLW_H

#include 
#include 

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

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

signals:

public slots:

private:
unsigned int VBO, VAO;
unsigned int shaderProgram;
};

#endif // BKQOPENGLW_H

QOpenGLFunctions_3_3_Core 这里是使用对应的版本号,这里使用的是3.3.因为书中使用的是这个,为了统一这里使用了3.3版本的api函数。

这里从写了三个继承的函数

virtual void initializeGL(); //初始化数据
virtual void resizeGL(int w, int h); //改变窗口大小
virtual void paintGL();//主要绘制数据

        写完后,我们也要从显卡gpu中获取对应指针函数,我们上面说使用的是 glad 的 gladLoadGLLoader来获取的,但是在qt中我们使用的是

initializeOpenGLFunctions();

这个函数功能就是glad 的gladLoadGLLoader 的作用。

而我们继承的QOpenGLWidget 可以看作是glfw 的作用,这样你也很快的了解了吧。

顶点数组对象(Vertex Array Object, VAO)

     opengl是一个状态机的概念,可以把VAO当成工头(这里管理顶点数组对象的),他手下可以管理很多工人,他是知道对应的工人的消息,当我们想用了解某个工人的时候,我们不用直接找对应工人,我们直接找这个工头,让他来找到你要的工人信息。

顶点缓冲对象(Vertex Buffer Objects, VBO)

      VBO是管理顶点数据的缓冲对象。你可以理解就是工人(对应技术的),他是可以拿到顶点数据,然后后期发送个gpu,让gpu知道你数据顶点

我们以一个图:

QT中学习Opengl---(基本创建与绘制三角形)_第4张图片

 比如VAO (工头)数据管理 VBO (工人),VBO 中记录了大量的顶点数据。 

比如代码段:

const float vertices[] = {
    -0.5f, -0.5f, 0.0f, // left
     0.5f, -0.5f, 0.0f, // right
     0.0f,  0.5f, 0.0f  // top
};

void BKQOpenglW::initializeGL()
{
    initializeOpenGLFunctions();
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0);
}

 通过glGenVertexArrays 创建vao , glGenBuffers(1, &VBO); 创建vbo。

然后是绑定部分,glBufferData来写入我们的顶点数据GL_STATIC_DRAW表示为静态。

glVertexAttribPointer 通过这个来告诉gpu按着这个规则来执行。偏移量为0 然后3个数据一组,数据是float类型,不用标准,然后告诉整个顶点的大小。

 glBindVertexArray(VAO);

 glBindBuffer(GL_ARRAY_BUFFER, VBO);
 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
 glEnableVertexAttribArray(0);

然后我们绑定完后可以使用:

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

来告诉工头与工人,你们去休息吧,有事我就开始在来找你,找人的时候我们在绑定就可以了。

glBindVertexArray(VAO); //呼叫工头

图形渲染管线

下面就是 图形渲染管线 流程图了,蓝色部分就是我们可以是自定义的着色器。没有定义的话,就使用默认。

QT中学习Opengl---(基本创建与绘制三角形)_第5张图片

 我们把顶点相关东西处理好了,然后我们要开始给图形对应的着色器了。

顶点着色器(Vertext Shader)

 现代OpenGL需要我们至少设置一个顶点和一个片段着色器, 如果我们打算做渲染的话。这里就是设置基本是xyz坐标相关

#version 330 core
layout (location = 0) in vec3 position;
void main()
{
gl_Position = vec4(position.x, position.y, position.z, 1.0);
}
//上面是对应的代码段,但是我们需要的是下面的字符串模式。

//顶点着色器
const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";

片段着色器

 这里主要是对颜色处理。计算机图形中颜色被表示为有4个元素的数组: 红色、 绿色、 蓝色和alpha(透明度)元素, 通常缩写为RGBA

#version 330 core
out vec4 color;
void main()
{
color = vec4(1.0f, 0.5f, 0.2f, 1.0f);//RGBA
}

//上面是对应的代码段,但是我们需要的是下面的字符串模式。
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";

对应绑定代码:

    //创建顶点着色器
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader,1,&vertexShaderSource,(nullptr));
    glCompileShader(vertexShader);
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader,GL_COMPILE_STATUS,&success);
    if (!success)
    {
       glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
       std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    //创建片段着色器
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
    glCompileShader(fragmentShader);
    // check for shader compile errors
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    //链接着色器
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram,vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

然后通过链接着色器把,顶点与片段的着色器链接起来

shaderProgram = glCreateProgram();
glAttachShader(shaderProgram,vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);

  然后我们使用的使用直接调用glUseProgram(shaderProgram); 就告诉了gpu当前应该使用那些着色器了。

绘制三角形 

 

QT中学习Opengl---(基本创建与绘制三角形)_第6张图片

 绘制代码:

void BKQOpenglW::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES,0,3);
}

这里我们

glUseProgram(shaderProgram);
glBindVertexArray(VAO);

就告诉gpu我们用的着色器,与对应顶点数据(工头)

让后使用

glDrawArrays(GL_TRIANGLES,0,3);

绘制图形。这里简单说下,opengl中能后绘制的多边形只能是三角形,也就是所所有图形都是三角形变化过来的。

整体代码:

#ifndef BKQOPENGLW_H
#define BKQOPENGLW_H

#include 
#include 

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

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

signals:

public slots:

private:
unsigned int VBO, VAO;
unsigned int shaderProgram;
};

#endif // BKQOPENGLW_H

对应cpp

#include "bkqopenglw.h"
#include
const float vertices[] = {
    -0.5f, -0.5f, 0.0f, // left
     0.5f, -0.5f, 0.0f, // right
     0.0f,  0.5f, 0.0f  // top
};

//顶点着色器
const char *vertexShaderSource = "#version 330 core\n"
    "layout (location = 0) in vec3 aPos;\n"
    "void main()\n"
    "{\n"
    "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
    "}\0";
//片段着色器
const char *fragmentShaderSource = "#version 330 core\n"
    "out vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "   FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
    "}\n\0";

BKQOpenglW::BKQOpenglW(QWidget *parent) : QOpenGLWidget(parent)
{

}

void BKQOpenglW::initializeGL()
{
    initializeOpenGLFunctions();
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    // bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
    glEnableVertexAttribArray(0);

    // note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    // You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
    // VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
    glBindVertexArray(0);

    //创建顶点着色器
    unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader,1,&vertexShaderSource,(nullptr));
    glCompileShader(vertexShader);
    int success;
    char infoLog[512];
    glGetShaderiv(vertexShader,GL_COMPILE_STATUS,&success);
    if (!success)
    {
       glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
       std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    //创建片段着色器
    unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderSource, nullptr);
    glCompileShader(fragmentShader);
    // check for shader compile errors
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
    }

    //链接着色器
    shaderProgram = glCreateProgram();
    glAttachShader(shaderProgram,vertexShader);
    glAttachShader(shaderProgram, fragmentShader);
    glLinkProgram(shaderProgram);
    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
    if (!success) {
        glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
    }
    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);
}

void BKQOpenglW::resizeGL(int w, int h)
{
       glViewport(0,0,w,h);
}

void BKQOpenglW::paintGL()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES,0,3);
}

喜欢我博客的小伙伴们,也同时想在qt上学习opengl的伙伴,可以关注与点赞博客,让我们共同进步吧。

你可能感兴趣的:(Qt之Opengl,qt,opengl,三角形,vao,vbo)