第一个QOpenGLWidget程序
学习内容:
1.创建OpenGL窗口;
2.创建并编写着色器程序;
3.为着色器程序装配顶点数据;
4.启动渲染管线进行绘图。
这部分知识我在该博主这里学习的
这部分基础详细讲解我就不赘述也不搬运了,这里我给出学习了这部分基础后自己写出的代码;大家可以学习完基础看看我的代码,我初期学习都加了注释
代码:
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QTimer>
//创建opengl窗口只需新建类继承于QOpenGLWidegt,再实现QOpenGL提供的三个虚函数,就可以完成opengl窗口的创建。
//需要在类中使用opengl函数,只需要使类继承于QOpenGLExtraFunctions
class Widget : public QOpenGLWidget,protected QOpenGLExtraFunctions
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
//initializeGL()—建立OpenGL的资源和状态。在第一次调用resizeGL()或paintGL()之前调用一次
//resizeGL()—设置OpenGL视口,投影等。每当调整Widget的大小时(第一次显示窗口Widget时会调用它,因为所有新创建Widget都会自动获得调整大小的事件)。
//paintGL()—渲染OpenGL场景,需要更新Widget时就会调用。
virtual void initializeGL() override;
virtual void paintGL() override;
virtual void resizeGL(int w,int h) override;
private:
QVector<float> vertices;//声明数组
QOpenGLShaderProgram shaderprogram;//声明着色器程序
QOpenGLVertexArrayObject VAO;//声明VAO顶点数组对象
QOpenGLBuffer VBO;//声明VBO数组缓冲对象
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QtMath>
#include <QTime>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QOpenGLWidget(parent)
,VBO(QOpenGLBuffer::VertexBuffer)
{
QSurfaceFormat format;
format.setAlphaBufferSize(24); //设置alpha缓冲大小
format.setVersion(3,3); //设置版本号
format.setSamples(10); //设置重采样次数,用于反走样
this->setFormat(format);
vertices={
// 位置 // 颜色
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // 右下
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // 左下
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, // 左下
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // 右上
};
}
Widget::~Widget()
{
makeCurrent();
}
void Widget::initializeGL()
{
this->initializeOpenGLFunctions();//初始化opengl函数
shaderprogram.create();//生成着色器程序
if(!shaderprogram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/gl.vert")){
qDebug()<<"ERROR:"<<shaderprogram.log(); //如果编译出错,打印报错信息
}
if(!shaderprogram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/gl.frag")){
qDebug()<<"ERROR:"<<shaderprogram.log(); //如果编译出错,打印报错信息
}
//将添加到此程序的着色器与addshader链接在一起
if(!shaderprogram.link()){
qDebug()<<"ERROR:"<<shaderprogram.log(); //如果链接出错,打印报错信息
}
VAO.create();// 创建一个VAO对象,OpenGL会给它(顶点数组缓存对象)分配一个id
VAO.bind();//将RC中的当前顶点数组缓存对象Id设置为VAO的id
VBO.create();
VBO.bind();
VBO.allocate(vertices.data(),sizeof(float)*vertices.size());//将顶点数据分配到VBO中,第一个参数为数据指针,第二个参数为数据的字节长度
shaderprogram.setAttributeBuffer("aPos", GL_FLOAT, 0, 3, sizeof(GLfloat) * 6);
shaderprogram.enableAttributeArray("aPos");
shaderprogram.setAttributeBuffer("aColor", GL_FLOAT,sizeof(GLfloat) * 3, 3, sizeof(GLfloat) * 6);
shaderprogram.enableAttributeArray("aColor");
VAO.release();//释放
VBO.release();
}
void Widget::paintGL()
{
this->glClearColor(0.1f,0.5f,0.7f,1.0f);//设置清屏颜色
this->glClear(GL_COLOR_BUFFER_BIT);//清空颜色缓冲区
shaderprogram.bind();
//将此着色器程序绑定到活动的qopenglcontext,并使其成为当前着色器程序。任何先前绑定的着色器程序都将被释放
//成功绑定返回ture,反之,返回false.
QOpenGLVertexArrayObject::Binder bind(&VAO);//绑定VAO
this->glDrawArrays(GL_POLYGON,0,4);
}
void Widget::resizeGL(int w,int h)
{
this->glViewport(0,0,w,h);
}
gl.vert
#version 330 core
layout (location = 0) in vec3 aPos; // 位置变量的属性位置值为 0
layout (location = 1) in vec3 aColor; // 颜色变量的属性位置值为 1
out vec3 ourColor; // 向片段着色器输出一个颜色
void main()
{
gl_Position = vec4(aPos, 1.0);
ourColor = aColor; // 将ourColor设置为我们从顶点数据那里得到的输入颜色
}
gl.frag
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0);
}
运行即可得到如下结果
旋转立方体
主要内容
代码
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLExtraFunctions>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLTexture>
#include <QTimer>
#include <QTime>
#include <QtMath>
#include <QVector>
class Widget : public QOpenGLWidget,public QOpenGLExtraFunctions
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
protected:
virtual void initializeGL() override;
virtual void resizeGL(int w,int h) override;
virtual void paintGL() override;
private:
QVector<float> vertices;
QOpenGLShaderProgram shaderProgram;
QOpenGLBuffer VBO;
QOpenGLVertexArrayObject VAO;
QOpenGLTexture texture;
QOpenGLTexture texture1;
QTimer timer;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QtMath>
Widget::Widget(QWidget *parent)
: QOpenGLWidget(parent)
, VBO(QOpenGLBuffer::VertexBuffer)
, texture(QOpenGLTexture::Target2D)
, texture1(QOpenGLTexture::Target2D)
{
vertices = {
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};
timer.setInterval(18);
connect(&timer,&QTimer::timeout,this,static_cast<void (Widget::*)()>(&Widget::update));
timer.start();
}
Widget::~Widget()
{
}
void Widget::initializeGL()
{
this->initializeOpenGLFunctions(); //初始化opengl函数
if(!shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex,":/triangle.vert")){ //添加并编译顶点着色器
qDebug()<<"ERROR:"<<shaderProgram.log(); //如果编译出错,打印报错信息
}
if(!shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment,":/triangle.frag")){ //添加并编译片段着色器
qDebug()<<"ERROR:"<<shaderProgram.log(); //如果编译出错,打印报错信息
}
if(!shaderProgram.link()){ //链接着色器
qDebug()<<"ERROR:"<<shaderProgram.log(); //如果链接出错,打印报错信息
}
QOpenGLVertexArrayObject::Binder{&VAO};
VBO.create(); //生成VBO对象
VBO.bind(); //将VBO绑定到当前的顶点缓冲对象(QOpenGLBuffer::VertexBuffer)中
//将顶点数据分配到VBO中,第一个参数为数据指针,第二个参数为数据的字节长度
VBO.allocate(vertices.data(),sizeof(float)*vertices.size());
texture.create();
texture.setData(QImage(":/opengl.jpg").mirrored());
texture.setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,QOpenGLTexture::Linear);
texture.setWrapMode(QOpenGLTexture::DirectionS,QOpenGLTexture::Repeat);
texture.setWrapMode(QOpenGLTexture::DirectionT,QOpenGLTexture::Repeat);
texture1.create();
texture1.setData(QImage(":/sea.jpg").mirrored());
texture1.setMinMagFilters(QOpenGLTexture::LinearMipMapLinear,QOpenGLTexture::Linear);
texture1.setWrapMode(QOpenGLTexture::DirectionS,QOpenGLTexture::Repeat);
texture1.setWrapMode(QOpenGLTexture::DirectionT,QOpenGLTexture::Repeat);
//设置顶点解析格式,并启用顶点
shaderProgram.setAttributeBuffer("aPos", GL_FLOAT, 0, 3, sizeof(GLfloat) * 5);
shaderProgram.enableAttributeArray("aPos");
shaderProgram.setAttributeBuffer("aTexCoord", GL_FLOAT,sizeof(GLfloat) * 3, 2, sizeof(GLfloat) * 5);
shaderProgram.enableAttributeArray("aTexCoord");
this->glEnable(GL_DEPTH_TEST);
}
void Widget::resizeGL(int w, int h)
{
this->glViewport(0,0,w,h); //定义视口区域
}
void Widget::paintGL()
{
this->glClearColor(0.1f,0.5f,0.7f,1.0f); //设置清屏颜色
this->glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT); //清除颜色缓存
shaderProgram.bind(); //使用shaderProgram着色程序
{
float time=QTime::currentTime().msecsSinceStartOfDay()/1000.0;
QMatrix4x4 model;//位移旋转矩阵
model.rotate(180*time,QVector3D(1.0f,0.5f,0.3f));
shaderProgram.setUniformValue("model",model);
QMatrix4x4 view;//观察矩阵
view.translate(0.0f,0.0f,-3.0f);
shaderProgram.setUniformValue("view",view);
QMatrix4x4 projection;//投影矩阵
projection.perspective(45.0f,width()/(float)height(),0.1f,100.0f);
shaderProgram.setUniformValue("projection",projection);
texture.bind(0); //将texture绑定到纹理单元0
shaderProgram.setUniformValue("ourTexture",0); //让ourTexture从纹理单元0中获取纹理数据
texture1.bind(1); //将texture绑定到纹理单元1
shaderProgram.setUniformValue("ourTexture1",1); //让ourTexture从纹理单元1中获取纹理数据
QOpenGLVertexArrayObject::Binder{&VAO};
this->glDrawArrays(GL_TRIANGLES, 0, 36); //使用以0开始,长度为36的顶点数据来绘制三角形
}
}
triangle.vert
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
// 注意乘法要从右向左读
gl_Position = projection * view * model * vec4(aPos, 1.0);
TexCoord = aTexCoord;
}
triangle.frag
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;
uniform sampler2D ourTexture1;
void main()
{
FragColor = mix(texture(ourTexture, TexCoord), texture(ourTexture1, TexCoord), 0.4);
}
结果
运行即可得到旋转的立方体