QT实现OPENGL画图
继承QOpenGLWidget和QOpenGLFunctions实现自定义窗口类。重写QOpenGLWidget的虚函数
void paintGL() override;
void initializeGL() override;
void mouseMoveEvent(QMouseEvent*)override;
void mousePressEvent(QMouseEvent*)override;
void wheelEvent(QWheelEvent*)override;
实现camera类,用于响应输入,改变观察矩阵,投影矩阵,从而实现视角控制。
camera.h
#ifndef __CAMERA_H__
#define __CAMERA_H__
#include <QOpenGLFunctions>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.03f;
const float ZOOM = 45.0f;
//摄像机移动方向
enum Camera_Movement {
FORWARD,
BACKWARD,
LEFT,
RIGHT,
UP,
DOWN
};
class Camera
{
public:
glm::vec3 Position;
glm::vec3 Forward;
glm::vec3 Up;
glm::vec3 Right;
glm::vec3 World_up;
float Yaw;
float Pitch;
float MovementSpeed;
float Mouse_Sensiticity;
float Zoom;
bool flip_y = false;
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 5.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH);
Camera(float pos_x, float pos_y, float pos_z, float up_x, float up_y, float up_z, float yaw, float pitch);
~Camera();
glm::mat4 GetViewMatrix();
void ProcessKeyboard(Camera_Movement direction, float deltaTime);
void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true);
void ProcessMouseScroll(float yoffset);
private:
void UpdateCameraVectors();
};
#endif
camera.cpp
#include "Camera.h"
Camera::Camera(glm::vec3 position, glm::vec3 up, float yaw, float pitch)
: Forward(glm::vec3(0.0f, 0.0f, -1.0f))
, MovementSpeed(SPEED)
, Mouse_Sensiticity(SENSITIVITY)
, Zoom(ZOOM)
{
this->Position = position;
this->World_up = up;
this->Yaw = yaw;
this->Pitch = pitch;
UpdateCameraVectors();
}
Camera::Camera(float pos_x, float pos_y, float pos_z, float up_x, float up_y, float up_z, float yaw, float pitch)
: Forward(glm::vec3(0.0f, 0.0f, -1.0f))
, MovementSpeed(SPEED)
, Mouse_Sensiticity(SENSITIVITY)
, Zoom(ZOOM)
{
this->Position = glm::vec3(pos_x, pos_y, pos_z);
this->World_up = glm::vec3(up_x, up_y, up_z);
this->Yaw = yaw;
this->Pitch = pitch;
UpdateCameraVectors();
}
Camera::~Camera()
{
}
glm::mat4 Camera::GetViewMatrix()
{
return glm::lookAt(Position, Position + Forward, Up);
}
//对应键盘移动事件
void Camera::ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Forward * velocity;
if (direction == BACKWARD)
Position -= Forward * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
if (direction == UP)
Position += Up * velocity;
if (direction == DOWN)
Position -= Up * velocity;
}
//对应鼠标移动事件
void Camera::ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch)
{
xoffset *= Mouse_Sensiticity;
yoffset *= Mouse_Sensiticity;
Yaw += xoffset;
Pitch += yoffset;
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
UpdateCameraVectors();
}
//对应鼠标滚轮事件
void Camera::ProcessMouseScroll(float yoffset)
{
if (Zoom >= 1.0f && Zoom <= 45.0f)
Zoom -= yoffset;
if (Zoom <= 1.0f)
Zoom = 1.0f;
if (Zoom >= 45.0f)
Zoom = 45.0f;
}
void Camera::UpdateCameraVectors()
{
glm::vec3 front;
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
front.y = sin(glm::radians(Pitch));
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Forward = glm::normalize(front);
Right = glm::normalize(glm::cross(Forward, World_up));
Up = glm::normalize(glm::cross(Right, Forward));
}
openwidget.h
#ifndef OPENWIDGET_H
#define OPENWIDGET_H
#include<QOpenGLWidget>
#include<QOpenGLFunctions_3_3_Compatibility>
#include<QOpenGLShader>
#include<QOpenGLShaderProgram>
#include"Camera.h"
class OpenWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Compatibility
{
public:
OpenWidget();
~OpenWidget() override;
void keyPressEvent(QKeyEvent*)override;
private:
GLuint VAO;
GLuint VBO;
GLuint _VAO;
GLuint _VBO;
QOpenGLShader* vshader;
QOpenGLShader* fshader;
QOpenGLShaderProgram* shaderProgram;
QOpenGLShader* _vshader;
QOpenGLShader* _fshader;
QOpenGLShaderProgram* _shaderProgram;
GLuint texture;
GLuint texture1;
GLuint texture2;
GLuint texture3;
GLuint texture4;
Camera camera;
QPoint prepoint;
protected:
void paintGL() override;
void initializeGL() override;
void mouseMoveEvent(QMouseEvent*)override;
void mousePressEvent(QMouseEvent*)override;
void wheelEvent(QWheelEvent*)override;
};
#endif // OPENWIDGET_H
openwidget.cpp
#define STB_IMAGE_IMPLEMENTATION
#include<QTime>
#include<QMouseEvent>
#include "openwidget.h"
#include"stb/stb_image.h"
#include"glm/glm.hpp"
#include"glm/gtc/type_ptr.hpp"
#include "glm/gtc/matrix_transform.hpp"
OpenWidget::OpenWidget()
{
}
OpenWidget::~OpenWidget()
{
//释放VAOVBO
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &_VAO);
glDeleteBuffers(1, &_VBO);
}
void OpenWidget::initializeGL()
{
initializeOpenGLFunctions();
//glClearColor(0.0f, 0.0f, 0.0f, 0.1f);
//深度测试
glEnable(GL_DEPTH_TEST);
//线框模式
//glPolygonMode(GL_FRONT_AND_BACK ,GL_LINE );
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST); // Antialias the lines
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//着色器
shaderProgram=new QOpenGLShaderProgram;
vshader=new QOpenGLShader(QOpenGLShader::Vertex,shaderProgram);
fshader=new QOpenGLShader(QOpenGLShader::Fragment,shaderProgram);
vshader->compileSourceCode(
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 PosColor;\n"
"layout (location = 2) in vec2 aTexCoord;\n"
"out vec3 positionColor;\n"
"out vec2 TexCoord;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
" void main()\n"
" {\n"
" gl_Position =projection * view * model * vec4(aPos, 1.0);\n"
" positionColor=PosColor;\n"
"TexCoord = aTexCoord;\n"
" }\n"
);
fshader->compileSourceCode(
"#version 330 core\n"
"out vec4 FragColor;\n"
"in vec3 positionColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
"FragColor = texture(ourTexture, TexCoord) * vec4(positionColor, 1.0);\n"
"}\n"
);
shaderProgram->addShader(vshader);
shaderProgram->addShader(fshader);
shaderProgram->link();
//纹理
glEnable(GL_TEXTURE_2D);//允许采用2D纹理技术
glShadeModel(GL_SMOOTH);//设置阴影平滑模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//当所显示的纹理比加载进来的纹理小时,采用GL_LINEAR的方法来处理
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);//当所显示的纹理比加载进来的纹理大时,采用GL_LINEAR的方法来处理
glGenTextures(1,&texture);
glBindTexture(GL_TEXTURE_2D, texture);
int width, height, nrChannels;
unsigned char *data = stbi_load("D:/1 a project/Fractal_Tree/Fractal_Tree/IMG_20200408_142732.jpg", &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
qDebug("Failed to load texture" );
}
stbi_image_free(data);
glUniform1i(glGetUniformLocation(shaderProgram->programId(), "texture"), 0);
//顶点数据
float vertices[] = {
// 位置 // 颜色 //纹理
0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 0.5f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f,0.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 1.0f,1.0f, 0.0f,
0.0f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,0.5f, 1.0f
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
//绑定VAO
glBindVertexArray(VAO);
//绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
//把顶点数组复制到VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// 位置属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8* sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// 颜色属性
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8* sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//纹理坐标
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8* sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
//解除绑定VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
//解除绑定VAO
glBindVertexArray(0);
}
void OpenWidget::paintGL()
{
QMetaObject::invokeMethod(this,"update",Qt::QueuedConnection);
glClearColor(0.3f, 0.3f, 0.3f, 0.3f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//paint
//激活着色器
glUseProgram(shaderProgram->programId());
// Transform坐标变换矩阵
float ra=QTime(0,0,0).secsTo(QTime::currentTime());
glm::mat4 model(1);//model矩阵,局部坐标变换至世界坐标
model = glm::rotate(model, (float)glm::radians(30.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 view(1);//view矩阵,世界坐标变换至观察坐标系
view = camera.GetViewMatrix();
glm::mat4 projection(1);//projection矩阵,投影矩阵
projection = glm::perspective(glm::radians(camera.Zoom), (float)this->width()/this->height(), 0.1f, 100.0f);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram->programId(),"model"), 1, GL_FALSE,&model[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram->programId(),"view"), 1, GL_FALSE,&view[0][0]);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram->programId(),"projection"), 1, GL_FALSE,&projection[0][0]);
//绑定顶点缓存对象
glBindVertexArray(VAO);
glBindTexture(GL_TEXTURE_2D, texture);
//开始绘制
glDrawArrays(GL_TRIANGLES, 0, 6);
//解除绑定
glBindVertexArray(0);
}
void OpenWidget::mouseMoveEvent(QMouseEvent *event)
{
qDebug("jjjj");
float dx=event->pos().x()-prepoint.x();
float dy=prepoint.y()-event->pos().y();
prepoint=event->pos();
camera.ProcessMouseMovement(dx,dy);
}
void OpenWidget::mousePressEvent(QMouseEvent *event)
{
prepoint=event->pos();
}
void OpenWidget::wheelEvent(QWheelEvent *event)
{
float dy=event->delta()/20;
camera.ProcessMouseScroll(dy);
}
void OpenWidget::keyPressEvent(QKeyEvent *event)
{
float sensity=0.1f;
if(event->key()==Qt::Key_A)
{
camera.ProcessKeyboard(LEFT,sensity);
}
if(event->key()==Qt::Key_D)
{
camera.ProcessKeyboard(RIGHT,sensity);
}
if(event->key()==Qt::Key_W)
{
camera.ProcessKeyboard(FORWARD,sensity);
}
if(event->key()==Qt::Key_S)
{
camera.ProcessKeyboard(BACKWARD,sensity);
}
if(event->key()==Qt::Key_Q)
{
camera.ProcessKeyboard(UP,sensity);
}
if(event->key()==Qt::Key_Z)
{
camera.ProcessKeyboard(DOWN,sensity);
}
}