目的:实现鼠标控制正方形的平移、缩放、以及围绕自身某个点旋转。
要求:
- 坐标系固定在左下角
- 坐标系和正方形一起旋转,但不平移与缩放
- 鼠标左键平移正方形,右键旋转,滚轮缩放(放大与缩小)
步骤
- 编写绘制正方形与坐标系函数
- 在OpenGL窗口界面绘制
- 实现鼠标左键平移移动,右键旋转,滚轮缩放(放大与缩小)
- 设置正方形的旋转点,以及坐标系位置
- 将对应的鼠标事件应用到正方形与坐标系
实现:
- 步骤1:编写绘制正方形与坐标系函数(比较简单,就不贴代码了)
drawObjects();
drawaxis();
- 步骤2:在OpenGL窗口界面绘制
- 步骤5:将对应的鼠标事件应用到正方形与坐标系
void paintGL();
绘制OpenGL窗口界面。在这里绘制图形,并对图形设置了不同的变换。
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
int renderMode;
glGetIntegerv(GL_RENDER_MODE, &renderMode);
if (renderMode != GL_SELECT) {
// Matrix setting
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
const float aspect = static_cast<float>(width()) / height();
gluPerspective(45.0, aspect, 1.0, 1000.0);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glPushMatrix();
glMultMatrixf(m_transform.constData());//对drawObjects()的图形进行平移,旋转
glScalef(zscale,zscale,zscale);//缩放
drawObjects();
glPopMatrix();
glPushMatrix();
glTranslatef(-4, -3, 0);
glMultMatrixf(axis_transform.constData());//对drawaxis()的图形进行旋转
drawaxis();
glPopMatrix();
- 步骤3:设置鼠标左键平移移动,右键旋转
mouseMoveEvent(QMouseEvent* ev);
int dx = ev->x() - m_lastPos.x();
int dy = ev->y() - m_lastPos.y();
if(ev->buttons() & Qt::LeftButton)
{
translate(dx, dy);
}
else if(ev->buttons() & Qt::RightButton)
{
objects_rotate(dx, dy);
axis_rotate(dx, dy);
}
m_lastPos = ev->pos();
update();
-
步骤3:正方形的平移移动
translate(int dx, int dy);
m_translation.setX(m_translation.x() + dx * 0.01);
m_translation.setY(m_translation.y() - dy * 0.01);
m_transform.setToIdentity(); //将变换矩阵重置为单位矩阵
m_transform.translate(m_translation); //平移到正确的位置
m_transform.rotate(QQuaternion::fromAxisAndAngle(1, 0, 0, m_rotation.x()/* + 1*/));//将旋转状态应用到平移中
m_transform.rotate(QQuaternion::fromAxisAndAngle(0, 1, 0, m_rotation.y()/* + 1*/));
-
步骤3:坐标系的旋转
axis_rotate(int dx, int dy);
// 四元数: new_rotation = q * m_rotation * q逆 // q = xRot * yRot * zRot, 即 rotate()的参数
axis_rotation.setX(axis_rotation.x() - dy);
axis_rotation.setY(axis_rotation.y() - dx);
QQuaternion xRot = QQuaternion::fromAxisAndAngle(1, 0, 0, axis_rotation.x());//绕(0,0,0)点与(1,0,0)点连线,即x轴,旋转角度m_rotation.x()
QQuaternion yRot = QQuaternion::fromAxisAndAngle(0, 1, 0, axis_rotation.y());
axis_transform.setToIdentity();
axis_transform.rotate(xRot * yRot);
-
步骤3:正方形的旋转
objects_rotate(int dx, int dy);
m_rotation.setX(m_rotation.x() - dy);
m_rotation.setY(m_rotation.y() - dx);
QQuaternion xRot = QQuaternion::fromAxisAndAngle(1, 0, 0, m_rotation.x());//绕(0,0,0)点与(1,0,0)点连线,即x轴,旋转角度m_rotation.x()
QQuaternion yRot = QQuaternion::fromAxisAndAngle(0, 1, 0, m_rotation.y());
m_transform.setToIdentity();
m_transform.translate(m_translation); //将平移状态应用到旋转
m_transform.rotate(xRot * yRot);//四元数相乘,表示两次旋转
-
步骤3:正方形的滚轮缩放(放大与缩小)
wheelEvent(QWheelEvent *ev);
int delta = ev->delta(); // positive when wheel up, delta +/- 120 when wheel +/- 1
if(zscale-delta*2.0*1e-3>0)
zscale += delta*2.0*1e-3;
update();
-
步骤4:设置正方形的旋转点,以及坐标系位置
qt opengl中想要绕着某个点旋转,主要思维是将图形平移到该点位置,进行旋转操作后,再对图形做逆平移。
//*******设置坐标轴的旋转中心********
float centre_x, centre_y;
centre_x = -4;
centre_y = -3;
axis_translation.setX(centre_x);
axis_translation.setY(centre_y);
//******设置坐标轴的旋转中心*********
axis_transform.translate(axis_translation);//平移到centre点的位置
axis_transform.rotate(xRot * yRot);//旋转
axis_translation.setX(-centre_x);
axis_translation.setY(-centre_y);
axis_transform.translate(axis_translation);//逆平移
在最近研究这个问题的过程中,发现如果同时对图形做了平移与旋转,用上述方法难点在于对于旋转点的世界坐标的获取。目前只学习了将屏幕坐标转换为世界坐标,但是对于追踪某一点的世界坐标还有待学习(有懂的大佬希望可以教教我qwq)。然而眼前的问题还是要尽快解决的,后来发现了下面的方法。
glTranslatef(1, 1, 0);
没错,就是平移!其实也就是将正方形想要围绕旋转的点平移到原点(0,0)的位置。
我的正方形边长为2,所以这个代码意思是将正方形向右上方平移(二维平面),结果就是正方形左下角到了原点的位置。也就是我的正方形设置是围绕左下角旋转,在一系列平移,缩放后,可以一直围绕左下角旋转。文章来源:https://www.toymoban.com/news/detail-740778.html
效果展示
文章来源地址https://www.toymoban.com/news/detail-740778.html
题外话
- 对于上图坐标系显示文字的绘制办法下次记录
- 鼠标点击,选择拾取glSelectBuffer整理之后再记录
到了这里,关于c++ QT opengl鼠标控制平移、缩放、绕点旋转的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!