QT点云显示--基于QOpenGLWidget和QOpenGLFunctions实现

news2024/11/24 9:27:46

一、实现功能

1、网格显示

2、坐标轴显示

3、鼠标操作旋转、平移、缩放

4、点云显示

之前写了一篇基于QGLWidget实现,此版本的功能接口基本保持一致,方便对比

QT点云显示--基于QGLWidget实现_Jason~shen的博客-CSDN博客1、网格显示2、坐标轴显示3、鼠标操作旋转、平移、缩放4、点云显示。https://blog.csdn.net/qq_40602000/article/details/128293336?spm=1001.2014.3001.5501

QGLWidget与QOpenGLWidget的区别:

1、QGLWidget中是直接调用opengl指令,个人觉得比较方便,逻辑清晰,可以了解opengl底层的接口;

2、QOpenGLWidget是调用QOpenGLFunctions中封装接口,从Qt5.4开始,Qt推荐使用QOpenGLWidget和QOpenGL类。

二、实现效果

 

 

 

三、实现方法

细节待补充

完整代码

PointCloudOpenGLWidget.h
#ifndef BASEOPENGLWIDGET_H
#define BASEOPENGLWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QMouseEvent>

#include "opengllib_global.h"

class OPENGLLIBSHARED_EXPORT PointCloudOpenGLWidget: public QOpenGLWidget, public QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    PointCloudOpenGLWidget(QWidget *parent = 0);
    ~PointCloudOpenGLWidget();
    void updatePoints(const QVector<QVector3D> &points);
    void loadCsvFile(const QString &path);

protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int width, int height) override;

    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void wheelEvent(QWheelEvent *event);

    virtual unsigned int drawMeshline(float size, int count);
    virtual void drawCooraxis(float length);
    virtual unsigned int drawPointdata(std::vector<float> &pointVertexs);

protected:
    QOpenGLShaderProgram m_shaderProgramMesh;
    QOpenGLShaderProgram m_shaderProgramAxis;
    QOpenGLShaderProgram m_shaderProgramPoint;

    unsigned int m_VBO_MeshLine;
    unsigned int m_VAO_MeshLine;

    unsigned int m_VBO_Axis;
    unsigned int m_VAO_Axis;

    unsigned int m_VBO_Point;
    unsigned int m_VAO_Point;

    std::vector<float> m_pointData;
    unsigned int m_pointCount;

    unsigned int m_vertexCount;

    float m_xRotate;
    float m_zRotate;
    float m_xTrans;
    float m_yTrans;
    float m_zoom;

    QPoint   lastPos;
};
PointCloudOpenGLWidget.cpp
#include "PointCloudOpenGLWidget.h"
#include <QDebug>

PointCloudOpenGLWidget::PointCloudOpenGLWidget(QWidget *parent)
    : QOpenGLWidget(parent)
{
    m_xRotate = -30.0;
    m_zRotate = 100.0;
    m_xTrans = 0.0;
    m_yTrans = 0.0;
    m_zoom = 45.0;
}

PointCloudOpenGLWidget::~PointCloudOpenGLWidget()
{
    makeCurrent();
    glDeleteBuffers(1, &m_VBO_MeshLine);
    glDeleteVertexArrays(1, &m_VAO_MeshLine);

    glDeleteBuffers(1, &m_VBO_Axis);
    glDeleteVertexArrays(1, &m_VAO_Axis);

    glDeleteBuffers(1, &m_VBO_Point);
    glDeleteVertexArrays(1, &m_VAO_Point);

    m_shaderProgramMesh.release();
    m_shaderProgramAxis.release();
    m_shaderProgramPoint.release();

    doneCurrent();
    qDebug() << __FUNCTION__;
}

void PointCloudOpenGLWidget::updatePoints(const QVector<QVector3D> &points)
{
    m_pointData.clear();
    for(auto vector3D : points)
    {
        m_pointData.push_back(vector3D.x());
        m_pointData.push_back(vector3D.y());
        m_pointData.push_back(vector3D.z());
        m_pointData.push_back(1);
    }
}

void PointCloudOpenGLWidget::loadCsvFile(const QString &path)
{
    m_pointData.clear();
    QFile inFile(path);
    if (inFile.open(QIODevice::ReadOnly))
    {
        QTextStream stream_text(&inFile);
        while (!stream_text.atEnd())
        {
            QString line = stream_text.readLine();
            QStringList strSplit = line.split(",");

            double x = strSplit.value(0).toDouble();
            double y = strSplit.value(1).toDouble();
            double z = strSplit.value(2).toDouble();
            m_pointData.push_back(x);
            m_pointData.push_back(y);
            m_pointData.push_back(z);
            m_pointData.push_back(1);
        }
        inFile.close();
    }
}

void PointCloudOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();

    // enable depth_test
    glEnable(GL_DEPTH_TEST);

    // link meshline shaders   vs文件为顶点着色器  fs为片段着色器
    m_shaderProgramMesh.addShaderFromSourceFile(QOpenGLShader::Vertex,
            ":/opengl/shader/shader_mesh.vs");
    m_shaderProgramMesh.addShaderFromSourceFile(QOpenGLShader::Fragment,
            ":/opengl/shader/shader_mesh.fs");
    m_shaderProgramMesh.link();

    // link coordinate axis shaders
    m_shaderProgramAxis.addShaderFromSourceFile(QOpenGLShader::Vertex,
            ":/opengl/shader/shader_axis.vs");
    m_shaderProgramAxis.addShaderFromSourceFile(QOpenGLShader::Fragment,
            ":/opengl/shader/shader_axis.fs");
    m_shaderProgramAxis.link();

    // link pointcloud shaders
    m_shaderProgramPoint.addShaderFromSourceFile(QOpenGLShader::Vertex,
            ":/opengl/shader/shader_point.vs");
    m_shaderProgramPoint.addShaderFromSourceFile(QOpenGLShader::Fragment,
            ":/opengl/shader/shader_point.fs");
    m_shaderProgramPoint.link();

    m_vertexCount = drawMeshline(2.0, 16);
    m_pointCount = drawPointdata(m_pointData);
    qDebug() << "point_count" << m_pointCount;
    drawCooraxis(4.0);
}

void PointCloudOpenGLWidget::paintGL()
{
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    /*
       为了将坐标从一个坐标系转换到另一个坐标系,需要用到几个转换矩阵,
       分别是模型(Model)、视图(View)、投影(Projection)三个矩阵。
    */
    QMatrix4x4 projection, view, model;
    //透视矩阵变换
    projection.perspective(m_zoom, (float)width() / (float)height(), 1.0f, 100.0f);

    // eye:摄像机位置  center:摄像机看的点位 up:摄像机上方的朝向
    view.lookAt(QVector3D(0.0, 0.0, 50.0), QVector3D(0.0, 0.0, 1.0), QVector3D(0.0, 1.0, 0.0));

    model.translate(m_xTrans, m_yTrans, 0.0);
    model.rotate(m_xRotate, 1.0, 0.0, 0.0);
    model.rotate(m_zRotate, 0.0, 0.0, 1.0);

    m_shaderProgramMesh.bind();
    m_shaderProgramMesh.setUniformValue("projection", projection);
    m_shaderProgramMesh.setUniformValue("view", view);
    m_shaderProgramMesh.setUniformValue("model", model);

    m_shaderProgramAxis.bind();
    m_shaderProgramAxis.setUniformValue("projection", projection);
    m_shaderProgramAxis.setUniformValue("view", view);
    m_shaderProgramAxis.setUniformValue("model", model);

    m_shaderProgramPoint.bind();
    m_shaderProgramPoint.setUniformValue("projection", projection);
    m_shaderProgramPoint.setUniformValue("view", view);
    m_shaderProgramPoint.setUniformValue("model", model);

    //画网格
    m_shaderProgramMesh.bind();
    glBindVertexArray(m_VAO_MeshLine);
    glLineWidth(1.0f);
    glDrawArrays(GL_LINES, 0, m_vertexCount);

    //画坐标轴
    m_shaderProgramAxis.bind();
    glBindVertexArray(m_VAO_Axis);
    glLineWidth(5.0f);
    glDrawArrays(GL_LINES, 0, 6);

    //画点云
    m_shaderProgramPoint.bind();
    glBindVertexArray(m_VAO_Point);
    glPointSize(1.0f);
    glDrawArrays(GL_POINTS, 0, m_pointCount);
}

void PointCloudOpenGLWidget::resizeGL(int width, int height)
{
    glViewport(0, 0, width, height);
}

void PointCloudOpenGLWidget::mousePressEvent(QMouseEvent *event)
{
    lastPos = event->pos();
}

void PointCloudOpenGLWidget::mouseMoveEvent(QMouseEvent *event)
{
    int dx = event->pos().x() - lastPos.x();
    int dy = event->pos().y() - lastPos.y();
    if (event->buttons() & Qt::LeftButton)
    {
        m_xRotate = m_xRotate + 0.3 * dy;
        m_zRotate = m_zRotate + 0.3 * dx;

        if (m_xRotate > 30.0f)
        {
            m_xRotate = 30.0f;
        }
        if (m_xRotate < -120.0f)
        {
            m_xRotate = -120.0f;
        }
        update();
    }
    else if (event->buttons() & Qt::MidButton)
    {
        m_xTrans = m_xTrans + 0.1 * dx;
        m_yTrans = m_yTrans - 0.1 * dy;
        update();
    }
    lastPos = event->pos();
}

void PointCloudOpenGLWidget::wheelEvent(QWheelEvent *event)
{
    auto scroll_offest = event->angleDelta().y() / 120;
    m_zoom = m_zoom - (float)scroll_offest;

    if (m_zoom < 1.0f)    /* 放大限制 */
    {
        m_zoom = 1.0f;
    }

    if (m_zoom > 80.0f)
    {
        m_zoom = 80.0f;
    }

    update();
}

unsigned int PointCloudOpenGLWidget::drawMeshline(float size, int count)
{
    std::vector<float> mesh_vertexs;
    unsigned int vertex_count = 0;

    float start = count * (size / 2);
    float posX = start, posZ = start;

    for (int i = 0; i <= count; ++i)
    {
        mesh_vertexs.push_back(posX);
        mesh_vertexs.push_back(start);
        mesh_vertexs.push_back(0);

        mesh_vertexs.push_back(posX);
        mesh_vertexs.push_back(-start);
        mesh_vertexs.push_back(0);

        mesh_vertexs.push_back(start);
        mesh_vertexs.push_back(posZ);
        mesh_vertexs.push_back(0);

        mesh_vertexs.push_back(-start);
        mesh_vertexs.push_back(posZ);
        mesh_vertexs.push_back(0);

        posX = posX - size;
        posZ = posZ - size;
    }

    glGenVertexArrays(1, &m_VAO_MeshLine);
    glGenBuffers(1, &m_VBO_MeshLine);

    glBindVertexArray(m_VAO_MeshLine);

    glBindBuffer(GL_ARRAY_BUFFER, m_VBO_MeshLine);

    glBufferData(GL_ARRAY_BUFFER, mesh_vertexs.size() * sizeof(float), &mesh_vertexs[0], GL_STATIC_DRAW);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);

    vertex_count = (int)mesh_vertexs.size() / 3;

    return vertex_count;
}

void PointCloudOpenGLWidget::drawCooraxis(float length)
{
    std::vector<float> axis_vertexs =
    {
        //x,y ,z ,r, g, b
        0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
        length, 0.0, 0.0, 1.0, 0.0, 0.0,
        0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
        0.0, length, 0.0, 0.0, 1.0, 0.0,
        0.0, 0.0, 0.0, 0.0, 0.0, 1.0,
        0.0, 0.0, length, 0.0, 0.0, 1.0,
    };

    glGenVertexArrays(1, &m_VAO_Axis);
    glGenBuffers(1, &m_VBO_Axis);

    glBindVertexArray(m_VAO_Axis);

    glBindBuffer(GL_ARRAY_BUFFER, m_VBO_Axis);
    glBufferData(GL_ARRAY_BUFFER, axis_vertexs.size() * sizeof(float), &axis_vertexs[0], GL_STATIC_DRAW);

    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(0);

    // 颜色属性
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);
}

unsigned int PointCloudOpenGLWidget::drawPointdata(std::vector<float> &pointVertexs)
{
    unsigned int point_count = 0;

    glGenVertexArrays(1, &m_VAO_Point);
    glGenBuffers(1, &m_VBO_Point);

    glBindVertexArray(m_VAO_Point);

    glBindBuffer(GL_ARRAY_BUFFER, m_VBO_Point);
    glBufferData(GL_ARRAY_BUFFER, pointVertexs.size() * sizeof(float), &pointVertexs[0], GL_STATIC_DRAW);

    // 位置属性
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
    glEnableVertexAttribArray(0);

// 颜色属性
    glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glBindVertexArray(0);

    point_count = (unsigned int)pointVertexs.size() / 4;

    return point_count;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/86999.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作系统学习笔记_2 中断和系统调用;进程和线程

中断 一开始的计算机只是简单的串行执行程序。 现在的操作系统不仅可以并发执行程序&#xff0c;而且收到中断指令时&#xff0c;CPU 会切换到内核模式&#xff0c;中断当前程序的执行&#xff0c;按中断指令调整程序执行顺序&#xff0c;然后恢复到用户态继续执行。 中断分…

docker容器安装与使用

目录 1. 什么是docker 2. docker的核心组件 3. docker的安装 3.1 安装的先决条件 3.2.1 ubuntu安装docker 3.2.2 CentOS安装docker 3.3 配置镜像加速器 4. 镜像常用操作 4.1 搜索镜像 4.3 查看宿主机中的镜像 4.3 删除镜像 5. 容器常用命令 5.1 运行容器 5.2 使用…

【算法】斐波那契数列通项公式

特征方程和通项公式 如果数列ana_nan​的递推公式&#xff1a;anc1an−1c2an−2a_nc_1a_{n-1}c_2a_{n-2}an​c1​an−1​c2​an−2​------(1) 根据待定系数法&#xff0c;假设an−xan−1y(an−1−xan−2)a_n-xa_{n-1}y(a_{n-1}-xa_{n-2})an​−xan−1​y(an−1​−xan−2​)…

Mybatis源码解析之执行SQL语句

作者&#xff1a;郑志杰 mybatis 操作数据库的过程 // 第一步&#xff1a;读取mybatis-config.xml配置文件 InputStream inputStream Resources.getResourceAsStream("mybatis-config.xml"); // 第二步&#xff1a;构建SqlSessionFactory(框架初始化) SqlSessionF…

FITC-PEG-Biotin,Biotin-PEG-Fluorescein,荧光素PEG生物素生物标记物用试剂

一&#xff1a;产品描述 1、名称 英文&#xff1a;FITC-PEG-Biotin&#xff0c;Biotin-PEG-Fluorescein 中文&#xff1a;荧光素-聚乙二醇-生物素 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a;Biotin PEG Fluorescent PEG 4、分子量&#xff1a;可定制&#xff0c…

MyBatis访问Db2和MySQL(Maven)

注&#xff1a;虽然前面写过一些文档&#xff0c;包含MyBatis连接Db2和MySQL的内容&#xff0c;但是貌似没有单独记录用Maven方式连接DB的文档&#xff0c;所以单写了这一篇文档&#xff0c;方便以后需要快速搭建MyBatis环境时参考。 注&#xff1a;有一篇文档“MyBatis访问Db…

基于java+springboot+mybatis+vue+mysql的摄影跟拍预定管理系统

项目介绍 摄影跟拍预定管理方面的任务繁琐,以至于每年都在摄影跟拍预定管理这方面投入较多的精力却效果甚微,摄影跟拍预定管理系统的目标就是为了能够缓解摄影跟拍预定管理工作方面面临的压力,让摄影跟拍预定管理方面的工作变得更加高效准确。 本项目在开发和设计过程中涉及到…

MyBaits入门完结篇

不仅可以判断参数&#xff0c;还可以判断_parameter和_databasedId bind标签 sql标签配合include标签完成对重复sql语句的抽取 要在带注解的映射器接口类中使用动态 SQL&#xff0c;可以使用 script 元素 缓存 一级缓存 一级缓存失效情况 手动清空缓冲的函数&#xff1a…

【众筹】百问网DShanMCU-Mio开源掌机(爻-澪)项目,完美支持运行10多个模拟器!

众筹说明 定金翻倍&#xff0c;即定金19.9元&#xff0c;在付尾款时可抵40元(成品售价不会超过120元)&#xff01;达标当天就开搞&#xff0c;满100人加速搞尽量在年前发货&#xff0c;让大家先玩起来&#xff01;如果不达标则原路退款&#xff0c;项目取消。 众筹时间&#…

ADI Blackfin DSP处理器-BF533的开发详解44:图像处理专题-StenciFilter (图像的平滑处理)(含源码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 功能介绍 代码实现了图像的平滑处理&#xff08;高斯模板&#xff09;&#xff0c;代码运行时&#xff0c;会通过文件系统打开工程文件根目下&qu…

NetCore基于Roslyn的动态编译实现

目录 一. AvalonEdit文本器 1.功能实现 2. 高亮 3. 代码提示 二. 运行效果展示 三. 源码链接 四. 参考资料 一. AvalonEdit文本器 1.功能实现 直接用Github上的源码进行实现&#xff0c;icsharpcode/AvalonEdit&#xff1a;The WPF-based text editor component used i…

在R语言中使用概率分布:dnorm,pnorm,qnorm和rnorm

在这里&#xff0c;我将讨论哪些函数可用于处理正态分布&#xff1a;dnorm&#xff0c;pnorm&#xff0c;qnorm和rnorm。 R中的分布函数 有四个关联的函数&#xff0c; 四个正态分布函数是&#xff1a; d范数&#xff1a;正态分布的密度函数p范数&#xff1a;正态分布的累积密…

【Spring】SpringBoot 配置 log4j2 日志

1. 概述 Apache Log4j2 是对原先的 Log4j 项目的升级版本&#xff0c;参考了 logback 的一些优秀的设计&#xff0c;并且修复了一些问题&#xff0c;因此带来了一些重大的提升。 2. 案例与解析 2.1 引入依赖 SpringBoot 的 starter 自带的是 logback 日志&#xff0c;若要使…

数据结构Data Structure和算法Algorithm导航目录(持续更新)

文章目录1. 大纲2. 算法基础3. 数据结构3.1 线性结构3.1.1 字符串3.1.2 线性表3.1.3 Hash表3.1.4 栈3.1.5 队列3.1.6 位图3.2 逻辑结构3.2.1 树3.2.1.1 二叉树3.2.1.2 动态查找树3.2.1.3 多路查找树3.2.2 图3.2.4 堆4. 算法4.1 排序4.2 查找5. 领域算法6. 优秀算法赏析1. 大纲 …

STM32F4 | 按键输入实验

文章目录一、STM32F4 IO 口简介二、硬件设计三、软件设计四、实验现象五、STM32CubeMX 配置 IO 口输出这一章&#xff0c;我们将通过 ALIENTEK阿波罗 STM32 开发板上载有的 4 个按钮&#xff08; KEY_UP、 KEY0、 KEY1 和 KEY2&#xff09;&#xff0c;来控制板上的 2 个 L…

成功的项目管理需要做好哪些方面?

每一个项目都代表了为公司建立同行竞争优势和提高利润的方式&#xff0c;成功交付的项目会将公司与那些竞争激烈的公司区分开来。而项目的成功取决于不同的因素。这也是项目经理所需要关注的问题&#xff0c;在每一个项目成功标准方面保持一致可以消除项目失败的风险&#xff0…

【数据库课程设计】SQLServer数据库课程设计(学生宿舍管理),课设报告+源码+数据库关系图

数据库课程设计——学生宿舍管理&#xff0c;需要全部源码可以关注私信我&#xff0c;把邮箱发在评论区前言一、课题背景和开发环境1、课题背景2、开发环境二、系统功能及示意图1、系统实现功能2、功能示意图2.1学生模块2.2管理人员模块三、概念结构设计1、管理员分配宿舍E_R图…

传染病模型3

一、研究方向 建立传染病的数学模型描述传染病的传播过程 分析感染人数的变化规律&#xff0c;预测传染病高峰的到来 探索控制、根除、预防传染病传播蔓延的手段 二、舱室 流行病学中的一大类模型&#xff0c;称为“舱室”模型&#xff0c;它是将人群分成若干个“舱室…

为什么机器码、汇编不可移植,而C语言可以移植?

1、机器码不可移植的原因 机器码&#xff08;二进制&#xff09;是处理器能直接识别的语言&#xff0c;不同的机器码代表不同的运算指令&#xff0c;处理器可以识别哪些机器码是由处理器的硬件设备决定的&#xff0c;不同的处理器机器码可能不同。 比如在ARM处理器上加法可能…

Linux 线程池

文章目录线程池的定义使用线程池的原因基于POSIX实现的线程池基于block队列的线程池实现基于ring队列的线程池实现设计单例模式线程池线程池的定义 线程池就一堆已经创建好的任务线程&#xff0c;初始它们都处于空闲等待状态&#xff0c;当有新的任务需要处理的时候&#xff0…