IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> QT中学习Opengl---(基本创建与绘制三角形) -> 正文阅读

[C++知识库]QT中学习Opengl---(基本创建与绘制三角形)

前言:

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

简单说明:

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

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

qt基本布局使用:

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

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

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

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

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

?然后在类中我们要这样写

#ifndef BKQOPENGLW_H
#define BKQOPENGLW_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>

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知道你数据顶点

我们以一个图:

?比如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); //呼叫工头

图形渲染管线

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

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

顶点着色器(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当前应该使用那些着色器了。

绘制三角形?

?

?绘制代码:

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 <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>

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<iostream>
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的伙伴,可以关注与点赞博客,让我们共同进步吧。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-07 13:32:31  更:2022-02-07 13:33:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:28:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码