QtOpenGL(一) 简单的三维点的绘制
前言
OpenGL网上的例子也很多,之前也一直在用,最近又系统的看了一下,也总结了一下,我我们开始吧。
1、Qt里面内嵌了OpenGL的环境,对于出初学者很友好,至少我开始学习的时候没有那么的头疼。
2、其次吧有时候要在Linux下进行,又回到Qt跨平台上面了,emmmmmm。
3、Qt里面至少还是有一些Opengl的文档可以直接看的。不会了直接F1。
好了我们开始吧。
一、Qt中的OpenGL
Qt中的OpenGL也是经过包装的,本篇主要基于的是Qt5.14.2里面的QOpenGLWidget和QOpenGLFunctions_3_3_Core。当让也有其他的,我们就暂时用这两个吧。
二、效果
三、代码
1-- .h文件
class SpiderOpenGLWidget : public QOpenGLWidget,QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
SpiderOpenGLWidget(QWidget *parent = nullptr);
~SpiderOpenGLWidget();
private:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
unsigned int draw_PointDara();
public slots:
void BuildPoint();
private:
Ui::SpiderOpenGLWidget *ui;
QOpenGLShaderProgram shaderProgram_point;
unsigned int VBO_Point;
unsigned int VAO_Point;
unsigned int point_count;
QVector<float> m_pointData;
QTimer* m_BulidPoint;
QMutex m_PointLook;
};
2–.cpp文件
代码如下(示例):
SpiderOpenGLWidget::SpiderOpenGLWidget(QWidget *parent)
: QOpenGLWidget(parent)
, ui(new Ui::SpiderOpenGLWidget)
{
ui->setupUi(this);
//抗锯齿
QSurfaceFormat format;
format.setSamples(4);
setFormat(format);
QSurfaceFormat fmt;
fmt.setDepthBufferSize(24);
setFormat(fmt);
//造点
m_BulidPoint = new QTimer;
connect(m_BulidPoint,SIGNAL(timeout()),this,SLOT(BuildPoint()));
m_BulidPoint->setInterval(100);
m_BulidPoint->start();
m_pointData.clear();
m_pointData.append(0);//X轴
m_pointData.append(10);//Y轴
m_pointData.append(10);//Z轴
m_pointData.append(100);
SpiderOpenGLWidget::~SpiderOpenGLWidget()
{
delete ui;
makeCurrent();
glDeleteBuffers(1, &VBO_Point);
glDeleteVertexArrays(1, &VAO_Point);
shaderProgram_point.release();
doneCurrent();
}
void SpiderOpenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glEnable(GL_DEPTH_TEST);
//点
shaderProgram_point.bind();
shaderProgram_point.addShaderFromSourceFile(QOpenGLShader::Vertex, "E:/4D/SpiderOpenGl/shader/shader_point.vs");
shaderProgram_point.addShaderFromSourceFile(QOpenGLShader::Fragment, "E:/4D/SpiderOpenGl/shader/shader_point.fs");
shaderProgram_point.link();
shaderProgram_point.release();
}
void SpiderOpenGLWidget::paintGL()
{
QMatrix4x4 projection, view, model;
projection.perspective(zoom, (float)width() / (float)height(), 1.0f, 100.0f);
view.lookAt(QVector3D(0.0, 0.0, 50.0), QVector3D(0.0, 0.0, 1.0), QVector3D(0.0, 1.0, 0.0));
model.translate(0, 0, 0.0);
model.rotate(-80.0, 1.0, 0.0, 0.0);
model.rotate(0.0, 0.0, 0.0, 1.0);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除缓存区
//点
m_PointLook.lock();
shaderProgram_point.bind();
shaderProgram_point.setUniformValue("projection", projection);
shaderProgram_point.setUniformValue("view", view);
shaderProgram_point.setUniformValue("model", model);
point_count = draw_PointDara();
glBindVertexArray(VAO_Point);
glPointSize(5.0f);//点的大小
glDrawArrays(GL_POINTS, 0, point_count);
glDeleteBuffers(1, &VBO_Point);
glDeleteVertexArrays(1, &VAO_Point);
shaderProgram_point.release();
m_PointLook.unlock();
}
void SpiderOpenGLWidget::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
}
void SpiderOpenGLWidget::BuildPoint()
{
//下面又两种不同常用造点方式,随机点
qDebug()<<"PointDataPointData"<<m_pointData.size();
if(m_pointData.size()>=1200)
{
m_pointData.clear();
// glDeleteBuffers(500,&VAO_Point);
}
QTime randtime;
randtime = QTime::currentTime();
qsrand(randtime.msec()+randtime.second()*1000); //以当前时间ms为随机种子
QRandomGenerator generator1 = QRandomGenerator::securelySeeded();
float randomNumber1 = generator1.bounded(100);
QRandomGenerator generator2 = QRandomGenerator::securelySeeded();
float randomNumber2 = generator2.bounded(100);
QRandomGenerator generator3 = QRandomGenerator::securelySeeded();
float randomNumber3 = generator3.bounded(100);
int n = qrand() % 100; //产生100以内的随机整数
float fn = float(n)/10; //产生10以内的随机浮点数,精度为小数点后1位
// qDebug()<<"BuildPointBuildPointBuildPoint"<<n;
m_pointData.append(fn);//X轴
m_pointData.append(randomNumber1);//Y轴
m_pointData.append(randomNumber2);//Z轴
m_pointData.append(randomNumber3);
update();
}
unsigned int SpiderOpenGLWidget::draw_PointDara()
{
unsigned point_count = 0;
glGenVertexArrays(1, &VAO_Point);
glGenBuffers(1, &VBO_Point);
glBindVertexArray(VAO_Point);
glBindBuffer(GL_ARRAY_BUFFER, VBO_Point);
glBufferData(GL_ARRAY_BUFFER, m_pointData.size() * sizeof(float), &m_pointData[0], GL_STREAM_DRAW );//GL_STATIC_DRAW
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
point_count = m_pointData.size() / 4;
return point_count;
}
四、注意
1、初始化
首先呢OpenGL的初始化是在initializeGL() 里面进行的。
1、当然Qt给我们提供了一个函数initializeOpenGLFunctions(); 我们只需要调用就好了。剩下的不用管。如果不使用的话将无法使用OpenL的函数。
2、接下来我们开启深度测试。
initializeOpenGLFunctions();
glEnable(GL_DEPTH_TEST);
3、添加顶点着色器和片段着色器。着色器是OpenGL重要的一个部分,后面我们会细说。
shaderProgram_axis.bind();
shaderProgram_axis.addShaderFromSourceFile(QOpenGLShader::Vertex, "E:/4D/SpiderOpenGl/shader/shader_point.vert");
shaderProgram_axis.addShaderFromSourceFile(QOpenGLShader::Fragment, "E:/4D/SpiderOpenGl/shader/shader_point.frag");
shaderProgram_axis.link();
shaderProgram_axis.release();
其中顶点着色器.vert如下所示:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aIntensity;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 ourColor;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
ourColor = vec3(0.0f, 1.0f, 1.0f);
}
其中片段着色器.frag如下所示:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main()
{
FragColor = vec4(ourColor, 1.0f);
}
2、绘图
1、设置观测矩阵、投影矩阵、模型矩阵。
2、清除之前绘制的内容。
QMatrix4x4 projection, view, model;
projection.perspective(zoom, (float)width() / (float)height(), 1.0f, 100.0f);
view.lookAt(QVector3D(0.0, 0.0, 50.0), QVector3D(0.0, 0.0, 1.0), QVector3D(0.0, 1.0, 0.0));
model.translate(x_trans, y_trans, 0.0);
model.rotate(x_rotate, 1.0, 0.0, 0.0);
model.rotate(z_rotate, 0.0, 0.0, 1.0);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除缓存区
3、启用QOpenGLShaderProgram,绑定。
4、设置QOpenGLShaderProgram中的矩阵数据等。
shaderProgram_point.bind();
shaderProgram_point.setUniformValue("projection", projection);
shaderProgram_point.setUniformValue("view", view);
shaderProgram_point.setUniformValue("model", model);
5、VBO(Vertex Buffer Object,顶点缓冲对象)他管理建立在GUP上的顶点数据。在使用前我们先要生成一个VBO对象。
6、VAO(Vertex Array Object,顶点数组对象)他记录这已经配置好的顶点属性。绑定以后即便有多个VBO对象,只需要执行一次渲染的API就可以了。
glGenVertexArrays(1, &VAO_Point);
glGenBuffers(1, &VBO_Point);
glBindVertexArray(VAO_Point);
glBindBuffer(GL_ARRAY_BUFFER, VBO_Point);
7、完成上述初始化操作后我们将数据绑定到当前的缓冲上,也就是将造出来的点拷贝到缓存对象上。
8、然后将当前属性与VBO连接起来。在这里就是告诉显卡如何解析缓冲里的属性值。
5、然后开启VAO管理的第一个值。
glBufferData(GL_ARRAY_BUFFER, m_pointData.size() * sizeof(float), &m_pointData[0], GL_STREAM_DRAW );//GL_STATIC_DRAW
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
9、解绑VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
10、绘图
glDrawArrays(GL_POINTS, 0, point_count);
11、释放内存,如果进行的连续update,我们要进行内存的释放否则有大量的内存泄露。
glDeleteBuffers(1, &VBO_Point);
glDeleteVertexArrays(1, &VAO_Point);
五、总结
根据上面的代码,我们是绘制出来了三维的点,但是看起来有不是,黑压压一片就几个点,看起来没有那么直观,后面我们应该让视角动起来。这样就能直观的感觉到三维的点了。