上章传送门参考:
1.opengl绘制三角形
1.QOpenGLWidget的早先版本
QGLWidget是遗留Qt OpenGL模块的一部分,和其他QGL类一样,应该在新的应用程序中避免使用。相反,从Qt 5.4开始,最好使用QOpenGLWidget和QOpenGL类。
如果开发XP平台,由于兼容性问题,Qt5.4(不含)之后的QtOpenglWidget 则不兼容,建议还是用QGLWidget.
2.QOpenGLWidget类是用于呈现OpenGL图形的部件
QOpenGLWidget提供显示集成到Qt应用程序中的OpenGL图形的功能。使用起来非常简单:让类继承它,并像其他QWidget一样使用子类,额外可以选择使用QPainer和标准的OpenGL渲染命令。
QOpenGLWidget提供了三个方便的虚拟函数,子类中重新实现这些函数来执行OpenGL绘制任务:
- paintGL():渲染OpenGL场景。该函数里面主要绘制部件,比如在全屏视频上面显示滑动条
- resizeGL ():当窗口尺寸发生变化时被调用,然后会调用paintGL()函数重新绘制一次(并且第一次显示时也会调用resizeGL() )。
- initializeGL():用于初始化,设置OpenGL要呈现的画面,只在程序开始时运行一次,之后不会再运行。
其中在initializeGL()中初始化具体如下所示:
然后在paintGL()中,每次当我们要绘制不同的物体时,便调用bind()来绑定对象、绘制完后,解绑对象,如果还要绘制下个物体,那么就取出对应的VAO,绑定它,绘制完物体后,再解绑。
3.本章需要用到的名词和类介绍
-
Program:
用来编译顶点和片元着色器的程序,简称着色器程序 -
VBO:
顶点缓冲对象(顶点输入,顶点位置),通过VBO将大量顶点存储在GPU内存(通常被称为显存)中.必须在初始化VAO之前初始化好.等VAO.bind后就可以释放了. -
VAO:
顶点数组对象,用于存储顶点状态配置信息,每当刷新时,通过VAO进行绘制(告诉着色器如何解释内存中的顶点数据). -
QOpenGLBuffer:
用来创建vbo对象或者ebo对象(索引缓冲对象) -
QOpenGLVertexArrayObject:
用来创建vao对象,用于存储顶点状态配置信息,每当界面刷新时,则通过VAO进行绘制 -
QOpenGLShaderProgram:
着色器程序,用来链接顶点shader和片元shader,一旦编译链接成功,就可以通过调用bind()成员函数进行激活.
4.三角形示例
5.头文件代码
#ifndef GLWIDGET_H
#define GLWIDGET_H
#include <QObject>
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLTexture>
#include <QDebug>
class Glwidget : public QOpenGLWidget , protected QOpenGLFunctions
{
Q_OBJECT
public:
explicit Glwidget(QWidget *parent = nullptr);
protected:
void paintGL() ;
void initializeGL() ;
void resizeGL(int width, int height);
signals:
private:
QOpenGLShaderProgram *program;
QOpenGLVertexArrayObject vao;
QOpenGLBuffer vbo;
};
#endif // GLWIDGET_H
6.源文件代码
#include "glwidget.h"
GLSL3.0版本后,废弃了attribute关键字(以及varying关键字),属性变量统一用in/out作为前置关键字
#define GLVERSION "#version 330 core\n"
#define GET_GLSTR(x) GLVERSION#x
const char *vertexShaderSource = GET_GLSTR(
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
);
const char *fragmentShaderSource = GET_GLSTR(
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
);
Glwidget::Glwidget(QWidget *parent) : QOpenGLWidget(parent)
{
}
void Glwidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT);
program->bind();
vao.bind();
glDrawArrays(GL_TRIANGLES, 0, 3); //绘制3个定点,样式为三角形
vao.release(); //解绑
program->release(); //解绑
}
void Glwidget::initializeGL()
{
bool ret;
initializeOpenGLFunctions();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f); //设置背景色为白色
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
// 初始化VBO(顶点输入,顶点位置)
vbo.create();
vbo.bind(); //绑定到当前的OpenGL上下文,
vbo.allocate(vertices, sizeof(vertices));
vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
// 初始化顶点着色器和片元着色器,链接到着色器程序对象(Shader Program Object)
program = new QOpenGLShaderProgram(this);
program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
ret = program->link();
if(!ret) {
qDebug()<<"QOpenGLShaderProgram ERR:"<<program->log();
return;
}
program->bind(); // 相当于调用glUseProgram()
// 将当前的顶点属性的配置信息(与program绑定一起)绑定到VAO(当我们打算绘制物体的时候就拿出相应的VAO,绑定它,绘制完物体后,再解绑VAO。)
vao.create();
vao.bind();
// 设置顶点属性,告诉着色器如何解释内存中的顶点数据(组件数量,数据类型,顶点个数),比如xyz坐标数据类型是GL_BYTE型,还是GL_SHORT型,还是GL_FLOAT型等
program->setAttributeBuffer(0, GL_FLOAT, 0, 3, 0);
//location:指定要设置的顶点位置(Location)的索引值
//type:指定数组中每个组件的数据类型。可用的符号常量有GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT,GL_UNSIGNED_SHORT, GL_FIXED, 和 GL_FLOAT
//offset:第一个数据的偏移量,如果是紧贴的,则填入0
//tupleSize:每个顶点属性的组件数量。必须为1、2、3、4之一。(如我们这里aPos顶点是由3个(x,y,z)组成,而颜色是4个(r,g,b,a))
//stride :步长,下个数据距离当前数据的之间距离,如果是紧贴的,则填0
//解绑所有对象
vao.release();
vbo.release();
program->release();
}
// 窗口尺寸变化
void Glwidget::resizeGL(int width, int height)
{
qDebug() << "resizeGL "<<width<<":"<<height;
}
版权声明:本文为qq_37997682原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。