feat: v0.1.0更新
This commit is contained in:
259
src/gui/PointCloudGLWidget.cpp
Normal file
259
src/gui/PointCloudGLWidget.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
#include "gui/PointCloudGLWidget.h"
|
||||
#include <QDebug>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
|
||||
PointCloudGLWidget::PointCloudGLWidget(QWidget *parent)
|
||||
: QOpenGLWidget(parent)
|
||||
, m_program(nullptr)
|
||||
, m_vertexBuffer(nullptr)
|
||||
, m_vao(nullptr)
|
||||
, m_pointCount(0)
|
||||
, m_orthoSize(2000.0f) // 正交投影视野大小
|
||||
, m_rotationX(0.0f) // 从正面看(0度)
|
||||
, m_rotationY(0.0f) // 从正面看(0度)
|
||||
, m_translation(0.0f, 0.0f, 0.0f)
|
||||
, m_leftButtonPressed(false)
|
||||
, m_rightButtonPressed(false)
|
||||
{
|
||||
setMinimumSize(400, 400);
|
||||
}
|
||||
|
||||
PointCloudGLWidget::~PointCloudGLWidget()
|
||||
{
|
||||
makeCurrent();
|
||||
if (m_vao) {
|
||||
m_vao->destroy();
|
||||
delete m_vao;
|
||||
}
|
||||
if (m_vertexBuffer) {
|
||||
m_vertexBuffer->destroy();
|
||||
delete m_vertexBuffer;
|
||||
}
|
||||
if (m_program) {
|
||||
delete m_program;
|
||||
}
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::initializeGL()
|
||||
{
|
||||
initializeOpenGLFunctions();
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
|
||||
setupShaders();
|
||||
|
||||
// 创建VAO和VBO
|
||||
m_vao = new QOpenGLVertexArrayObject(this);
|
||||
m_vao->create();
|
||||
|
||||
m_vertexBuffer = new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
|
||||
m_vertexBuffer->create();
|
||||
|
||||
qDebug() << "[PointCloudGLWidget] OpenGL initialized";
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::setupShaders()
|
||||
{
|
||||
m_program = new QOpenGLShaderProgram(this);
|
||||
|
||||
// 顶点着色器
|
||||
const char *vertexShaderSource = R"(
|
||||
#version 330 core
|
||||
layout(location = 0) in vec3 position;
|
||||
uniform mat4 mvp;
|
||||
void main() {
|
||||
gl_Position = mvp * vec4(position, 1.0);
|
||||
gl_PointSize = 2.0;
|
||||
}
|
||||
)";
|
||||
|
||||
// 片段着色器
|
||||
const char *fragmentShaderSource = R"(
|
||||
#version 330 core
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
if (!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource)) {
|
||||
qDebug() << "[PointCloudGLWidget] Vertex shader error:" << m_program->log();
|
||||
}
|
||||
if (!m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource)) {
|
||||
qDebug() << "[PointCloudGLWidget] Fragment shader error:" << m_program->log();
|
||||
}
|
||||
if (!m_program->link()) {
|
||||
qDebug() << "[PointCloudGLWidget] Shader link error:" << m_program->log();
|
||||
} else {
|
||||
qDebug() << "[PointCloudGLWidget] Shaders compiled and linked successfully";
|
||||
}
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::resizeGL(int w, int h)
|
||||
{
|
||||
m_projection.setToIdentity();
|
||||
|
||||
// 使用正交投影代替透视投影,避免"喷射状"效果
|
||||
float aspect = float(w) / float(h);
|
||||
m_projection.ortho(-m_orthoSize * aspect, m_orthoSize * aspect,
|
||||
-m_orthoSize, m_orthoSize,
|
||||
-50000.0f, 50000.0f); // 近平面和远平面
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::paintGL()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
if (m_pointCount == 0 || !m_program) {
|
||||
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);
|
||||
|
||||
// 设置view矩阵
|
||||
m_view.setToIdentity();
|
||||
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);
|
||||
|
||||
// 设置model矩阵
|
||||
m_model.setToIdentity();
|
||||
|
||||
// 计算MVP矩阵
|
||||
QMatrix4x4 mvp = m_projection * m_view * m_model;
|
||||
|
||||
// 绑定shader和设置uniform
|
||||
m_program->bind();
|
||||
m_program->setUniformValue("mvp", mvp);
|
||||
|
||||
// 绑定VAO和绘制
|
||||
m_vao->bind();
|
||||
glDrawArrays(GL_POINTS, 0, m_pointCount);
|
||||
m_vao->release();
|
||||
|
||||
m_program->release();
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
m_lastMousePos = event->pos();
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
m_leftButtonPressed = true;
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
m_rightButtonPressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QPoint delta = event->pos() - m_lastMousePos;
|
||||
m_lastMousePos = event->pos();
|
||||
|
||||
if (m_leftButtonPressed) {
|
||||
// 左键:旋转
|
||||
m_rotationX += delta.y() * 0.5f;
|
||||
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);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
m_leftButtonPressed = false;
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
m_rightButtonPressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
// 滚轮:缩放(调整正交投影视野大小)
|
||||
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
|
||||
|
||||
update(); // 触发重绘,paintGL会使用新的m_orthoSize
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::updatePointCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
|
||||
{
|
||||
if (!cloud) {
|
||||
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;
|
||||
|
||||
for (const auto& point : cloud->points) {
|
||||
if (point.z > 0.01f) {
|
||||
m_vertices.push_back(point.x);
|
||||
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;
|
||||
if (point.y > maxY) maxY = point.y;
|
||||
if (point.z < minZ) minZ = point.z;
|
||||
if (point.z > maxZ) maxZ = point.z;
|
||||
}
|
||||
}
|
||||
|
||||
m_pointCount = m_vertices.size() / 3;
|
||||
|
||||
// 添加调试日志
|
||||
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;
|
||||
}
|
||||
updateCount++;
|
||||
|
||||
updateBuffers();
|
||||
update();
|
||||
}
|
||||
|
||||
void PointCloudGLWidget::updateBuffers()
|
||||
{
|
||||
if (m_vertices.empty() || !m_vao || !m_vertexBuffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
makeCurrent();
|
||||
|
||||
m_vao->bind();
|
||||
m_vertexBuffer->bind();
|
||||
m_vertexBuffer->allocate(m_vertices.data(), m_vertices.size() * sizeof(float));
|
||||
|
||||
// 设置顶点属性指针
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
|
||||
|
||||
m_vertexBuffer->release();
|
||||
m_vao->release();
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
Reference in New Issue
Block a user