OpenGL: QOpenGLShaderProgram

一、QOpenGLShaderProgram 编译过程的封装
1 、bool addShaderFromSourceCode(QGLShader::ShaderType type, const char * source);
2 、bool addShaderFromSourceFile(QGLShader::ShaderType type, const QString & fileName);
3 、virtual bool link();
4 、bool bind();
5 、QString log() const;
6 、一般将顶点着色器和片段着色器源码放入文件,后缀分别为.vert和.frag。
7 、着色器文件可以放入工程目录中,但更推荐放入Qt资源文件中。
8、为了在Qt中正常加载并编辑shader文件,shader文件设置编码为: UTF-8。

二、代码示例

cpp 复制代码
//MyOpenGLWidget.h
#pragma once

//需要两个头文件
#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QOpenGLShaderProgram>


class MyOpenGLWidget : public QOpenGLWidget, QOpenGLFunctions_4_5_Core
{
	Q_OBJECT

public:
	MyOpenGLWidget(QWidget * parent = nullptr);
	~MyOpenGLWidget();

	enum Shape { None, Rect, Circle, Triangle };

	void DrawShape(Shape shape);
	void WireFrame(bool bWire);

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

private:
	unsigned int VAO;
	unsigned int VBO;
	unsigned int EBO;

	Shape m_shape = None;

	QOpenGLShaderProgram m_shaderProgram;
};



//MyOpenGLWidget.cpp
#include "MyOpenGLWidget.h"
#include <QDebug>


MyOpenGLWidget::MyOpenGLWidget(QWidget * parent) : QOpenGLWidget(parent)
{
}


MyOpenGLWidget::~MyOpenGLWidget()
{
	makeCurrent();
	glDeleteBuffers(1, &VBO);
	glDeleteBuffers(1, &EBO);
	glDeleteVertexArrays(1, &VAO);
	doneCurrent();
}


void MyOpenGLWidget::DrawShape(Shape shape)
{
	//触发重新绘制
	m_shape = shape;
	update();
}


void MyOpenGLWidget::WireFrame(bool bWire)
{
	makeCurrent();
	if (bWire)
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	}
	else
	{
		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	}
	doneCurrent();

	update();
}


void MyOpenGLWidget::initializeGL()
{
	initializeOpenGLFunctions();

	//创建VAO、VBO、EBO,并赋予ID
	glGenVertexArrays(1, &VAO);
	glGenBuffers(1, &VBO);
	glGenBuffers(1, &EBO);

	//绑定VAO、VBO、EBO对象
	glBindVertexArray(VAO);
	glBindBuffer(GL_ARRAY_BUFFER, VBO);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);  //注意, 因为VAO已经绑定,此句会被VAO的最后一个指针偷偷记录下来, 指向EBO。
	
	//顶点数据
	float 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, 0.0f, 1.0f,   // 左下角
		-0.5f,  0.5f,  0.0f,  0.3f, 0.5f, 0.8f,   // 左上角
	};
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

	//索引数据
	unsigned int indices[] = 
	{
		0, 1, 3, // 第一个三角形
		1, 2, 3  // 第二个三角形
	};
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

	//配置VAO位置属性指针
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
	glEnableVertexAttribArray(0);
	//配置VAO颜色属性指针
	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float)));
	glEnableVertexAttribArray(1);

	//解绑VAO、VBO、EBO
	glBindVertexArray(0);
	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);   //注意,因为VAO已经解绑了,所以此句不会被VAO记录下来,VAO的最后一个指针依然指向EBO,这样好处是绘制前,只要再绑定VAO即可,EBO、VBO都不用再绑定。

	//着色器程序
	m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/1_shader.vert");
	m_shaderProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/1_shader.frag");
	bool success = m_shaderProgram.link();
	if (!success)
	{
		qDebug() << "ERROR: " << m_shaderProgram.log();
	}
}


void MyOpenGLWidget::resizeGL(int w, int h)
{
}


//绘制都是在此函数中,其它地方都是触发绘制
void MyOpenGLWidget::paintGL()
{
	glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT);

	glBindVertexArray(VAO);
	m_shaderProgram.bind();

	switch (m_shape)
	{
	case MyOpenGLWidget::None:
		break;
	case MyOpenGLWidget::Rect:
	{
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		break;
	}
	case MyOpenGLWidget::Circle:
		break;
	case MyOpenGLWidget::Triangle:
		break;
	default:
		break;
	}
}



//MainWindow.h
#pragma once

#include <QtWidgets/QMainWindow>


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindowClass; };
QT_END_NAMESPACE


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget * parent = nullptr);
    ~MainWindow();

private:
	void ActDrawRectTriggered(bool checked);
	void ActClearTriggered(bool checked);
	void ActWireFrameTriggered(bool checked);

private:
    Ui::MainWindowClass * ui;
};



//MainWindow.cpp
#include "MainWindow.h"
#include "ui_MainWindow.h"


MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindowClass())
{
    ui->setupUi(this);
	setCentralWidget(ui->openGLWidget);

	connect(ui->actDrawRect, &QAction::triggered, this, &MainWindow::ActDrawRectTriggered);
	connect(ui->actClear, &QAction::triggered, this, &MainWindow::ActClearTriggered);
	connect(ui->actWireFrame, &QAction::triggered, this, &MainWindow::ActWireFrameTriggered);
}


MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::ActDrawRectTriggered(bool checked)
{
	ui->openGLWidget->DrawShape(MaLanOpenGLWidget::Rect);
}


void MainWindow::ActClearTriggered(bool checked)
{
	ui->openGLWidget->DrawShape(MaLanOpenGLWidget::None);
}


void MainWindow::ActWireFrameTriggered(bool checked)
{
	ui->openGLWidget->WireFrame(checked);
}




//1_shader.vert
#version 330 core

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;

out vec3 ourColor;

void main()
{
    gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
    ourColor = aColor;
}




//1_shader.frag
#version 330 core

in vec3 ourColor;
out vec4 FragColor;

void main()
{
    FragColor = vec4(ourColor, 1.0);
}
相关推荐
CV实验室21 分钟前
NeurIPS 2025 | 北大等提出C²Prompt:解耦类内与类间知识,攻克FCL遗忘难题!
人工智能·计算机视觉·prompt·论文·cv
不枯石9 小时前
Matlab通过GUI实现点云的均值滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab·均值算法
不枯石9 小时前
Matlab通过GUI实现点云的双边(Bilateral)滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab
千宇宙航14 小时前
闲庭信步使用图像验证平台加速FPGA的开发:第三十课——车牌识别的FPGA实现(2)实现车牌定位
图像处理·计算机视觉·fpga开发·车牌识别
天涯路s16 小时前
OpenCV 特征检测与描述
人工智能·opencv·计算机视觉
飞翔的佩奇17 小时前
【完整源码+数据集+部署教程】鸡只与养殖场环境物品图像分割: yolov8-seg等50+全套改进创新点发刊_一键训练教程_Web前端展示
python·yolo·计算机视觉·数据集·yolov8·yolo11·鸡只与养殖场环境物品图像分割
星期天要睡觉21 小时前
计算机视觉(opencv)——基于 dlib 和 CNN卷积神经网络 的人脸检测
opencv·计算机视觉·cnn
春末的南方城市21 小时前
港大和字节携手打造WorldWeaver:以统一建模方案整合感知条件,为长视频生成领域带来质量与一致性双重飞跃。
人工智能·深度学习·机器学习·计算机视觉·aigc·音视频
极客代码1 天前
第五篇:后端优化——位姿图的灵魂--从图优化到滑动窗口的联合状态估计
python·深度学习·计算机视觉·视觉里程计·slam·回环检测·地图构建
春末的南方城市1 天前
苏大团队联合阿丘科技发表异常生成新方法:创新双分支训练法,同步攻克异常图像生成、分割及下游模型性能提升难题。
人工智能·科技·深度学习·计算机视觉·aigc