Qt5与现代OpenGL学习(十一)OpenGL Widget鼠标控制直线旋转

glwidget.h

cpp 复制代码
#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QMatrix4x4>
#include <QMouseEvent>
#include <QVector3D>

class GLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT
public:
    explicit GLWidget(QWidget *parent = nullptr);
    ~GLWidget() override;

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;

private:
    void initShaders();
    QVector3D getArcballVector(int x, int y);

    QOpenGLShaderProgram shaderProgram;
    QMatrix4x4 projection;
    QMatrix4x4 view;
    QMatrix4x4 model;

    // 旋转控制变量
    QPoint lastMousePos;
    QQuaternion rotation;
    QQuaternion lastRotation;
    float zoomFactor = 1.0f;



     float pointSize = 550.0f; // 控制点的大小



};

#endif // GLWIDGET_H

glwidget.cpp

cpp 复制代码
#include "glwidget.h"
#include <QMouseEvent>
#include <QWheelEvent>
#include <QtMath>
#include <QTimer>

GLWidget::GLWidget(QWidget *parent) : QOpenGLWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
}

GLWidget::~GLWidget()
{
    makeCurrent();
    doneCurrent();
}

void GLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glEnable(GL_DEPTH_TEST);
    initShaders();
}

void GLWidget::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
    projection.setToIdentity();
    projection.perspective(45.0f, (float)w/(float)h, 0.1f, 100.0f);
    view.setToIdentity();
    view.translate(0.0f, 0.0f, -5.0f);
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    model.setToIdentity();
    model.scale(zoomFactor);
    model.rotate(rotation);

    QMatrix4x4 mvp = projection * view * model;

    shaderProgram.bind();
    shaderProgram.setUniformValue("mvpMatrix", mvp);







    GLfloat vertices[] = {
        -0.2f, 0.3f, 0.5f,  // p1
        1.0f, 1.0f, 1.0f     // p2
    };

    GLfloat colors[] = {
        1.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f
    };

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, colors);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glDrawArrays(GL_LINES, 0, 2);


















    // 绘制绿色原点(0,0,0)
        GLfloat pointVertex[] = {0.0f, 0.0f, 0.0f};
        GLfloat pointColor[] = {0.0f, 1.0f, 0.0f};

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, pointVertex);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, pointColor);


        glDrawArrays(GL_POINTS, 0, 1);







        GLfloat vertices1[] = {
            -0.2f, 0.3f, 0.5f,  // p1
            -1.0f, -1.0f, -1.0f     // p2
        };

        GLfloat colors1[] = {
            1.0f, 1.0f, 0.0f,
            1.0f, 1.0f, 0.0f
        };

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vertices1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, colors1);
        glEnableVertexAttribArray(0);
        glEnableVertexAttribArray(1);
        glDrawArrays(GL_LINES, 0, 2);




    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    shaderProgram.release();















}

void GLWidget::mousePressEvent(QMouseEvent *event)
{
    lastMousePos = event->pos();
    lastRotation = rotation;
}

void GLWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        // 获取当前和之前的鼠标位置对应的球面坐标
        QVector3D va = getArcballVector(lastMousePos.x(), lastMousePos.y());
        QVector3D vb = getArcballVector(event->x(), event->y());

        // 计算旋转轴和角度
        float angle = qAcos(qMin(1.0f, QVector3D::dotProduct(va, vb))) * 180.0f / M_PI;
        QVector3D axis = QVector3D::crossProduct(va, vb).normalized();

        // 更新旋转
        rotation = QQuaternion::fromAxisAndAngle(axis, angle) * lastRotation;
        update();
    }
}

void GLWidget::wheelEvent(QWheelEvent *event)
{
    float delta = event->angleDelta().y() / 120.0f;
    zoomFactor *= (1.0f + delta * 0.1f);
    zoomFactor = qBound(0.1f, zoomFactor, 2.0f);
    update();
}

QVector3D GLWidget::getArcballVector(int x, int y)
{
    // 将鼠标坐标映射到[-1, 1]范围
    float mx = (float)x / width() * 2.0f - 1.0f;
    float my = 1.0f - (float)y / height() * 2.0f;

    float length = mx * mx + my * my;
    if (length <= 1.0f) {
        return QVector3D(mx, my, qSqrt(1.0f - length));
    } else {
        // 如果超出单位球,归一化到球面
        return QVector3D(mx, my, 0.0f).normalized();
    }
}

void GLWidget::initShaders()
{
    const char *vertexShaderSource =
        "#version 330 core\n"
        "layout(location = 0) in vec3 position;\n"
        "layout(location = 1) in vec3 color;\n"
        "uniform mat4 mvpMatrix;\n"
        "out vec3 fragColor;\n"
        "void main() {\n"
        "   gl_Position = mvpMatrix * vec4(position, 1.0);\n"
        "   fragColor = color;\n"
        "}\n";

    const char *fragmentShaderSource =
        "#version 330 core\n"
        "in vec3 fragColor;\n"
        "out vec4 outColor;\n"
        "void main() {\n"
        "   outColor = vec4(fragColor, 1.0);\n"
        "}\n";

    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
    shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
    shaderProgram.link();
}

在mainwindow.ui中,添加OpenGLWidget,并提升为:GLWidget

相关推荐
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript