Qt OpenGL(二十一)——Qt OpenGL 核心模式绘制一个三角形的流程

Qt OpenGL(二十一)——Qt OpenGL 核心模式绘制一个三角形的流程

一、写在前面

上一篇文章介绍了Qt Creator中的示例,旋转的三角形。本篇介绍通过OpenGL核心模式的代码实现绘制三角形,稍后会通过Qt封装的OpenGL核心模式的代码(即OpenGL 3.2及之后的版本)实现旋转的三角形。接下来的几篇会实现上一篇中的会旋转的彩色三角形。

 在OpenGL3.2版本之前,OpenGL使用的都是固定渲染管线的写法,在3.2版本之后,进入核心模式之后,使用的都是图形渲染管线。

渲染管线又称渲染流水线,它是图形图像从数据一步一步形成最终输出的画面所要经历的各种操作过程。

二、图形渲染管线

在OpenGL中,任何事物都在3D空间中,而我们的屏幕和窗口却是2D像素数组,所以OpenGL的大部分工作都是关于把3D坐标转变为适应你屏幕的2D像素。3D坐标转为2D坐标的处理过程是由OpenGL的图形渲染管线(Graphics Pipeline)管理的。图形渲染管线可以被划分为两个主要部分:

第一部分把3D坐标转换为2D坐标;

第二部分是把2D坐标转变为实际的有颜色的像素。
下图是图形渲染管线的每个阶段的抽象展示:

上图中蓝色部分代表的是我们可以注入自定义的着色器的部分。

顶点着色器(Vertex Shader),它把一个单独的顶点作为输入。顶点着色器主要的目的是把3D坐标转为另一种3D坐标(后面会解释),同时顶点着色器允许我们对顶点属性进行一些基本处理。

图元装配(Primitive Assembly)阶段将顶点着色器输出的所有顶点作为输入(如果是GL_POINTS,那么就是一个顶点),并所有的点装配成指定图元的形状;

图元装配阶段的输出会传递给几何着色器(Geometry Shader)。

几何着色器把图元形式的一系列顶点的集合作为输入,它可以通过产生新顶点构造出新的(或是其它的)图元来生成其他形状。

几何着色器的输出会被传入光栅化阶段(Rasterization Stage),这里它会把图元映射为最终屏幕上相应的像素,生成供片段着色器(Fragment Shader)使用的片段(Fragment)。在片段着色器运行之前会执行裁切(Clipping)。裁切会丢弃超出你的视图以外的所有像素,用来提升执行效率。

顶点数据是一些顶点的集合,顶点一般是3维的点坐标组成。

基本图元(Primitives)包括点,线段,三角形等,是构成实体模型的基本单位,需要在传入顶点数据的同时通知openGL这些顶点数据要组成的基本图元类型,并将并所有的点装配成指定图元的形状。

顶点着色器(Vertex Shader)包含对一些顶点属性(数据)的基本处理。

图元装配(Primitive Assembly)把所有输入的顶点数据作为输入,并将所有的点装配成指定图元的形状。

几何着色器(Geometry Shader):把基本图元形式的顶点的几何作为输入,可以通过产生新顶点构造出新的基本图元来生成其它形状。

光栅化(Rasterization):即像素化。把细分着色器输出的基本图形映射为屏幕上网格的像素点,生成供片段着色器处理的片段(Fragment),光栅化包含一个剪裁操作,会舍弃超出定义的视窗之外的像素。

片段着色器(Fragment Shader):主要作用是计算出每一个像素点最终的颜色,通常片段着色器会包含3D场景的一些额外的数据,如光线、阴影等。

测试与混合:是对每个像素点进行深度测试,Alpha测试等测试并进行颜色混合的操作,这些测试与混合操作决定了屏幕视窗上每个像素点最终的颜色以及透明度。

Note:通俗的理解,顶点着色器就是给予程序员一次操作一个顶点的能力,几何着色器就是给予程序员一次操作一个图元的能力,片段着色器就是给予程序员一次操作一个像素的能力。

在整个渲染管线中需要自定义处理的主要是顶点着色器和片段着色器。

三、几个基本的概念

在开始绘制图形之前,需要先了解几个非常重要的概念:

  • 顶点数组对象:Vertex Array Object,VAO
  • 顶点缓冲对象:Vertex Buffer Object,VBO
  • 元素缓冲对象:Element Buffer Object,EBO 或 索引缓冲对象 Index Buffer Object,IBO

本篇先介绍VAO和VBO。

VAO和VBO都是用来存储顶点信息的,并把这些信息送入顶点着色器。

顶点缓冲对象(Vertex Buffer Objects,VBO)
顶点缓冲对象VBO是在显卡存储空间中开辟出的一块内存缓存区,用于存储顶点的各类属性信息,如顶点坐标,顶点法向量,顶点颜色数据等。在渲染时,可以直接从VBO中取出顶点的各类属性数据,由于VBO在显存而不是在内存中,不需要从CPU传输数据,处理效率更高。

你可以用一句话这样理解,就是在GPU上创建内存,用于存储顶点数据。

顶点数组对象(Vertex Arrary Object,VAO)
VBO保存了一个模型的顶点属性信息,每次绘制模型之前需要绑定顶点的所有信息,当数据量很大时,重复这样的动作变得非常麻烦。VAO可以把这些所有的配置都存储在一个对象中,每次绘制模型时,只需要绑定这个VAO对象就可以了。 VAO是一个保存了所有顶点数据属性的状态结合,它对应上一个VBO和一个EBO(如果存在)。

你可以用一句话这样理解,VAO就是怎么去解释顶点的数据结构的。

后续的文章会再次介绍VAO和VBO的,以及EBO的。

四、绘制

开始创建一个继承QOpenGLWidget QOpenGLFunctions_3_3_Core的类。

本篇的代码是主要是用作展示绘制一个三角形的流程,后续会使用Qt封装的类。

#ifndef VAOOPENGLWIDGET_H
#define VAOOPENGLWIDGET_H

#include <QObject>
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>

class VAOOpenGLWidget : public QOpenGLWidget, public QOpenGLFunctions_3_3_Core
{
public:
    VAOOpenGLWidget(QWidget *parent = nullptr);

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

#endif // VAOOPENGLWIDGET_H
#include "vaoopenglwidget.h"


unsigned int VAO, VBO;

float vertices[] = {
    -0.5f,-0.5f,0.0f,
    0.5f,-0.5f,0.0f,
    0.0f,0.5f,0.0f,
};


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

}

void VAOOpenGLWidget::initializeGL()
{
    //step 1.初始化,指向OpenGL函数.
    initializeOpenGLFunctions();

    //step 2. create VAO&VBO.
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);

    //step 3. bind VAO&VBO.
    glBindVertexArray(VAO);
    glBindBuffer( GL_ARRAY_BUFFER, VBO );

    //step 4. 把顶点数据绑定到目标上(你这样理解,把数据CPU->GPU上保存,方便接下来快速绘制)
    glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW ); //

    //step 5. 告诉显卡如何解析.
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);

    //step 6. 开启VAO的第一个属性值.
    glEnableVertexAttribArray(0);

    //step 7. 释放.
    glBindBuffer( GL_ARRAY_BUFFER, 0 );
    glBindVertexArray( 0 );
}


void VAOOpenGLWidget::resizeGL(int w, int h)
{

}

void VAOOpenGLWidget::paintGL()
{
    glClearColor( 0.1f,0.1f,0.1f,1.0f );
    glClear( GL_COLOR_BUFFER_BIT );

    glBindVertexArray(VAO);

    glDrawArrays( GL_TRIANGLES, 0, 3 );

    glBindVertexArray(0);
}

看一下运行效果:

 五、上色

接下来还是使用这个风格的代码给三角形上色,最后会使用Qt封装的OpenGL绘制一个上一篇一模一样的会旋转的彩色三角形,我们一篇一篇展开,顺便把一些基础的概念和函数学习一下。

等基础的分享结束后,抽空再分享一些项目中常用的。

上一篇:Qt OpenGL(二十)——Qt OpenGL 核心模式版本

下一篇:Qt OpenGL(二十二)——Qt OpenGL 核心模式-VAO和VBO

本文原创作者:冯一川(ifeng12358@163.com),未经作者授权同意,请勿转载。

可以使用以下代码来在 Qt 中使用 OpenGL 绘制三角形: ```cpp #include <QtGui/QOpenGLFunctions> #include <QtGui/QOpenGLShaderProgram> #include <QtGui/QOpenGLVertexArrayObject> #include <QtGui/QOpenGLBuffer> class MyOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions { public: MyOpenGLWidget(QWidget *parent = nullptr) : QOpenGLWidget(parent) {} protected: void initializeGL() override { initializeOpenGLFunctions(); // 创建着色器程序 m_program = new QOpenGLShaderProgram(this); m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, R"( #version 330 core layout (location = 0) in vec3 aPos; void main() { gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); } )"); m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, R"( #version 330 core out vec4 FragColor; void main() { FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); } )"); m_program->link(); // 创建顶点数组对象和顶点缓冲对象 m_vao = new QOpenGLVertexArrayObject(this); m_vao->create(); m_vao->bind(); m_vbo = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer); m_vbo->create(); m_vbo->bind(); float vertices[] = { -0.5f, -0.5f, 0.0f, 0.5f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f }; m_vbo->allocate(vertices, sizeof(vertices)); // 设置顶点属性指针 m_program->bind(); m_program->enableAttributeArray(0); m_program->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0); // 解绑 m_vao->release(); m_vbo->release(); m_program->release(); } void paintGL() override { glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); m_program->bind(); m_vao->bind(); glDrawArrays(GL_TRIANGLES, 0, 3); m_vao->release(); m_program->release(); } private: QOpenGLShaderProgram *m_program; QOpenGLVertexArrayObject *m_vao; QOpenGLBuffer *m_vbo; }; ``` 这段代码使用 QtOpenGL 模块来创建一个继承自 QOpenGLWidget 的自定义 OpenGL 窗口,然后在 initializeGL() 函数中初始化着色器程序、顶点数组对象和顶点缓冲对象,最后在 paintGL() 函数中绘制三角形
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冯一川

谢谢老板对我的支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值