近期在折腾点云可视化的一些东西, 让我参考 的功能自己用 去实现,虽然 提供了现成的功能,但是 执意让我自己去写,一方面是因为自己写可以写更灵活的功能,另一方面就是锻炼我的能力吧~~~
首先,需要将点云里的数据加载出来,按照我个人的理解,点云里的数据就是一堆点的信息, 存放在类似数组或者向量中,具体是什么没有深入研究……然后第一步是对这些点进行了一个上色的操作,读取了一个色卡,然后根据点云中点的 轴信息进行上色,这个也是为了看着更清晰,毕竟在之后要进行一些缩放旋转操作,全部都是一个颜色,看着可能并没有那么强的立体感?这是我个人的理解。
这是上色后的样子,未上色的样子自己跑一下 就知道了。
接着做的是放大的功能,做这个功能是要理解几个重要的矩形(其他两个功能同样要用到这个),也可以说是需要理解 的坐标系统。
不过一开始我并没有理解太明白,以为必须自己用数学函数去写矩阵进行变化,但是始终没有显示效果,后来才发现,只需要用到人家提供的函数—— ,不过这里需要注意的是,用这个函数进行操作是在当前矩阵上进行变换,当前矩阵是一个状态机,假如说此时矩阵的功能是在 轴分别放大 倍,那么再执行一次 时,就是在这个基础上再放大两倍,一共是三十倍,而不是最开始的两倍,这里如果想要实现放大最开始的两倍,可以 一下将状态机重置为单位阵,不过也可以将原来的状态机保存到栈内,改变放大倍数时,弹出栈内的状态机覆盖现在的再进行变换。
这里我就不需要那么麻烦了,因为需要做的是根据鼠标滑轮事件进行放大缩小,并不需要在最开始的数据上操作,只要对现在的状态进行放大 倍或者缩小 倍即可。嗯,这里鼠标事件也得了解一下,不知道为啥,我直接将 函数放在鼠标事件响应的函数中时,没有实现功能,所以我直接在这个里面记录一个 来标记状态机下次的变换参数,默认为 ,放大时设置为 ,缩小时置为 。
void Widget::wheelEvent(QWheelEvent *event)
{
qDebug() << "wheelEvent";
if (event->delta() > 0)
{
zoom = 1.1;
}
else
{
zoom = 0.9;
}
update();
}
用鼠标事件控制 ,最后在一个 函数内统一进行状态机的变换,包括平移旋转。
接着做平移旋转,这个和缩放实现原理相似,鼠标左键拖动时进行平移,右键拖动时进行旋转。
void Widget::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << "mouseMoveEvent";
if (last_globalPos == QPoint(-1, -1))
{
// qDebug() << "last_globalPos";
last_globalPos = event->globalPos();
}
if (event->buttons() == Qt::LeftButton)
{
move = event->globalPos() - last_globalPos;
}
else
{
angle_x = (event->globalX() - last_globalPos.x());
angle_y = -(event->globalY() - last_globalPos.y());
// qDebug() << angleX << angleY;
}
last_globalPos = event->globalPos();
update();
}
这里我用 记录上一次响应时鼠标的位置,默认为 ,所以又用了鼠标释放的事件来进行重置一些关键信息。
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
qDebug() << "mouseReleaseEvent";
zoom = 1;
move = QPoint(0, 0);
last_globalPos = QPoint(-1, -1);
angle_x = angle_y = 0;
update();
}
最后都在 里修改状态机,然后通过 函数进行绘制,不过此时遇见了最大的问题,那就是在平移时,由于视图放大比例不一样,视图的平移和鼠标的平移无法同步,这里就要根据视图的放大比例来进行调参了,这里需要记录目前视图的放大比例,我这里给他乘以了一个 的参数,使其同步了,这里的 是反复修改取的一个比较适合的值,当我将视图放大三十倍时,鼠标和视图的平移基本一致,低于三十时,鼠标移动的幅度大于视图,大于三十时,恰好相反,所以最后除以 视图的放大倍数来调节一下。
当然到这里问题并没有处理完,因为当视图旋转后,在进行平移时,发现视图平移的方向和鼠标平移的方向并不同,后来网上查到说在视图旋转后,相当于坐标系也旋转了,想要实现鼠标平移旋转和视图平移旋转的组合操作的一致,那就需要将平移的向量也进行相应的旋转,视图旋转多少弧度,平移的向量也需要旋转多少弧度。于是我推算了一下公式,对向量进行了改变后,才大功告成。
void Widget::changeViewpoint()
{
qDebug() << "changeViewpoint";
// glMatrixMode(GL_MODELVIEW);
// glRotated(10 / 360, 0.0f, 0.0f, 1.0f);
glScaled(zoom, zoom, zoom);
zoom_amount *= zoom;
zoom = 1;
// qDebug() << move.x() << -move.y();
qDebug() << angle_amount << std::cos(angle_amount / 180 * pi);
GLdouble angle_cos = std::cos(angle_amount / 180 * pi);
GLdouble angle_sin = std::sin(angle_amount / 180 * pi);
GLdouble coefficient = move_coefficient / zoom_amount;
GLdouble delta_x = (move.x() * angle_cos + move.y() * angle_sin) * coefficient;
GLdouble delta_y = -(-move.x() * angle_sin + move.y() * angle_cos) * coefficient;
glTranslated(delta_x,
delta_y,
0.0);
move = QPoint(0, 0);
glRotated((angle_x + angle_y) / 2, 0, 0, 1);
angle_amount -= (angle_x + angle_y) / 2;
angle_amount += round_angle;
angle_amount = fmod(angle_amount, round_angle);
// glRotated(angleY, 0, 1, 0);
angle_x = angle_y = 0;
qDebug() << zoom_amount << angle_amount;
}
这里并没有实现 中的旋转方式,这里通过 轴旋转视图,但是想要实现更多轴的旋转,感觉处理起来还是挺麻烦的,如果想要效果更加接近于 中的效果,可能不能通过旋转视图,而应该通过改变相机的位置。一开始并没有想到这么多,同组的大佬告诉我让我先实现按照 轴旋转,其他的具体需要了再改,然后我就傻乎乎的旋转了视图……如果一开始就尝试改变相机的位置,可能下一步修改代码就没有那么麻烦了。
这是最后通过缩放旋转平移后的效果,看着还挺像回事儿,现在看来这个代码写的十分简单,但是一开始真的无从下手……新手入坑难。
最后贴一下 函数:
void Widget::paintGL()
{
qDebug() << "paintGL";
changeViewpoint();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
if (!pointcloud->points.empty())
{
qreal r, g, b, a;
QColor color;
float upper = 4, lower = -4, range = upper - lower;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glBegin(GL_POINTS);
for (uint32_t i = 0; i < pointcloud->points.size(); ++i)
{
float z = pointcloud->points[i].z;
if (z < upper && z > lower)
{
float percent = (z - lower) / range;
int index = int(percent * colormap.size());
color = colormap.at(index);
if (percent > 0.5)
color.setAlphaF(0.3);
}
else
continue;
color.getRgbF(&r, &g, &b, &a);
glColor4f(r, g, b, a);
glVertex3f(pointcloud->points[i].x,
pointcloud->points[i].y,
pointcloud->points[i].z);
}
glEnd();
}
}
其他的一些细碎的东西就不贴了吧……还是太菜了,这么简单的功能折腾了好几天。