OpenGL入门第二步:颜色、纹理设置(解析)-CSDN博客
目录
1、创建一个QOpenGLWidget 子类
2、重写虚函数
initializeGL:
设置OpenGL资源和状态。在第一次调用resizeGL()或paintGL()之前被调用一次。
resizeGL
:窗口尺寸变化时调用。
paintGL:
窗口更新时调用,渲染 OpenGL 场景。
makeCurrent:
绑定当前OpenGL上下文。
doneCurrent
:释放当前OpenGL上下文。
如果要重绘场景 应该调用
update
而不是resizeGL
所有跟 OpenGL 相关的操作都应该发生在
initializeGL、
resizeGL、
paintGL
三个函数内 或者在 调用makeCurrent
之后。
3、了解OpenGL绘图,重写函数
openGL绘制3d的本质其实就是画三角形,所有的面都是由三角形组成。
要绘制三角形就要了解渲染管线(如下)。
需要我们参与的是顶点着色器、几何着色器(可无)、片段着色器。
所以在重写虚函数的时候,在initializeGL函数中写着色器。
QOpenGLFunctions* f = context()->functions();:这行代码获取了与 OpenGL 上下文相关的函数指针
在顶点着色器中通过
layout (location = 0) in vec3 aPos;将位置变量的属性位置值设为0
着色器的另外一种写法(路径默认在bin里面)
设置顶点数据
先记住下面3个概念。
代码中创建vbo、vao和ebo。把顶点数据放入vbo,把索引放入ebo。
通过调用 enableAttributeArray 方法并传递数组索引(在这里是 0),可以告诉图形渲染引擎要启用对应索引的属性数组。
通过调用setAttributeBuffer 方法设置着色器程序(shaderProgram)的属性缓冲区(attribute buffer)。
setAttributeBuffer:这是一个函数调用,用于将属性数据绑定到着色器程序的特定属性位置。
0:表示要绑定的属性位置索引。在这里,索引 0 可能对应着某个特定的顶点属性,比如位置、颜色或其他属性。这个与enableAttributeArray的值对应,这两处都是因为在顶点着色器中设置了0表示位置。
GL_FLOAT:指定了属性数据的类型。这里使用了 GL_FLOAT,表示浮点型数据。
0:可能是属性数据在缓冲区中的起始偏移量。
3:表示每个顶点属性的组件数量。例如,如果是位置属性,可能有 x、y、z 三个组件。
3 * sizeof(float):计算了每个顶点属性的字节大小。这里假设每个浮点数(float)占用 4 个字节(sizeof(float)),所以 3 * 4 = 12 字节。
resizeGL函数控制视口
paintGL函数实时绘制
绑定着色器和vao
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);:调用了 glClear 函数来清除颜色缓冲区和深度缓冲区。GL_COLOR_BUFFER_BIT 表示要清除颜色数据,GL_DEPTH_BUFFER_BIT 表示要清除深度数据。通过使用位或操作符 |,将这两个标志组合在一起。
f->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);:这行代码使用 glDrawElements 函数来绘制三角形。GL_TRIANGLES 指定了要绘制的图元类型为三角形。6 表示绘制要取顶点数(前面设置了索引3个点一组,输入的必须是3的倍数)。GL_UNSIGNED_INT 指定了索引数据的类型为无符号整数。0 有待确认
还有一种三角绘制:
f->glDrawArrays(GL_TRIANGLES, 0, 3);:GL_TRIANGLES:指定要绘制的几何图形类型为三角形。0:表示三角形的起始顶点索引。3:表示要绘制的三角形的顶点数量。
具体代码
#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLTexture>
#include <QElapsedTimer>
QT_BEGIN_NAMESPACE
namespace Ui { class openGLWidget; }
QT_END_NAMESPACE
class openGLWidget : public QOpenGLWidget
{
Q_OBJECT
public:
openGLWidget(QWidget *parent = nullptr);
~openGLWidget();
protected:
virtual void initializeGL() override;
virtual void resizeGL(int w, int h) override;
virtual void paintGL() override;
private:
QOpenGLShaderProgram shaderProgram;
QOpenGLBuffer vbo;
QOpenGLBuffer ebo {QOpenGLBuffer(QOpenGLBuffer::IndexBuffer)};
QOpenGLVertexArrayObject vao;
private:
Ui::openGLWidget *ui;
};
#endif // OPENGLWIDGET_H
#include "openGLWidget.h"
#include "./ui_openGLWidget.h"
#include <QOpenGLFunctions>
#include <QtMath>
openGLWidget::openGLWidget(QWidget *parent)
: QOpenGLWidget(parent)
, ui(new Ui::openGLWidget)
{
ui->setupUi(this);
}
openGLWidget::~openGLWidget()
{
makeCurrent();
vao.destroy();
vbo.destroy();
ebo.destroy();
doneCurrent();
delete ui;
}
void openGLWidget::initializeGL()
{
// 设置用来清空屏幕的颜色 这里设置为黑色
QOpenGLFunctions *f = context()->functions();
f->glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
// 顶点着色器
shaderProgram.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, R"(
#version 330 core
layout (location = 0) in vec3 aPos;// 位置变量的属性位置值为0
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); // 注意我们如何把一个vec3作为vec4的构造器的参数
}
)");
// 片段着色器
shaderProgram.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, R"(
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
)");
// 编译链接
if(!shaderProgram.link()) {
qDebug() << shaderProgram.log();
};
// 顶点数据
float vertices[] = {
0.5f, 0.5f, 0.0f, // 右上角
0.5f, -0.5f, 0.0f, // 右下角
-0.5f, -0.5f, 0.0f, // 左下角
-0.5f, 0.5f, 0.0f // 左上角
};
// 顶点索引
uint indices[] = {
// 注意索引从0开始!
// 此例的索引(0,1,2,3)就是顶点数组vertices的下标,
// 这样可以由下标代表顶点组合成矩形
0, 1, 3, // 第一个三角形
1, 2, 3 // 第二个三角形
};
// 创建VAO VBO EBO
vao.create();
vao.bind();
vbo.create();
vbo.bind();
ebo.create();
ebo.bind();
vbo.allocate(vertices, sizeof(vertices));
ebo.allocate(indices, sizeof(indices));
shaderProgram.enableAttributeArray(0);
shaderProgram.setAttributeBuffer(0, GL_FLOAT, 0, 3, 3 * sizeof(float));
}
void openGLWidget::resizeGL(int w, int h)
{
// 窗口尺寸发生变化时,设置视口大小, 这里把视口设置与窗口一样大
QOpenGLFunctions *f = context()->functions();
f->glViewport(0, 0, w, h);
}
void openGLWidget::paintGL()
{
QOpenGLFunctions* f = context()->functions();
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shaderProgram.bind();
vao.bind();
f->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}