当前位置: 首页 > news >正文

Qt配置OpenGL相机踩的坑

项目根据LearnOpenGL配置Qt的相机,更新view矩阵和project矩阵的位移向量变得很大,我设置的明明相机位置是(0,0,3),理想的位移向量刚好是相反数(0,0,-3),对应的view矩阵位置向量可以变成(0,0,1200)…离模型非常远矩阵模型也看不见:

#include "UI/RobotView.h"
#include <QtCore/QtGlobal>
#include <QtCore/QFile>
#include <QtCore/QDebug>
#include <QtGui/QMouseEvent>
#include <QtGui/QWheelEvent>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLBuffer>
#include <QtGui/QOpenGLVertexArrayObject>
#include <QtGui/QMatrix4x4>
#include <QtGui/QVector3D>
#include <QtWidgets/QOpenGLWidget>
#include <QElapsedTimer>
#include <QtMath>

#include <urdf_model/model.h>
#include <urdf_parser/urdf_parser.h>

RobotView::RobotView(QWidget *parent) : QOpenGLWidget(parent),
                                        VBO(QOpenGLBuffer::VertexBuffer),
                                        model_(nullptr),
                                        firstMouse(true),
                                        cameraZoom(45.0f),
                                        cameraYaw(-90.0f),
                                        cameraPitch(0.0f),
                                        cameraPosition(0.0f, 0.0f, 3.0f),
                                        worldUp(0.0f, 1.0f, 0.0f),
                                        cameraFront(0.0f, 0.0f, -1.0f), //*
                                        cameraUp(0.0f, 1.0f, 0.0f),
                                        mouseSensitivity(0.1f)
{
    setFocusPolicy(Qt::StrongFocus);

    frameCount = 0;
    fps = 0.0f;

    fpsTimer = new QTimer(this);
    connect(fpsTimer, &QTimer::timeout, this, [this]()
            {
                fps = frameCount;
                frameCount = 0;
                emit sendFPS(fps); // 发送帧率信号
            });
    fpsTimer->start(1000);
    updateTimer = new QTimer(this);
    connect(updateTimer, &QTimer::timeout, this, [this]()
            { update(); });
    updateTimer->start(16); // 60 FPS
    model_ = new RobotModel();
    viewMatrix.lookAt(cameraPosition, cameraPosition + cameraFront, cameraUp);
    projectionMatrix.perspective(cameraZoom, float(width()) / float(height()), 0.01f, 200.0f);
    if (!model_->loadFromURDF(":/assets/instrument_sim/urdf/instrument_sim.urdf"))
    {
        qCritical() << "Failed to load URDF file";
        delete model_;
    }
}

RobotView::~RobotView()
{
    delete fpsTimer;
    delete updateTimer;
    delete model_;
    fpsTimer = nullptr;
    updateTimer = nullptr;
    model_ = nullptr;
    cleanupGL();
}

void RobotView::initializeGL()
{
    initializeOpenGLFunctions();

    VAO.create();
    VBO.create();

    VAO.bind();
    VBO.bind();
    if (!initShaders())
    {
        qCritical() << "Failed to initialize shaders";
        return;
    }

    VAO.release();
    VBO.release();

    glEnable(GL_DEPTH_TEST);
}

void RobotView::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
}

void RobotView::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    shaderProgram.bind();
    projectionMatrix.perspective(cameraZoom, float(width()) / float(height()), 0.01f, 200.0f);
    viewMatrix.lookAt(cameraPosition, cameraPosition + cameraFront, cameraUp);

    // 将矩阵传递给着色器
    shaderProgram.setUniformValue("lightPos", lightPos);
    shaderProgram.setUniformValue("viewPos", cameraPosition);
    shaderProgram.setUniformValue("objectColor", objectColor);
    shaderProgram.setUniformValue("lightColor", lightColor);
    shaderProgram.setUniformValue("projectionMatrix", projectionMatrix);
    shaderProgram.setUniformValue("viewMatrix", viewMatrix);

    VAO.bind();

    // // Draw robot model
    auto &link = model_->getLinks()[1];
    if (link.visual)
    {
        VBO.bind();

        VBO.allocate(link.visual->getVertices(), link.visual->getVerticesSize() * sizeof(float));
        modelMatrix.setToIdentity();
        shaderProgram.setUniformValue("modelMatrix", modelMatrix);
        // Draw triangles
        int positionAttribute = shaderProgram.attributeLocation("aPos");
        shaderProgram.enableAttributeArray(positionAttribute);
        shaderProgram.setAttributeBuffer(positionAttribute, GL_FLOAT, 0, 3, 6 * sizeof(GLfloat));

        // 设置顶点属性
        int normalAttribute = shaderProgram.attributeLocation("aNormal");
        shaderProgram.enableAttributeArray(normalAttribute);
        shaderProgram.setAttributeBuffer(normalAttribute, GL_FLOAT, 3 * sizeof(GLfloat), 3, 6 * sizeof(GLfloat));
        glDrawArrays(GL_TRIANGLES, 0, link.visual->getVerticesSize() / 6);

        VBO.release();
    }
    VAO.release();
    shaderProgram.release();

    frameCount++;
}

bool RobotView::initShaders()
{
    // Load vertex shader
    QFile vertShaderFile(":/assets/shaders/phongShader.vert");

    if (!vertShaderFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qCritical() << "Failed to open vertex shader file:" << vertShaderFile.fileName();
        doneCurrent();
        return false;
    }
    QString vertShaderSource = vertShaderFile.readAll();
    vertShaderFile.close();

    // Load fragment shader
    QFile fragShaderFile(":/assets/shaders/phongShader.frag");

    if (!fragShaderFile.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qCritical() << "Failed to open fragment shader file:" << fragShaderFile.fileName();
        return false;
    }
    QString fragShaderSource = fragShaderFile.readAll();
    fragShaderFile.close();

    // Compile shaders
    if (!shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, vertShaderSource))
    {
        qCritical() << "Failed to compile vertex shader:" << shaderProgram.log();
        return false;
    }

    if (!shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, fragShaderSource))
    {
        qCritical() << "Failed to compile fragment shader:" << shaderProgram.log();
        return false;
    }

    // Link shader program
    if (!shaderProgram.link())
    {
        qCritical() << "Failed to link shader program:" << shaderProgram.log();
        return false;
    }

    return true;
}

void RobotView::mouseMoveEvent(QMouseEvent *event)
{
    // update Front, Right and Up Vectors using the updated Euler angles
    
    if (event->buttons() & Qt::LeftButton)
    {
    	float xPos = event->x();
    	float yPos = event->y();
        if (firstMouse)
        {
            lastMousePosX = xPos;
            lastMousePosY = yPos;
            firstMouse = false;
        }
        float xoffset = xPos - lastMousePosX;
        float yoffset = lastMousePosY - yPos;

		lastMousePosX = xPos;
	    lastMousePosY = yPos;
	    
        xoffset *= mouseSensitivity;
        yoffset *= mouseSensitivity;

        cameraYaw += xoffset;
        cameraPitch += yoffset;

        // make sure that when pitch is out of bounds, screen doesn't get flipped
        if (cameraPitch > 89.0f)
            cameraPitch = 89.0f;
        if (cameraPitch < -89.0f)
            cameraPitch = -89.0f;
        QVector3D front;
        front.setX(cos(qDegreesToRadians(cameraYaw)) * cos(qDegreesToRadians(cameraPitch)));
        front.setY(sin(qDegreesToRadians(cameraPitch)));
        front.setZ(sin(qDegreesToRadians(cameraYaw)) * cos(qDegreesToRadians(cameraPitch)));
        cameraFront = front.normalized();
    }
    
}


void RobotView::cleanupGL()
{
    makeCurrent();
    VAO.destroy();
    VBO.destroy();
    shaderProgram.removeAllShaders();
    doneCurrent();
}


解决办法:

  1. 在每一次使用lookat和perspective函数前都将矩阵置为identity,根据手册,这两个函数api和glm不一样,会一直连乘之前的矩阵,所以调用这个函数api,先得吧矩阵view和project变为单位阵,防止一直连乘跑飞
    在这里插入图片描述

在这里插入图片描述

projectionMatrix.setToIdentity();
projectionMatrix.perspective(cameraZoom, float(width()) / float(height()), 0.01f, 200.0f);
viewMatrix.setToIdentity();
viewMatrix.lookAt(cameraPosition, cameraPosition + cameraFront, cameraUp);

加了以后好一点了,但是鼠标拖拽有时候移动到其他位置再拖动,模型会突然跳一下,分析了一下原因是因为鼠标的位置没有及时更新:

  1. 在构造函数加上鼠标的跟踪,修改把获取位置更新上一时刻位置放在if判断外面:

void RobotView::mouseMoveEvent(QMouseEvent *event)
{
    // update Front, Right and Up Vectors using the updated Euler angles
    float xPos = event->x();
    float yPos = event->y();
    if (event->buttons() & Qt::LeftButton)
    {
        if (firstMouse)
        {
            lastMousePosX = xPos;
            lastMousePosY = yPos;
            firstMouse = false;
        }
        float xoffset = xPos - lastMousePosX;
        float yoffset = lastMousePosY - yPos;

        xoffset *= mouseSensitivity;
        yoffset *= mouseSensitivity;

        cameraYaw += xoffset;
        cameraPitch += yoffset;

        // make sure that when pitch is out of bounds, screen doesn't get flipped
        if (cameraPitch > 89.0f)
            cameraPitch = 89.0f;
        if (cameraPitch < -89.0f)
            cameraPitch = -89.0f;
        QVector3D front;
        front.setX(cos(qDegreesToRadians(cameraYaw)) * cos(qDegreesToRadians(cameraPitch)));
        front.setY(sin(qDegreesToRadians(cameraPitch)));
        front.setZ(sin(qDegreesToRadians(cameraYaw)) * cos(qDegreesToRadians(cameraPitch)));
        cameraFront = front.normalized();
        // viewMatrix.setToIdentity();
        // viewMatrix.lookAt(cameraPosition, cameraPosition + cameraFront, cameraUp);
    }
    lastMousePosX = xPos;
    lastMousePosY = yPos;
}

但是发现还是有问题,貌似mouseMove事件需要按键按下才触发,鼠标的位置没有得到及时更新,经过查资料,推测可能是没有开启鼠标的跟踪,在构造函数加入下面的语句就可以了

setMouseTracking(true);

调bug还是看看用户手册的好

相关文章:

  • 蓝桥杯 C++ b组 统计子矩阵双指针+一维前缀和
  • 【2025深夜随笔】简单认识一下Android Studio
  • Redis 缓存穿透、缓存击穿与缓存雪崩详解:问题、解决方案与最佳实践
  • C语言一维数组
  • SD模型进阶学习全攻略(三)
  • 深入理解Mesa:Linux图形渲染背后的开源力量
  • OSPF总结
  • 正则表达式快速入门
  • MyBatis 中SQL 映射文件是如何与 Mapper 接口关联起来的? MyBatis 如何知道应该调用哪个 SQL 语句?
  • 高校数字素养通识教育解决方案
  • 饮食调治痉挛性斜颈,开启健康生活
  • 【python运行Janus-Pro-1B文生图功能】
  • 可视化图解算法:链表指定区间反转
  • 版本号标识
  • 【C++】C++11新特性
  • C语言中scanf(“%c“,s)会出现的问题
  • mac安装mysql之后报错zsh: command not found: mysql !
  • 如何在Python下实现摄像头|屏幕|AI视觉算法数据的RTMP直播推送
  • 用0去修改数据库异常
  • MySQL的安装与建表
  • 美军空袭也门拘留中心,已致68人死亡
  • 大家聊中国式现代化|陶希东:打造高水平安全韧性城市,给群众看得见的安全感
  • 仅退款正式成历史?仅退款究竟该不该有?
  • 新闻1+1丨应对外部冲击,中央政治局会议释放哪些信号?
  • 政治局会议:优化存量商品房收购政策,持续巩固房地产市场稳定态势
  • 政治局会议:要提高中低收入群体收入,设立服务消费与养老再贷款