带有 Qt 和 OpenGL 的轨迹球控件
Posted
技术标签:
【中文标题】带有 Qt 和 OpenGL 的轨迹球控件【英文标题】:arcball controls with Qt, and OpenGL 【发布时间】:2014-05-19 20:52:45 【问题描述】:我正在尝试使用 Open GL 和 Qt 实现轨迹球/轨迹球控制器。但是,我对 OpenGL 还是很陌生。我有一个可怕的,可怕的,可怕的时间让事情正常工作。
我从以下视频开始:https://www.youtube.com/watch?v=3IQV65ApWGs
我正在为我的窗口使用 Qt,使用他们的 QtWidget 类。
基本上,我在原点周围有一个立方体。我想用鼠标围绕立方体旋转相机。现在,当我拖动相机时,当立方体围绕球体运行时,相机似乎保持不动。与我需要的相反。
希望大家帮忙。我觉得我已经在这里尝试了几乎所有东西。
首先我的鼠标处理:
void GLWidget::wheelEvent(QWheelEvent *e)
scrollDelta += e->delta() / 120;
void GLWidget::mousePressEvent(QMouseEvent *e)
rotate=false;
if(e->button() == Qt::LeftButton)
oldX = e->x(); // Set this to the mouse position
oldY = e->y(); // Set this to the mouse position
newX = e->x();
newY = e->y();
qDebug() << oldX << oldY << newX << newY;
rotate = true;
useArcBall = true;
void GLWidget::mouseMoveEvent(QMouseEvent *e)
if(e->buttons() & Qt::LeftButton)
//qDebug() << QString::number(e->x());
if(rotate)
newX = e->x();
newY = e->y();
updateMouse();
oldX = e->x();
oldY = e->y();
void GLWidget::mouseReleaseEvent(QMouseEvent *e)
if(e->button() == Qt::LeftButton)
useArcBall = false;
void GLWidget::updateMouse()
QVector3D v = getArcBallVector(oldX,oldY); // from the mouse
QVector3D u = getArcBallVector(newX, newY);
float angle = std::acos(std::min(1.0f, QVector3D::dotProduct(u,v)));
QVector3D rotAxis = QVector3D::crossProduct(v,u);
QMatrix4x4 eye2ObjSpaceMat = rotationMat.inverted();
QVector3D objSpaceRotAxis = eye2ObjSpaceMat * rotAxis;
qDebug() << 4 * qRadiansToDegrees(angle);
//modelview.rotate(4 * qRadiansToDegrees(angle), rotAxis);
//oldRot = newRot;
//oldX = newX;
//oldY = newY;
//qDebug() << objSpaceRotAxis.normalized();
if(true)
rotationMat.rotate(4 * qRadiansToDegrees(angle), objSpaceRotAxis);
现在是轨迹球相关的数学:
QVector3D GLWidget::getArcBallVector(int x, int y)
QVector3D pt = QVector3D(2.0 * x / GLWidget::width() - 1.0, 2.0 * y / GLWidget::height() - 1.0 , 0);
pt.setY(pt.y() * -1);
// compute z-coordinates
float xySquared = pt.x() * pt.x() + pt.y() * pt.y();
if(xySquared <= 1.0)
pt.setZ(std::sqrt(1.0 - xySquared));
else
pt.normalize();
return pt;
这是我渲染所有内容的部分:
void GLWidget::paintGL() QMatrix4x4 模型视图;
QPainter painter;
painter.begin(this);
painter.beginNativePainting();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFrontFace(GL_CW);
glCullFace(GL_FRONT);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
modelview.perspective(90.0f, 4.0f / 3.0f, 0.1f, 3000.0f);
modelview.lookAt(QVector3D(eyeX,eyeY,eyeZ), QVector3D(0,0,0), QVector3D(0,1,0));
// New Trackball code
modelview = rotationMat * modelview;
modelview.scale(1 - scrollDelta / 10);
我做错了什么? 我的方法不合理吗?
更新 所以我修复了一些鼠标处理。现在我的问题是立方体围绕球体表面旋转,而不是相机。这是因为我使用的是lookat 命令吗?
此外,当我转动立方体时,它会被背景颜色遮挡。这是投影问题吗?
【问题讨论】:
你从来没有设置过旧的,你需要在按下和更新鼠标之后设置它 我更新了问题。设置 old 有帮助,但并没有完全解决问题。 我还加了一个短视频youtube.com/watch?v=0CHPJZ2Ibt4&feature=youtu.be 您以错误的顺序应用矩阵,矩阵运算不可交换 YAAAAAAY 做到了。当然矩阵是不可交换的! DERP! 【参考方案1】:您的矩阵似乎以错误的顺序应用
在paintGL
你应该这样做:
modelview *= rotationMat;
在 updateMouse 中你应该这样做
QMatrix4x4 tmp;
tmp.rotate(4 * qRadiansToDegrees(angle), objSpaceRotAxis);
rotationMat = tmp * rotationMat;
【讨论】:
以上是关于带有 Qt 和 OpenGL 的轨迹球控件的主要内容,如果未能解决你的问题,请参考以下文章
带有 OpenGL 和 Kinect v2 的 QT5:错误的图像呈现
带有 OpenGL 的 Qt MDI 应用程序:如何获取有效的屏幕截图?