程序里的三角形可以根据鼠标移动,滚轮实现旋转。同时添加了一个定时器实现自动旋转。
代码结构:
代码:
QT += core gui opengl widgets
greaterThan(QT_MAJOR_VERSION, 5)
TARGET = openGL_1
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QMouseEvent>
#include <QWheelEvent>
class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
GLWidget(QWidget *parent = nullptr);
~GLWidget();
protected:
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
void mousePressEvent(QMouseEvent *event)override;
void mouseMoveEvent(QMouseEvent *event)override;
void wheelEvent(QWheelEvent *event)override;
void mouseReleaseEvent(QMouseEvent *event)override;
private:
float rotationAngle;//旋转角度
QPointF trianglePos;//三角形位置(OpenGL坐标)
QPointF lastMousePos;//上次鼠标位置(屏幕坐标)
bool isDragging;//是否正在拖动
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include <QMouseEvent>
#include <QWheelEvent>
#include <cmath>
#include <QTimer>
GLWidget::GLWidget(QWidget *parent) :
QOpenGLWidget(parent),
rotationAngle(0),
trianglePos(0, 0),
isDragging(false)
{
setMouseTracking(true);//设置目标追踪
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, [this]() {
rotationAngle += 1.0f;
if(rotationAngle >= 360.0f) rotationAngle -= 360.0f;
update();
});
timer->start(16);
/* 大约60帧每秒
* 参数表示定时器每隔16毫秒触发一次timeout信号
* 1000毫秒(1秒) ÷ 16毫秒/帧 ≈ 62.5帧/秒
*/
}
GLWidget::~GLWidget()
{
//将当前OpenGL上下文(Context)绑定到该窗口(GLWidget)。
//OpenGL操作必须在正确的上下文中执行。析构时需要确保当前线程的上下文是该窗口的上下文,否则无法安全释放资源。
makeCurrent();
//解除当前上下文与窗口的绑定。 在对象销毁时,释放上下文关联,避免资源泄漏。
doneCurrent();
}
void GLWidget::initializeGL()
{
initializeOpenGLFunctions();
/* OpenGL中用于设置清除颜色缓冲区的颜色值的函数,
* 这个函数指定了当调用glClear(GL_COLOR_BUFFER_BIT)时,屏幕将被清除成的颜色。
* 具体参数:
* 第一个参数 (0.2f):红色分量 (Red)--取值范围:0.0(无红色)到1.0(最大红色)
* 第二个参数 (0.3f):绿色分量 (Green)
* 第三个参数 (0.3f):蓝色分量 (Blue)
* 第四个参数 (1.0f):Alpha通道(透明度)1.0表示完全不透明,0.0表示完全透明
* RGB(51, 76.5, 76.5) // 0.2*255≈51, 0.3*255≈76.5
* 这个颜色看起来像是:略带红色的深蓝绿色(类似深青色/墨绿色)
* 在OpenGL中,这个设置是"状态设置"(state-setting)函数,它不会立即改变任何东西,只是告诉OpenGL:"下次清除颜色缓冲区时,请使用这个颜色"。
* 实际清除操作是在调用glClear(GL_COLOR_BUFFER_BIT)时执行的,这个函数会用之前设置的清除颜色填充整个颜色缓冲区
*/
glClearColor(0.2f, 0.3f, 0.3f, 0.0f);
}
void GLWidget::resizeGL(int w, int h)
{
/* resizeGL(int w, int h) 是 QOpenGLWidget 中的一个关键函数,
* 专门用于处理窗口大小变化时的OpenGL视口(Viewport)和投影矩阵的调整。
* 它的核心作用是 确保OpenGL渲染内容能正确适应窗口尺寸的变化。
*/
glViewport(0, 0, w, h);//定义OpenGL渲染的可视区域(视口)
/*前两个参数 (0, 0):视口左下角在窗口中的坐标(通常是窗口左下角)。
后两个参数 (w, h):视口的宽度和高度(一般等于窗口的新尺寸)。
效果:当窗口大小改变时,OpenGL会将渲染内容拉伸或压缩到新的视口范围内。
如果不调用 glViewport,窗口尺寸变化时,渲染内容可能会:
保持原比例导致黑边(未填满窗口)。
拉伸变形(未正确适配新尺寸)。
它确保了OpenGL坐标系到屏幕坐标系的正确映射。
使用:1、窗口大小调整--用户拖动窗口边缘时,Qt会自动调用此函数。例如:从800x600调整为1024x768时,w 和 h 会更新为新值。
2、初始化时--在initializeGL()之后,Qt会首次调用resizeGL()设置初始视口。
*/
}
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 1. 清除颜色缓冲区和深度缓冲区
// 2. 设置投影矩阵
glMatrixMode(GL_PROJECTION);//切换到投影矩阵栈
glLoadIdentity();//重置当前矩阵为单位矩阵
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);//设置正交投影
// 3. 设置模型视图矩阵
glMatrixMode(GL_MODELVIEW);// 切换到模型视图矩阵栈
glLoadIdentity(); // 重置当前矩阵为单位矩阵
// 4、应用模型变换
glTranslatef(trianglePos.x(), trianglePos.y(), 0.0f);//平移
glRotatef(rotationAngle, 0.0f, 0.0f, 1.0f);//旋转
// 5、绘制三角形
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);//第一个顶点(红色)
glVertex2f(-0.2f, -0.2f);//设置顶点坐标
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2f(0.2f, -0.2f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.2f);
glEnd();
}
void GLWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
isDragging = true;
lastMousePos = event->pos();
}
}
void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
if (isDragging) {
// 计算鼠标移动的增量
QPointF delta = event->pos() - lastMousePos;
lastMousePos = event->pos();
// 将屏幕坐标转换为OpenGL坐标
// 注意Y轴方向相反
float glDeltaX = 2.0f * delta.x() / width();
float glDeltaY = -2.0f * delta.y() / height();
// 更新三角形位置
trianglePos += QPointF(glDeltaX, glDeltaY);
update();
}
}
void GLWidget::wheelEvent(QWheelEvent *event)
{
// 获取滚轮角度增量
QPoint angleDelta = event->angleDelta();
// 通常垂直滚轮数据在angleDelta.y()
if (!angleDelta.isNull()) {
rotationAngle += angleDelta.y() * 0.1f; // 调整旋转速度
//向上滚动:顺时针|向下滚动:逆时针
// 规范化角度到0-360范围
if (rotationAngle > 360.0f) rotationAngle -= 360.0f;
if (rotationAngle < 0.0f) rotationAngle += 360.0f;
update();
}
}
void GLWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
isDragging = false;
}
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
setWindowTitle("OpenGL_1");
resize(600, 600);
GLWidget *glWidget = new GLWidget(this);
setCentralWidget(glWidget);
}
MainWindow::~MainWindow()
{
}
#include "mainwindow.h"
#include <QApplication>
#include "glwidget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}