项目根据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();
}
解决办法:
- 在每一次使用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 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还是看看用户手册的好