QT点云控件

qpointcloudwidget.h

#ifndef QPOINTCLOUDWIDGET_H
#define QPOINTCLOUDWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions_4_5_Core>
#include <QVector3D>
class QPointCloudWidget :  public QOpenGLWidget,
        public QOpenGLFunctions_4_5_Core
{
    Q_OBJECT
public:
    QPointCloudWidget(QWidget *parent = nullptr);
    void setPoses(QVector<float> &poses);
protected:
    void initializeGL();
    void resizeGL(int width, int height);
    void paintGL();
protected:
    //1 鼠标及滚轮消息
    void wheelEvent(QWheelEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);

private:
    void shaderProgram();
    void getShaderSource(const char*, QString&);//从资源文件中读取两个着色器
    void bindShader();      //绑定着色器
    bool checkCompileErrors(GLuint shader, QString type);//检查编译错误
    void drawPointCloud(); // 绘制点云
    void drawAxis();       // 绘制坐标轴
    void translate_and_rotate();
    void axix_translate_and_rotate();
private:
    QString vShaderSource;       //顶点着色器
    QString fShaderSource;       //片段着色器
    GLuint  programID;           //着色器程序ID
    QString axisVShaderSource;       //顶点着色器
    QString axisFShaderSource;       //片段着色器
    GLuint  axisProgramID;           //着色器程序ID
    QVector<float> poses;        //点云数组
    QVector<float> lines;        //直线数组
    float yawAngle;//偏航角
    float rollAngle;//横滚角
    float pitchAngle;//俯仰角,鼠标右键控制
    float dx;
    float dy;
    float zoom;//缩放比例
    QVector3D translate_inc;      //表示平移量
    QPoint leftButtonClicked;//鼠标左键按下状态下的上一时刻坐标
    QPoint rightButtonClicked;//鼠标右键按下状态下的上一时刻坐标
    int m_iIsmouseclicked;//标识鼠标是否按下, 0表示松开状态, 1表示按下左键, 2表示按下右键
};

#endif // QPOINTCLOUDWIDGET_H

qpointcloudwidget.cpp

#include "qpointcloudwidget.h"
#include <QFile>
#include <QMatrix4x4>
#include <QMouseEvent>
#include <QDebug>

static const unsigned int SCR_WIDTH = 800;
static const unsigned int SCR_HEIGHT = 600;
static const float PI = 3.141593f;
// camera
static QVector3D cameraPos   = QVector3D(0.0f, 0.0f, 100.0f);
static QVector3D cameraFront = QVector3D(0.0f, 0.0f, 0.0f);
static QVector3D cameraUp    = QVector3D(0.0f, 1.0f, 0.0f);

QPointCloudWidget::QPointCloudWidget(QWidget *parent) : QOpenGLWidget(parent)
{
    for (int i = -100; i < 100; i++) {
        for (int j = -100; j < 100; j++) {
            for (int k = -100; k < 100; k++) {
                poses.append(i);
                poses.append(j) ;
                poses.append(k );
            }
        }
    }
    for (int i = 10; i < 100; i++) {
        for (int j = 0; j < 100; j++) {
            for (int k = 0; k < 100; k++) {
                poses.append((1000 + i) * 0.03f);
                poses.append((1000 + j) * 0.01f) ;
                poses.append(k * 0.01f);
            }
        }
    }
    lines.append(0.0f);
    lines.append(0.0f);
    lines.append(200.0f);

    lines.append(0.0f);
    lines.append(0.0f);
    lines.append(-200.0f);

    lines.append(200.0f);
    lines.append(0.0f);
    lines.append(0.0f);

    lines.append(-200.0f);
    lines.append(0.0f);
    lines.append(0.0f);

    lines.append(0.0f);
    lines.append(200.0f);
    lines.append(0.0f);

    lines.append(0.0f);
    lines.append(-200.0f);
    lines.append(0.0f);

    yawAngle = 0.0f;//偏航角
    rollAngle = 0.0f;//横滚角
    pitchAngle = 0.0f;//俯仰角,鼠标右键控制
    dx = dy = 0.0f;
    zoom = 1.0;
}

void  QPointCloudWidget::setPoses(QVector<float> &points)
{
    poses = points;
    update();
}

void QPointCloudWidget::initializeGL()
{
    // Initialize OpenGL Backend
    initializeOpenGLFunctions();

    // Set global information
    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);

    // 创建着色器对象
    shaderProgram();
}

void QPointCloudWidget::resizeGL(int width, int height)
{
    Q_UNUSED(width);
    Q_UNUSED(height);
}

void QPointCloudWidget::paintGL()
{
    //每次绘图前清理屏幕,否则会有残影
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
   // glClearColor(1.0f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    // 开启深度测试
    glEnable(GL_DEPTH_TEST);
    // 绘制点云
    drawAxis();
    drawPointCloud();
}

void QPointCloudWidget::wheelEvent(QWheelEvent *event)
{
    if(event->delta() > 0)
        zoom *= 1.05f;
    else
        zoom *= 0.95f;
    if(zoom < 0.002f)
        zoom = 0.002f;
    update();
}

void QPointCloudWidget::mousePressEvent(QMouseEvent *event)
{
    if(Qt::LeftButton == event->button()){
        m_iIsmouseclicked = 1;
        leftButtonClicked = event->pos();
    }
    if(Qt::RightButton == event->button()){
        rightButtonClicked = event->pos();
        m_iIsmouseclicked = 2;
    }
}

void QPointCloudWidget::mouseReleaseEvent(QMouseEvent *event)
{
    m_iIsmouseclicked = 0;
    update();
}

void QPointCloudWidget::mouseMoveEvent(QMouseEvent *event)
{
    if(1 == m_iIsmouseclicked){
        float x = event->pos().x() - leftButtonClicked.x();
        float y = event->pos().y() - leftButtonClicked.y();

        yawAngle += (PI * x / this->rect().width()) * 180;
        rollAngle  += (PI * y / this->rect().height()) * 180;

        leftButtonClicked = event->pos();
        update();
    }

    if(2 == m_iIsmouseclicked){
        float x = event->pos().x() - rightButtonClicked.x();
        float y = event->pos().y() - rightButtonClicked.y();
        if (qAbs(x) > 10) {
            if (x > 0)
                dx += 10.0;
            else
                dx -= 10.0;
        }
        if (qAbs(y) > 10) {
            if (y < 0 )
                dy += 3;
            else
                dy -= 3;
        }
#if 0
        if(x > 0)
            pitchAngle += (PI * x / this->rect().width()) * 180;
        if(x < 0)
            pitchAngle -= (PI * x / this->rect().width()) * 180;
#endif
        rightButtonClicked = event->pos();
        update();
    }
}


void QPointCloudWidget::shaderProgram()
{
    getShaderSource(":/pose.vert", vShaderSource);
    getShaderSource(":/pose.frag", fShaderSource);
    getShaderSource(":/axis.vert", axisVShaderSource);
    getShaderSource(":/axis.frag", axisFShaderSource);
    bindShader();
}

void QPointCloudWidget::getShaderSource(const char *path, QString &str)
{
    QFile file(path);
    file.open(QIODevice::ReadOnly);
    QTextStream in(&file);
    str = in.readAll();
    file.close();
}

void QPointCloudWidget::bindShader()
{
    const GLchar  *vertexShaderSource          = vShaderSource.toStdString().c_str();
    const GLchar  *fragmentShaderSource        = fShaderSource.toStdString().c_str();
    const GLchar  *axisVertexShaderSource      = axisVShaderSource.toStdString().c_str();
    const GLchar  *axisFragmentShaderSource    = axisFShaderSource.toStdString().c_str();

    GLuint vertex, fragment, axisVertex, axisFragment;
    // 顶点着色器
    vertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertex, 1, &vertexShaderSource, nullptr);
    glCompileShader(vertex);
    // 检查着色器编译错误
    checkCompileErrors(vertex, "VERTEX");

    // 片段着色器
    fragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragment, 1, &fragmentShaderSource, nullptr);
    glCompileShader(fragment);
    // 检查着色器编译错误
    checkCompileErrors(fragment, "FRAGMENT");

    // 顶点着色器
    axisVertex = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(axisVertex, 1, &axisVertexShaderSource, nullptr);
    glCompileShader(axisVertex);
    // 检查着色器编译错误
    checkCompileErrors(axisVertex, "VERTEX");

    // 片段着色器
    axisFragment = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(axisFragment, 1, &axisFragmentShaderSource, nullptr);
    glCompileShader(axisFragment);
    // 检查着色器编译错误
    checkCompileErrors(axisFragment, "FRAGMENT");

    // 着色器程序
    programID = glCreateProgram();
    glAttachShader(programID, vertex);
    glAttachShader(programID, fragment);
    glLinkProgram(programID);

    // 检查链接错误
    checkCompileErrors(programID, "PROGRAM");

    // 着色器程序
    axisProgramID = glCreateProgram();
    glAttachShader(axisProgramID, axisVertex);
    glAttachShader(axisProgramID, axisFragment);
    glLinkProgram(axisProgramID);

    // 检查链接错误
    checkCompileErrors(axisProgramID, "PROGRAM");

    // 删除着色器
    glDeleteShader(vertex);
    glDeleteShader(fragment);
    glDeleteShader(axisVertex);
    glDeleteShader(axisFragment);
}

bool QPointCloudWidget::checkCompileErrors(GLuint shader, QString type)
{
    int success;
    char infoLog[512];
    if (type != "PROGRAM") {
        glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
        if (!success){
            glGetShaderInfoLog(shader, 512, NULL, infoLog);
            qDebug() << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "---" << infoLog  << endl;
            return false;
        }
    } else {
        glGetProgramiv(shader, GL_LINK_STATUS, &success);
        if (!success) {
            glGetProgramInfoLog(shader, 512, NULL, infoLog);
            qDebug()  << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "---" << infoLog << endl;
            return false;
        }
    }
    return true;
}

void QPointCloudWidget::drawPointCloud()
{
    glUseProgram(programID);

    translate_and_rotate();

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, poses.data()); 
    glEnableVertexAttribArray(0);

    glDrawArrays(GL_POINTS, 0, poses.count() / 3);
    glDisableVertexAttribArray(0);

#if 0
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, lines.data());
    glEnableVertexAttribArray(0);

    glDrawArrays(GL_LINES, 0, 6);
    glDisableVertexAttribArray(0);
#endif
    glUseProgram(0);
}

void QPointCloudWidget::drawAxis()
{
//    qDebug() << __FUNCTION__;
    glUseProgram(axisProgramID);

    axix_translate_and_rotate();
    GLfloat colors[] = {
        1.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f,
        0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f,
    };

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, lines.data());
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, colors);

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

   // glDrawArrays(GL_LINES, 0, lines.count() / 3);
    glDrawArrays(GL_LINES, 0, 6);

    glUseProgram(0);
}

void QPointCloudWidget::translate_and_rotate()
{
    QMatrix4x4 projection, view, model;
    projection.perspective(60.0f, 1.0f, 0.1f, 3000.0f);

#if 1
    model.rotate(rollAngle, 1.0f, 0.0f, 0.0f);
    model.rotate(yawAngle, 0.0f, 1.0f, 0.0f);
    model.rotate(pitchAngle, 0.0f, 0.0f, 1.0f);
#endif
    model.translate(dx, dy, 0);

    view.lookAt(cameraPos / zoom, cameraFront, cameraUp);

    GLint modelLoc = glGetUniformLocation(programID, "model");
    GLint viewLoc  = glGetUniformLocation(programID, "view");
    GLint projectLoc = glGetUniformLocation(programID, "projection");

    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, model.data());
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, view.data());
    glUniformMatrix4fv(projectLoc, 1, GL_FALSE, projection.data());
}

void QPointCloudWidget::axix_translate_and_rotate()
{
    QMatrix4x4 projection, view, model;
    projection.perspective(60.0f, 1.0f, 0.1f, 3000.0f);

#if 1
    model.rotate(rollAngle, 1.0f, 0.0f, 0.0f);
    model.rotate(yawAngle, 0.0f, 1.0f, 0.0f);
    model.rotate(pitchAngle, 0.0f, 0.0f, 1.0f);
#endif
    model.translate(dx, dy, 0);

    view.lookAt(cameraPos / zoom, cameraFront, cameraUp);

    GLint modelLoc = glGetUniformLocation(axisProgramID, "model");
    GLint viewLoc  = glGetUniformLocation(axisProgramID, "view");
    GLint projectLoc = glGetUniformLocation(axisProgramID, "projection");

    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, model.data());
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, view.data());
    glUniformMatrix4fv(projectLoc, 1, GL_FALSE, projection.data());
}

axis.vert

#version 450 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec4 col;
void main() {
    col = vec4(aColor, 1.0);
    gl_Position = projection * view * model * vec4(aPos, 1.0);
}

axis.frag

#version 450 core
out vec4 FragColor;
in vec4 col;
void main() {
    FragColor = col;
}

pose.frag

#version 450 core
out vec4 FragColor;
in vec4 col;
void main() {
    FragColor = mat4( 1.0f, 0.0f, 0.0f, 0.0f,
                      0.0f, 1.0f, 0.0f, 0.0f,
                      0.0f, 0.0f, 1.0f, 0.0f,
                      0.0f, 0.0f, 0.0f, 1.0f) * vec4(col[0], col[1], col[2], 1.0f);
}

pose.vert

#version 450 core
layout (location = 0) in vec3 aPos;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec4 col;
void main() {
    col = vec4((100.0 - aPos.x) / 200.0 , (100.0 - aPos.y) / 200.0, (100.0 - aPos.z), 1.0);
    gl_Position = projection * view *model * vec4(aPos, 1.0);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值