1.头文件
#ifndef COPENGLWIDGET_H
#define COPENGLWIDGET_H
#include
#include
#include
class COPenGLWidget : public QOpenGLWidget, public QOpenGLFunctions_3_3_Core
{
Q_OBJECT
public:
COPenGLWidget(QWidget* parent = nullptr);
virtual void initializeGL() override;
virtual void resizeGL(int w, int h) override;
virtual void paintGL() override;
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
virtual void wheelEvent(QWheelEvent *event) override;
private:
void Init();
void ShaderProgram(); // 着色器程序
void GetShaderSource(const QString &path, std::string &str); // 获取着色器源码
void BindShader(); // 绑定着色器
bool CheckCompileErrors(unsigned int shader, std::string type); // 检查着色器编译错误
void DrawCoordinate(); // 坐标轴
private:
std::string m_vShaderSource; // 顶点着色器
std::string m_fShaderSource; // 片段着色器
unsigned int m_coordId;
int m_mousebuttonStatus; //鼠标按钮状态,0:松开状态,1:左键按下,2:右键按下
QPoint m_leftmousebuttonPos; // 左键按下位置
QPoint m_rightmousebuttonPos; // 右键按下位置
float m_pitch; // 俯仰角
float m_yaw; // 偏航角
float m_roll; // 翻滚角
float m_zoom; // 缩放
};
#endif // COPENGLWIDGET_H
2.源文件
#include "copenglwidget.h"
#include
#include
#include
#include
#include
const int src_width = 800;
const int src_height = 600;
const float PI = 3.141593f;
COPenGLWidget::COPenGLWidget(QWidget* parent) :
QOpenGLWidget(parent),
m_coordId(0),
m_mousebuttonStatus(0),
m_pitch(0.0f), m_yaw(0.0f), m_roll(0.0f)
{
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);
format.setVersion(3, 3);
setFormat(format);
Init();
}
void COPenGLWidget::initializeGL()
{
initializeOpenGLFunctions();
ShaderProgram();
}
void COPenGLWidget::resizeGL(int w, int h)
{
}
void COPenGLWidget::paintGL()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
DrawCoordinate();
}
void COPenGLWidget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton) {
m_mousebuttonStatus = 1;
m_leftmousebuttonPos = event->pos();
} else if (event->button() == Qt::RightButton) {
m_mousebuttonStatus = 2;
m_rightmousebuttonPos = event->pos();
}
}
void COPenGLWidget::mouseReleaseEvent(QMouseEvent *event)
{
m_mousebuttonStatus = 0;
update();
}
void COPenGLWidget::mouseMoveEvent(QMouseEvent *event)
{
if(m_mousebuttonStatus == 1) {
float x = event->pos().x() - m_leftmousebuttonPos.x();
float y = event->pos().y() - m_leftmousebuttonPos.y();
m_pitch += PI * x / rect().width();
m_yaw += PI * y / rect().height();
m_leftmousebuttonPos = event->pos();
update();
} else if (m_mousebuttonStatus == 2) {
float x = event->pos().x() - m_rightmousebuttonPos.x();
if(x > 0) {
m_roll += 0.05;
} else {
m_roll -= 0.05;
}
m_rightmousebuttonPos = event->pos();
update();
}
}
void COPenGLWidget::wheelEvent(QWheelEvent *event)
{
if(event->delta() > 0) {
m_zoom *= 1.05;
} else {
m_zoom *= 0.95;
}
if(m_zoom < 0.2) {
m_zoom = 0.2;
}
update();
}
void COPenGLWidget::Init()
{
}
void COPenGLWidget::ShaderProgram()
{
// 获取着色器源码
GetShaderSource(":/shaders/axis.vert", m_vShaderSource);
GetShaderSource(":/shaders/axis.frag", m_fShaderSource);
// 绑定着色器
BindShader();
}
void COPenGLWidget::GetShaderSource(const QString &path, std::string &str)
{
QFile file(path);
file.open(QIODevice::ReadOnly);
QTextStream in(&file);
str = in.readAll().toStdString();
file.close();
}
void COPenGLWidget::BindShader()
{
const char* vShaderSource = m_vShaderSource.c_str();
const char* fShaderSource = m_fShaderSource.c_str();
// 顶点着色器
unsigned int vertex = glCreateShader(GL_VERTEX_SHADER); // 创建顶点着色器
glShaderSource(vertex, 1, &vShaderSource, nullptr); // 绑定着色器
glCompileShader(vertex); // 编译着色器
CheckCompileErrors(vertex, "VERTEX"); // 检查着色器编译错误
// 片段着色器
unsigned int fragment = glCreateShader(GL_FRAGMENT_SHADER); // 创建片段着色器
glShaderSource(fragment, 1, &fShaderSource, nullptr); // 绑定着色器
glCompileShader(fragment); // 编译着色器
CheckCompileErrors(fragment, "FRAGMENT"); // 检查着色器编译错误
// 链接着色器
m_coordId = glCreateProgram();
glAttachShader(m_coordId, vertex);
glAttachShader(m_coordId, fragment);
glLinkProgram(m_coordId);
CheckCompileErrors(m_coordId, "PROGRAM"); // 检查链接错误
// 删除着色器
glDeleteShader(vertex);
glDeleteShader(fragment);
}
bool COPenGLWidget::CheckCompileErrors(unsigned int shader, std::string type)
{
int success;
char infoLog[512];
if(type != "PROGRAM") {
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if(!success) {
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
return false;
}
} else {
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if(!success) {
glGetProgramInfoLog(shader, 512, nullptr, infoLog);
return false;
}
}
return true;
}
void COPenGLWidget::DrawCoordinate()
{
float vertex[] = {
0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.1f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.1f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.1f, 0.0f, 0.0f, 1.0f
};
unsigned int VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof (vertex), vertex, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof (float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(m_coordId);
// 投影矩阵
glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)src_width / (float)src_height, 0.1f, 1000.0f);
// 视图矩阵
glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 10.0f); // 摄像机位置
glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, 0.0f); // 摄像机 指向的方向
glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); // 上向量
glm::mat4 view = glm::lookAt(cameraPos, cameraFront, cameraUp); // 视图矩阵
// 模型矩阵
glm::mat4 model = glm::mat4();
model = glm::translate(model, glm::vec3(-0.45f, -0.35f, 9.0f));
model = glm::rotate(model, m_pitch, glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, m_yaw, glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::rotate(model, m_roll, glm::vec3(0.0f, 0.0f, 1.0f));
// 返回 全局变量的位置
unsigned int modelLoc = glGetUniformLocation(m_coordId, "model");
unsigned int viewLoc = glGetUniformLocation(m_coordId, "view");
unsigned int projectLoc = glGetUniformLocation(m_coordId, "projection");
// 将矩阵 传入管线
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, &view[0][0]);
glUniformMatrix4fv(projectLoc, 1, GL_FALSE, &projection[0][0]);
glBindVertexArray(VAO);
glDrawArrays(GL_LINES, 0, 6);
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
}
3.顶点着色器
axis.vert
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 ourColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(){
gl_Position = projection * view * model * vec4(aPos, 1.0f);
ourColor = aColor;
}
4.片段着色器
axis.frag
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
void main(){
FragColor = vec4(ourColor, 1.0f);
}
5.结果