feat: 添加点云着色按钮 适配调整后的下位机图像采集方式
This commit is contained in:
@@ -9,14 +9,19 @@ PointCloudGLWidget::PointCloudGLWidget(QWidget *parent)
|
||||
, m_vertexBuffer(nullptr)
|
||||
, m_vao(nullptr)
|
||||
, m_pointCount(0)
|
||||
, m_fixedCenter(0.0f, 0.0f, 0.0f)
|
||||
, m_centerInitialized(false)
|
||||
, m_orthoSize(2000.0f) // 正交投影视野大小
|
||||
, m_minZ(0.0f)
|
||||
, m_maxZ(1000.0f)
|
||||
, m_fov(60.0f) // 透视投影视场角
|
||||
, m_rotationX(0.0f) // 从正面看(0度)
|
||||
, m_rotationY(0.0f) // 不旋转Y轴
|
||||
, m_translation(0.0f, 0.0f, 0.0f)
|
||||
, m_cloudCenter(0.0f, 0.0f, 0.0f)
|
||||
, m_viewDistance(1000.0f)
|
||||
, m_panOffset(0.0f, 0.0f, 0.0f)
|
||||
, m_zoom(1.0f) // 缩放因子
|
||||
, m_leftButtonPressed(false)
|
||||
, m_rightButtonPressed(false)
|
||||
, m_firstFrame(true)
|
||||
, m_colorMode(0) // 默认黑白模式
|
||||
{
|
||||
setMinimumSize(400, 400);
|
||||
}
|
||||
@@ -42,7 +47,7 @@ void PointCloudGLWidget::initializeGL()
|
||||
{
|
||||
initializeOpenGLFunctions();
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glClearColor(0.1f, 0.1f, 0.15f, 1.0f); // 深灰色背景
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
|
||||
@@ -67,18 +72,39 @@ void PointCloudGLWidget::setupShaders()
|
||||
#version 330 core
|
||||
layout(location = 0) in vec3 position;
|
||||
uniform mat4 mvp;
|
||||
uniform float minZ;
|
||||
uniform float maxZ;
|
||||
out float depth;
|
||||
void main() {
|
||||
gl_Position = mvp * vec4(position, 1.0);
|
||||
gl_PointSize = 1.0; // 减小点的大小
|
||||
gl_PointSize = 1.0;
|
||||
depth = (position.z - minZ) / (maxZ - minZ);
|
||||
}
|
||||
)";
|
||||
|
||||
// 片段着色器
|
||||
// 片段着色器 - 支持黑白和彩色两种模式
|
||||
const char *fragmentShaderSource = R"(
|
||||
#version 330 core
|
||||
in float depth;
|
||||
uniform int colorMode;
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
float d = clamp(depth, 0.0, 1.0);
|
||||
if (colorMode == 0) {
|
||||
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
} else {
|
||||
vec3 color;
|
||||
if (d < 0.25) {
|
||||
color = mix(vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 1.0), d * 4.0);
|
||||
} else if (d < 0.5) {
|
||||
color = mix(vec3(0.0, 1.0, 1.0), vec3(0.0, 1.0, 0.0), (d - 0.25) * 4.0);
|
||||
} else if (d < 0.75) {
|
||||
color = mix(vec3(0.0, 1.0, 0.0), vec3(1.0, 1.0, 0.0), (d - 0.5) * 4.0);
|
||||
} else {
|
||||
color = mix(vec3(1.0, 1.0, 0.0), vec3(1.0, 0.0, 0.0), (d - 0.75) * 4.0);
|
||||
}
|
||||
fragColor = vec4(color, 1.0);
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
@@ -99,11 +125,9 @@ void PointCloudGLWidget::resizeGL(int w, int h)
|
||||
{
|
||||
m_projection.setToIdentity();
|
||||
|
||||
// 使用正交投影代替透视投影,避免"喷射状"效果
|
||||
// 使用透视投影,从相机原点看向Z轴正方向
|
||||
float aspect = float(w) / float(h);
|
||||
m_projection.ortho(-m_orthoSize * aspect, m_orthoSize * aspect,
|
||||
-m_orthoSize, m_orthoSize,
|
||||
-50000.0f, 50000.0f); // 近平面和远平面
|
||||
m_projection.perspective(m_fov, aspect, 1.0f, 50000.0f);
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::paintGL()
|
||||
@@ -114,18 +138,22 @@ void PointCloudGLWidget::paintGL()
|
||||
return;
|
||||
}
|
||||
|
||||
// 每帧重新计算正交投影矩阵(确保使用最新的m_orthoSize)
|
||||
// 重新计算透视投影矩阵
|
||||
m_projection.setToIdentity();
|
||||
float aspect = float(width()) / float(height());
|
||||
m_projection.ortho(-m_orthoSize * aspect, m_orthoSize * aspect,
|
||||
-m_orthoSize, m_orthoSize,
|
||||
-50000.0f, 50000.0f);
|
||||
m_projection.perspective(m_fov / m_zoom, aspect, 1.0f, 50000.0f);
|
||||
|
||||
// 设置view矩阵
|
||||
// 设置view矩阵 - 轨道相机模式(围绕点云中心旋转)
|
||||
m_view.setToIdentity();
|
||||
// 1. 用户平移偏移
|
||||
m_view.translate(m_panOffset);
|
||||
// 2. 相机后退到观察距离
|
||||
m_view.translate(0.0f, 0.0f, -m_viewDistance);
|
||||
// 3. 应用旋转(围绕原点,即点云中心)
|
||||
m_view.rotate(m_rotationX, 1.0f, 0.0f, 0.0f);
|
||||
m_view.rotate(m_rotationY, 0.0f, 1.0f, 0.0f);
|
||||
m_view.translate(m_translation);
|
||||
// 4. 将点云中心移到原点
|
||||
m_view.translate(-m_cloudCenter);
|
||||
|
||||
// 设置model矩阵
|
||||
m_model.setToIdentity();
|
||||
@@ -136,6 +164,9 @@ void PointCloudGLWidget::paintGL()
|
||||
// 绑定shader和设置uniform
|
||||
m_program->bind();
|
||||
m_program->setUniformValue("mvp", mvp);
|
||||
m_program->setUniformValue("minZ", m_minZ);
|
||||
m_program->setUniformValue("maxZ", m_maxZ);
|
||||
m_program->setUniformValue("colorMode", m_colorMode);
|
||||
|
||||
// 绑定VAO和绘制
|
||||
m_vao->bind();
|
||||
@@ -166,10 +197,10 @@ void PointCloudGLWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
m_rotationY += delta.x() * 0.5f;
|
||||
update();
|
||||
} else if (m_rightButtonPressed) {
|
||||
// 右键:平移(根据正交投影视野大小调整平移速度)
|
||||
float scale = m_orthoSize * 0.002f;
|
||||
m_translation.setX(m_translation.x() + delta.x() * scale);
|
||||
m_translation.setY(m_translation.y() - delta.y() * scale);
|
||||
// 右键:平移(根据观察距离调整平移速度)
|
||||
float scale = m_viewDistance * 0.002f;
|
||||
m_panOffset.setX(m_panOffset.x() + delta.x() * scale);
|
||||
m_panOffset.setY(m_panOffset.y() - delta.y() * scale);
|
||||
update();
|
||||
}
|
||||
}
|
||||
@@ -185,12 +216,12 @@ void PointCloudGLWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
|
||||
void PointCloudGLWidget::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
// 滚轮:缩放(调整正交投影视野大小)
|
||||
// 滚轮:缩放(调整zoom因子)
|
||||
float delta = event->angleDelta().y() / 120.0f;
|
||||
m_orthoSize *= (1.0f - delta * 0.1f);
|
||||
m_orthoSize = qMax(100.0f, qMin(m_orthoSize, 10000.0f)); // 范围:100-10000
|
||||
m_zoom *= (1.0f + delta * 0.1f);
|
||||
m_zoom = qMax(0.1f, qMin(m_zoom, 10.0f)); // 范围:0.1-10倍
|
||||
|
||||
update(); // 触发重绘,paintGL会使用新的m_orthoSize
|
||||
update();
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::updatePointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
|
||||
@@ -199,8 +230,9 @@ void PointCloudGLWidget::updatePointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cl
|
||||
return;
|
||||
}
|
||||
|
||||
// 过滤全零点并转换为顶点数组
|
||||
// 过滤全零点并转换为顶点数组,同时计算包围盒
|
||||
m_vertices.clear();
|
||||
|
||||
float minX = FLT_MAX, maxX = -FLT_MAX;
|
||||
float minY = FLT_MAX, maxY = -FLT_MAX;
|
||||
float minZ = FLT_MAX, maxZ = -FLT_MAX;
|
||||
@@ -211,7 +243,7 @@ void PointCloudGLWidget::updatePointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cl
|
||||
m_vertices.push_back(point.y);
|
||||
m_vertices.push_back(point.z);
|
||||
|
||||
// 统计坐标范围
|
||||
// 更新包围盒
|
||||
if (point.x < minX) minX = point.x;
|
||||
if (point.x > maxX) maxX = point.x;
|
||||
if (point.y < minY) minY = point.y;
|
||||
@@ -223,37 +255,43 @@ void PointCloudGLWidget::updatePointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cl
|
||||
|
||||
m_pointCount = m_vertices.size() / 3;
|
||||
|
||||
// 计算点云中心并进行中心化处理
|
||||
// 保存深度范围用于着色
|
||||
if (m_pointCount > 0) {
|
||||
m_minZ = minZ;
|
||||
m_maxZ = maxZ;
|
||||
}
|
||||
|
||||
// 只在首帧时自动调整相机位置,之后保持用户交互状态
|
||||
if (m_pointCount > 0 && m_firstFrame) {
|
||||
// 计算点云中心
|
||||
float centerX = (minX + maxX) / 2.0f;
|
||||
float centerY = (minY + maxY) / 2.0f;
|
||||
float centerZ = (minZ + maxZ) / 2.0f;
|
||||
|
||||
// 第一帧:初始化固定中心点
|
||||
if (!m_centerInitialized) {
|
||||
m_fixedCenter = QVector3D(centerX, centerY, centerZ);
|
||||
m_centerInitialized = true;
|
||||
qDebug() << "[PointCloudGLWidget] Fixed center initialized:" << m_fixedCenter;
|
||||
}
|
||||
// 计算点云尺寸
|
||||
float depthRange = maxZ - minZ;
|
||||
float sizeX = maxX - minX;
|
||||
float sizeY = maxY - minY;
|
||||
float maxSize = std::max({sizeX, sizeY, depthRange});
|
||||
|
||||
// 使用固定的中心点进行中心化(避免抖动)
|
||||
for (size_t i = 0; i < m_vertices.size(); i += 3) {
|
||||
m_vertices[i] -= m_fixedCenter.x(); // X坐标
|
||||
m_vertices[i + 1] -= m_fixedCenter.y(); // Y坐标
|
||||
m_vertices[i + 2] -= m_fixedCenter.z(); // Z坐标
|
||||
}
|
||||
}
|
||||
// 设置点云中心
|
||||
m_cloudCenter = QVector3D(centerX, centerY, centerZ);
|
||||
|
||||
// 添加调试日志
|
||||
static int updateCount = 0;
|
||||
if (updateCount < 3 || updateCount % 100 == 0) {
|
||||
// qDebug() << "[PointCloudGLWidget] Update" << updateCount << "- Points:" << m_pointCount
|
||||
// << "Total cloud size:" << cloud->size();
|
||||
// qDebug() << " X range:" << minX << "to" << maxX;
|
||||
// qDebug() << " Y range:" << minY << "to" << maxY;
|
||||
// qDebug() << " Z range:" << minZ << "to" << maxZ;
|
||||
// 计算观察距离,让相机从外部观察点云
|
||||
m_viewDistance = maxSize * 1.5f;
|
||||
|
||||
// 重置平移偏移和旋转角度
|
||||
m_panOffset = QVector3D(0.0f, 0.0f, 0.0f);
|
||||
m_rotationX = 0.0f;
|
||||
m_rotationY = 0.0f;
|
||||
|
||||
// 设置缩放
|
||||
m_zoom = 1.0f;
|
||||
|
||||
qDebug() << "[PointCloudGLWidget] 首帧自动居中 - 点云中心:" << centerX << centerY << centerZ
|
||||
<< "观察距离:" << m_viewDistance;
|
||||
m_firstFrame = false; // 标记首帧已处理
|
||||
}
|
||||
updateCount++;
|
||||
|
||||
updateBuffers();
|
||||
update();
|
||||
|
||||
Reference in New Issue
Block a user