#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H
#include "QtGui/QOpenGLBuffer"
#include "QtWidgets/QOpenGLWidget"
#include "QtGui/QOpenGLVertexArrayObject"
#include "QtGui/QOpenGLFunctions_4_5_Core"
class OpenGLCamera;
class QOpenGLShaderProgram;
class OpenGLWidget
: public QOpenGLWidget
, protected QOpenGLFunctions_4_5_Core
{
public:
/* @接口 默认构造函数
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月8号
*/
OpenGLWidget();
/* @接口 默认析构
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月8号
*/
~OpenGLWidget();
/* @接口
* @返回
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月8号
*/
virtual void paintGL();
/* @接口
* @返回
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月8号
*/
virtual void initializeGL();
/* @接口
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月8号
*/
virtual void resizeGL(int, int);
/* @接口
* @返回
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
virtual void wheelEvent(QWheelEvent *);
/* @接口
* @返回
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
virtual void keyPressEvent(QKeyEvent *);
/* @接口
* @返回
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
virtual void mouseMoveEvent(QMouseEvent *);
/* @接口
* @返回
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
virtual void mousePressEvent(QMouseEvent *);
/* @接口
* @返回
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
virtual void mouseReleaseEvent(QMouseEvent *);
private:
/* @接口
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
bool initShader();
/* @接口
* @类名 [OpenGLWidget]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initOpenGLCamera();
private:
QPoint m_lastPt;
bool m_isMove = false;
OpenGLCamera *m_pCamera;
QOpenGLBuffer m_vbo, m_ebo;
QOpenGLVertexArrayObject m_vao;
QOpenGLShaderProgram *m_shaderProgram;
};
#endif /*OPENGLWIDGET_H*/
#include "openglmvp.h"
#include "openglwidget.h"
#include "openglcamera.h"
#include "QtGui/QWheelEvent"
#include "QtGui/QMouseEvent"
#include "QOpenGLShaderProgram"
const char *vertexShader =
"#version 450 core \n"
"in vec3 vPosition; \n"
"in vec3 vColor; \n"
"out vec4 outColor; \n"
"uniform mat4 gWorld; \n"
"void main() { \n"
" gl_Position = gWorld * vec4(vPosition * 0.5, 1.0); \n"
" outColor = vec4(vColor, 1.0); \n"
"} \n";
const char *fragmentShader =
"#version 450 core \n"
"in vec4 outColor; \n"
"out vec4 FragColor; \n"
"void main() { \n"
" FragColor = outColor; \n"
"} \n";
OpenGLWidget::OpenGLWidget()
: QOpenGLWidget(), m_vao()
, m_ebo(QOpenGLBuffer::IndexBuffer)
, m_vbo(QOpenGLBuffer::VertexBuffer)
{
QSurfaceFormat surfaceFormat;
surfaceFormat.setSamples(4);//多重采样
setFormat(surfaceFormat); //setFormat是QOpenGLWidget的函数
setFocusPolicy(Qt::StrongFocus);
}
OpenGLWidget::~OpenGLWidget()
{
}
void OpenGLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
OpenGLMVP mvp;
mvp.initWorldMove(QVector3D(0, 0, -5));
mvp.initCameraPos(m_pCamera->getCameraPos());
mvp.initCameraTarget(m_pCamera->getCameraTarget());
mvp.initCameraUp(m_pCamera->getCameraUp());
mvp.initPerpectivePro(30, width() / height(), 1.0f, 100.0f);
QMatrix4x4 gWorld = mvp.getTransform();
m_shaderProgram->setUniformValue("gWorld", gWorld);
m_vao.bind();
glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, 0);
m_vao.release();
}
bool OpenGLWidget::initShader()
{
m_shaderProgram = new QOpenGLShaderProgram;
m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader);
m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader);
if(!m_shaderProgram->link()) return false;
return m_shaderProgram->bind();
}
void OpenGLWidget::initializeGL()
{
initializeOpenGLFunctions(); //初始化OPenGL功能函数
glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
glClearDepth(1.0);
glEnable(GL_DEPTH_TEST);
if(!initShader()) return;
float vertices[] = {
-1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f
};
GLuint indices[] = {
0, 3, 1,
1, 3, 2,
2, 3, 0,
0, 1, 2
};
m_vao.create();
m_vao.bind();
m_vbo.create();
m_vbo.bind();
m_vbo.allocate(vertices, 4 * 6 * sizeof(GLfloat));
m_ebo.create();
m_ebo.bind();
m_ebo.allocate(indices, 4 * 3 * sizeof(GLuint));
int attr = -1;
//顶点属性设置
attr = m_shaderProgram->attributeLocation("vPosition");
m_shaderProgram->setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 6);
m_shaderProgram->enableAttributeArray(attr);
//颜色属性设置
attr = m_shaderProgram->attributeLocation("vColor");
m_shaderProgram->setAttributeBuffer(attr, GL_FLOAT, sizeof(GLfloat) * 3, 3, sizeof(GLfloat) * 6);
m_shaderProgram->enableAttributeArray(attr);
m_vao.release();
m_vbo.release();
m_ebo.release();
initOpenGLCamera();
}
void OpenGLWidget::initOpenGLCamera()
{
m_pCamera = new OpenGLCamera;
}
void OpenGLWidget::resizeGL(int w, int h)
{
glViewport(0, 0, w, h);
}
void OpenGLWidget::wheelEvent(QWheelEvent *ev)
{
double val = ev->delta() * 1.0 / 120;
m_pCamera->setCameraVecMove(val);
repaint();
}
void OpenGLWidget::keyPressEvent(QKeyEvent *ev)
{
switch(ev->key())
{
case Qt::Key_Up: m_pCamera->setCameraVecMove(-1.0); break;
case Qt::Key_Down: m_pCamera->setCameraVecMove(1.0); break;
case Qt::Key_Left: m_pCamera->setCameraHorMove(-1.0); break;
case Qt::Key_Right: m_pCamera->setCameraHorMove(1.0); break;
}
repaint();
QOpenGLWidget::keyPressEvent(ev);
}
void OpenGLWidget::mouseMoveEvent(QMouseEvent *ev)
{
if(m_isMove)
{
QPoint pt = ev->pos();
double x = pt.x() - m_lastPt.x();
double y = pt.y() - m_lastPt.y();
}
}
void OpenGLWidget::mousePressEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::MiddleButton)
{
m_isMove = true;
m_lastPt = ev->pos();
}
}
void OpenGLWidget::mouseReleaseEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::MiddleButton)
m_isMove = false;
}
OpenGLMVP头文件:
#ifndef OPENGLMVP_H
#define OPENGLMVP_H
class QVector2D;
class QVector3D;
class QMatrix4x4;
class OpenGLMVPData;
class OpenGLMVP
{
public:
/* @接口 默认构造函数
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
OpenGLMVP();
/* @接口 默认析构
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
~OpenGLMVP();
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
const QMatrix4x4 getTransform();
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldScale(float);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCameraUp(const QVector2D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCameraUp(const QVector3D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCameraPos(const QVector2D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCameraPos(const QVector3D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldMove(const QVector2D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldMove(const QVector3D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldScale(const QVector2D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldScale(const QVector3D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldRotate(const QVector2D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldRotate(const QVector3D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCameraTarget(const QVector2D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCameraTarget(const QVector3D &);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldScale(float, float, float = 1.0);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldMove(float, float = 0.0, float = 0.0);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCameraUp(float, float = 0.0f, float = 0.0f);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCameraPos(float, float = 0.0f, float = 0.0f);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initWorldRotate(float, float = 0.0, float = 0.0);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initPerpectivePro(double, double, double, double);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCameraTarget(float, float = 0.0f, float = 0.0f);
/* @接口
* @类名 [OpenGLMVP]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void initCamera(const QVector3D &, const QVector3D &, const QVector3D &);
private:
OpenGLMVPData *m_mvpData;
};
#endif /*OPENGLMVP_H*/
OpenGLMVP源文件:
#ifndef OPENGLMVP_H
#include "openglmvp.h"
#endif /*OPENGLMVP_H*/
#include "QtGui/QMatrix4x4"
#define PI 3.14159265358979323846264338327
#define ToRadian(val) PI * val / 180
struct OpenGLMVPData
{
/* @接口 默认构造函数
* @类名 [OpenGLMVPData]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
OpenGLMVPData();
QVector3D m_cameraUp;
QVector3D m_cameraPos;
QMatrix4x4 m_worldMove;
QMatrix4x4 m_cameraMove;
QMatrix4x4 m_worldScale;
QMatrix4x4 m_worldRotate;
QVector3D m_cameraTarget;
QMatrix4x4 m_cameraRotate;
QMatrix4x4 m_perpectivePro;
const QMatrix4x4 getCameraMatrix();
const QMatrix4x4 getWorldTransform();
};
QVector3D vectorCross(const QVector3D &u, const QVector3D &v)
{
float x = u.y() * v.z() - u.z() * v.y();
float y = u.z() * v.x() - u.x() * v.z();
float z = u.x() * v.y() - u.y() * v.x();
return QVector3D(x, y, z);
}
OpenGLMVP::OpenGLMVP()
: m_mvpData(new OpenGLMVPData)
{
}
OpenGLMVP::~OpenGLMVP()
{
}
OpenGLMVPData::OpenGLMVPData()
: m_cameraPos(0, 0, 1)
, m_cameraUp(0, 1, 0)
, m_cameraTarget(0, 0, -1)
{
}
const QMatrix4x4 OpenGLMVP::getTransform()
{
return m_mvpData->m_perpectivePro * m_mvpData->getCameraMatrix() * m_mvpData->getWorldTransform();
}
void OpenGLMVP::initWorldScale(float scale)
{
initWorldScale(QVector3D(scale, scale, scale));
}
void OpenGLMVP::initCameraUp(const QVector2D &up)
{
initCameraUp(QVector3D(up, 0));
}
void OpenGLMVP::initCameraUp(const QVector3D &up)
{
m_mvpData->m_cameraUp = up;
}
const QMatrix4x4 OpenGLMVPData::getCameraMatrix()
{
m_cameraMove.translate(-m_cameraPos);
QVector3D U = m_cameraUp, N = m_cameraTarget;
U.normalize(); N.normalize();
U = vectorCross(U, N);
QVector3D V = vectorCross(N, U);
m_cameraRotate.setRow(0, QVector4D(U.x(), U.y(), U.z(), 0));
m_cameraRotate.setRow(1, QVector4D(V.x(), V.y(), V.z(), 0));
m_cameraRotate.setRow(2, QVector4D(N.x(), N.y(), N.z(), 0));
return m_cameraRotate * m_cameraMove;
}
const QMatrix4x4 OpenGLMVPData::getWorldTransform()
{
return m_worldMove * m_worldRotate * m_worldScale;
}
void OpenGLMVP::initCameraPos(const QVector2D &pos)
{
initCameraPos(QVector3D(pos, 0));
}
void OpenGLMVP::initCameraPos(const QVector3D &pos)
{
m_mvpData->m_cameraPos = pos;
}
void OpenGLMVP::initWorldMove(const QVector2D &move)
{
initWorldMove(QVector3D(move, 0.0));
}
void OpenGLMVP::initWorldMove(const QVector3D &move)
{
m_mvpData->m_worldMove.translate(move);
}
void OpenGLMVP::initWorldScale(const QVector2D &scale)
{
initWorldScale(QVector3D(scale, 1.0));
}
void OpenGLMVP::initWorldScale(const QVector3D &scale)
{
m_mvpData->m_worldMove.scale(scale);
}
void OpenGLMVP::initCameraUp(float x, float y, float z)
{
initCameraUp(QVector3D(x, y, z));
}
void OpenGLMVP::initCameraPos(float x, float y, float z)
{
initCameraPos(QVector3D(x, y, z));
}
void OpenGLMVP::initWorldRotate(const QVector2D &rotate)
{
initWorldRotate(QVector3D(rotate, 0));
}
void OpenGLMVP::initWorldRotate(const QVector3D &rotate)
{
QMatrix4x4 xRotate, yRotate, zRotate;
xRotate.rotate(ToRadian(rotate.x()), 1.0, 0.0, 0.0);
yRotate.rotate(ToRadian(rotate.y()), 0.0, 1.0, 0.0);
zRotate.rotate(ToRadian(rotate.z()), 0.0, 0.0, 1.0);
m_mvpData->m_worldRotate = zRotate * yRotate * xRotate;
}
void OpenGLMVP::initWorldMove(float x, float y, float z)
{
initWorldMove(QVector3D(x, y, z));
}
void OpenGLMVP::initWorldScale(float x, float y, float z)
{
initWorldScale(QVector3D(x, y, z));
}
void OpenGLMVP::initCameraTarget(const QVector2D &target)
{
initCameraTarget(QVector3D(target, 0.0));
}
void OpenGLMVP::initCameraTarget(const QVector3D &target)
{
m_mvpData->m_cameraTarget = target;
}
void OpenGLMVP::initWorldRotate(float x, float y, float z)
{
initWorldRotate(QVector3D(x, y, z));
}
void OpenGLMVP::initCameraTarget(float x, float y, float z)
{
initCameraTarget(QVector3D(x, y, z));
}
void OpenGLMVP::initPerpectivePro(double angle, double ratio, double near, double far)
{
m_mvpData->m_perpectivePro.perspective(angle, ratio, near, far);
}
void OpenGLMVP::initCamera(const QVector3D &pos, const QVector3D &up, const QVector3D &target)
{
m_mvpData->m_cameraUp = up;
m_mvpData->m_cameraPos = pos;
m_mvpData->m_cameraTarget = target;
}
OpenGLCamera头文件:
#ifndef OPENGLCAMERA_H
#define OPENGLCAMERA_H
#include "QtGui/QVector3D"
class OpenGLCamera
{
public:
/* @接口 默认构造函数
* @类名 [OpenGLCamera]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
OpenGLCamera();
/* @接口 默认构造函数
* @类名 [OpenGLCamera]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
OpenGLCamera(const QVector3D &, const QVector3D &, const QVector3D &);
/* @接口 默认析构
* @类名 [OpenGLCamera]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
~OpenGLCamera();
/* @接口
* @类名 [OpenGLCamera]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void setCameraHorMove(float);
/* @接口
* @类名 [OpenGLCamera]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
void setCameraVecMove(float);
/* @接口
* @类名 [OpenGLCamera]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
const QVector3D &getCameraUp();
/* @接口
* @类名 [OpenGLCamera]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
const QVector3D &getCameraPos();
/* @接口
* @类名 [OpenGLCamera]
* @作者 杨发荷
* @邮箱 575814050@qq.com
* @时间 2021年10月17号
*/
const QVector3D &getCameraTarget();
private:
double m_step;
QVector3D m_up;
QVector3D m_pos;
QVector3D m_target;
};
#endif /*OPENGLCAMERA_H*/
OpenGLCamera源文件:
#include "openglcamera.h"
#include "QtGui/QVector3D"
OpenGLCamera::OpenGLCamera()
: m_up(0, 1, 0)
, m_pos(0, 0, -10)
, m_target(0, 0, -1)
, m_step(0.1)
{
}
extern QVector3D vectorCross(const QVector3D &u, const QVector3D &v);
OpenGLCamera::OpenGLCamera(const QVector3D &pos, const QVector3D &target, const QVector3D &up)
{
m_pos = pos; m_target = target; m_up = up;
m_target.normalize(); m_up.normalize();
}
OpenGLCamera::~OpenGLCamera()
{
}
const QVector3D &OpenGLCamera::getCameraUp()
{
return m_up;
}
const QVector3D &OpenGLCamera::getCameraPos()
{
return m_pos;
}
void OpenGLCamera::setCameraHorMove(float dir)
{
QVector3D move = vectorCross(m_target, m_up);
move.normalize();
m_pos += move * m_step * dir;
}
void OpenGLCamera::setCameraVecMove(float dir)
{
m_pos += m_target * m_step * dir;
}
const QVector3D &OpenGLCamera::getCameraTarget()
{
return m_target;
}
运行效果:
![](https://i-blog.csdnimg.cn/blog_migrate/f938ae5bd1184d35443e7a0b62915dc4.gif)
QOpenGLWidget 第四篇 透视投影
QOpenGLWidget第六篇 简化相机类