項目根據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 FPSmodel_ = 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 modelauto &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 trianglesint 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 shaderQFile 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 shaderQFile 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 shadersif (!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 programif (!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 anglesif (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 flippedif (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();
}
解決辦法:
- 在每一次使用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);
加了以后好一點了,但是鼠標拖拽有時候移動到其他位置再拖動,模型會突然跳一下,分析了一下原因是因為鼠標的位置沒有及時更新:
- 在構造函數加上鼠標的跟蹤,修改把獲取位置更新上一時刻位置放在if判斷外面:
void RobotView::mouseMoveEvent(QMouseEvent *event)
{// update Front, Right and Up Vectors using the updated Euler anglesfloat 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 flippedif (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還是看看用戶手冊的好