目录

一、实现功能

二、实现效果

三、实现方法

光源设置

 材料设置

平移旋转缩放

绘制

完整代码


一、实现功能

1、网格显示

2、坐标轴显示

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

4、点云显示

二、实现效果

opengles绘制点云 opengl显示点云_数组

opengles绘制点云 opengl显示点云_qt_02

 

opengles绘制点云 opengl显示点云_qt_03

三、实现方法

基于QGLWidget实现

光源设置

/**
 * https://learn.microsoft.com/zh-cn/windows/win32/opengl/gllightfv
 * @brief glLightfv   设置单个光源参数
 * @param GLenum light 光线的标识符(GL_LIGHT0 ~ GL_LIGHT7)
          GLenum pname 参数名称 
                       GL_AMBIENT 环境光
                       GL_DIFFUSE  散射光
                       GL_SPECULAR 镜面反射光
                       GL_POSITION 光源位置齐次坐标(x,y,z,w)
                       GL_SPOT_DIRECTION 点光源聚光方向矢量(x,y,z)
                       GL_SPOT_EXPONENT  点光源聚光指数
                       GL_SPOT_CUTOFF    点光源聚光截至角
                       GL_CONSTANT_ATTENUATION  常数衰减因子K0,衰减系数=1/(K0+K1*D+K2*D2)  
                       GL_LINEAR_ATTENUATION    线性衰减因子K1
                       GL_QUADRATIC_ATTENUATION  二次衰减因子K2     
          const GLfloat *params 
 */
void APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params);
//设置好以上光源的属性之后,要使用glEnable(GL_LIGHTING)和glEnable(GL_LIGHTX)来启用光照和第X号光源。

示例:
    GLfloat ambientLight[] = {0.7f, 0.7f, 0.7f, 1.0f}; //光源环境光强度数组
    GLfloat diffuseLight[] = {0.7f, 0.8f, 0.8f, 1.0f}; //光源散射光强度数组
    GLfloat specularLight[] = {0.4f, 0.4f, 0.4f, 1.0f}; //光源镜面反射光强度数组
    GLfloat positionLight[] = {20.0f, 20.0f, 20.0f, 0.0f}; //光源位置数组

    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); //设置0号光源的环境光属性
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); //设置0号光源的散射光属性
    glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); //设置0号光源的镜面反射光属性
    glLightfv(GL_LIGHT0, GL_POSITION, positionLight); //设置0号光源的位置属性

 材料设置

/**
 * https://learn.microsoft.com/zh-cn/windows/win32/opengl/glmaterialfv
 * @brief glMaterialfv   设置材料属性
 * @param GLenum face,  指出材质属性将应用于物体的哪面  
                       GL_FRONT 前面
                       GL_BACK 背面
                       GL_FRONT_AND_BACK 前面和背面
          GLenum pname, 设置的哪种材质属性 
                       GL_AMBIENT 材料的环境光颜色
                       GL_DIFFUSE 材料的漫射光颜色
                       GL_SPECULAR 材料的镜面反射光颜色
                       GL_EMISSION 材料的辐射光颜色
                       GL_SHININESS 镜面指数(光亮度)
                       GL_AMBIENT_AND_DIFFUSE  材质的环境颜色和散射颜色
                       GL_COLOR_INDEXES 材料的环境光、漫射光和镜面光颜色
          const GLfloat *params
 */
void APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);

示例:
    GLfloat color[] = {r / 255.0f, g / 255.0f, b / 255.0f};
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);

平移旋转缩放

/**
 * https://learn.microsoft.com/zh-cn/windows/win32/opengl/gltranslated
 * @brief glTranslated   将当前矩阵乘以平移矩阵,与glTranslatef函数功能一样
 * @param  x,y,z分别指定沿x,y,z轴方向的平移分量
 */
void APIENTRY glTranslated (GLdouble x, GLdouble y, GLdouble z);


/**
 * https://learn.microsoft.com/zh-cn/windows/win32/opengl/glrotated
 * @brief glRotated   当前矩阵乘以旋转矩阵,绕着向量(cx, cy, cz)逆时针旋转,与glRotatef函数功能一样
 * @param  GLdouble angle,  旋转角度(以度为单位)
           GLdouble x,  向量的 x 坐标
           GLdouble y,  向量的 y 坐标
           GLdouble z   向量的 z 坐标
 */
void APIENTRY glRotated (GLdouble angle, GLdouble x, GLdouble y, GLdouble z);

示例:
    glTranslated(0, 0, m_zoom);                 /* 不清楚为什么可以达到缩放的效果 */     
    glTranslated(m_xTrans, m_yTrans, 0);        
    glRotated(m_xRotate / 16.0, 1.0, 0.0, 0.0); /* 绕x轴旋转 */
    glRotated(m_yRotate / 16.0, 0.0, 1.0, 0.0); /* 绕y轴旋转 */

绘制

// 使用glPushMatrix和glPopMatrix保存和还原未启动的坐标系
void APIENTRY glPushMatrix (void);
void APIENTRY glPopMatrix (void);

/**
 * https://learn.microsoft.com/zh-cn/windows/win32/opengl/glbegin
 * @brief glBegin    与glEnd组合使用
 * @param GLenum mode       创建元素的类型
         GL_POINTS          将每个顶点视为单个点
         GL_LINES           将顶点的每个配对视为独立的线段
         GL_LINE_LOOP       绘制从第一个顶点到最后一个顶点的连接线段组,然后返回到第一个
         GL_LINE_STRIP      绘制从第一个顶点到最后一个顶点的连接线段组
         GL_TRIANGLES       将每个三元顶点视为独立的三角形
         GL_TRIANGLE_STRIP  绘制一组连接的三角形
         GL_TRIANGLE_FAN    绘制一组连接的三角形
         GL_QUADS           将四个顶点的每个组视为独立的四边形
         GL_QUAD_STRIP      绘制一组连接的四边形
         GL_POLYGON         绘制单个凸面多边形
 */
WINGDIAPI void APIENTRY glBegin (GLenum mode);
WINGDIAPI void APIENTRY glEnd (void);

示例:画点云
    glPushMatrix();
    glBegin(GL_POINTS);
    for(auto vec3d : m_pointVector)
    {
        glVertex3d(vec3d.x(), vec3d.y(), vec3d.z());
    }
    glEnd();
    glPopMatrix();

完整代码


BaseGLWidget.h


#ifndef RRGLWIDGET_H
#define RRGLWIDGET_H

#include <QGLWidget>
#include <QWidget>
#include "opengllib_global.h"

class OPENGLLIBSHARED_EXPORT BaseGLWidget : public QGLWidget
{
    Q_OBJECT
public:
    BaseGLWidget(QWidget *parent = 0);
    ~BaseGLWidget();

protected:
    void initializeGL() override;
    void paintGL() override;
    void resizeGL(int w, int h) override;

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

    void setGLMaterialColor(int r, int g, int b);
    void setXRotation(int angle);
    void setYRotation(int angle);
    void setXYTranslate(int dx, int dy);
    void setZoom(int zoom);

    virtual void drawGL() = 0;
    virtual void drawMeshline(float size = 50, int count = 15);
    virtual void drawCoordAxis(float length = 900);

protected:
    GLdouble m_xRotate;   /**< x旋转角度 */
    GLdouble m_yRotate;   /**< y旋转角度 */
    GLdouble m_zoom;      /**< 缩放 */
    GLdouble m_xTrans;    /**< 界面显示X位置 */
    GLdouble m_yTrans;    /**< 界面显示Y位置 */
    QPoint   lastPos;
};
#endif // RRGLWIDGET_H


BaseGLWidget.cpp


#include "BaseGLWidget.h"
#include <GL/glu.h>
#include <QDebug>
#include <QMouseEvent>

BaseGLWidget::BaseGLWidget(QWidget *parent)
    : QGLWidget(parent)
{
    m_xRotate = -2276;
    m_yRotate = 1736;
    m_zoom    = -20;
    m_xTrans  = 0;
    m_yTrans  = 0;
}

BaseGLWidget::~BaseGLWidget() {}

void BaseGLWidget::initializeGL()
{
    //用来初始化这个OpenGL窗口部件的,可以在里面设定一些有关选项
    GLfloat ambientLight[] = {0.7f, 0.7f, 0.7f, 1.0f}; //光源环境光强度数组
    GLfloat diffuseLight[] = {0.7f, 0.8f, 0.8f, 1.0f}; //光源散射光强度数组
    GLfloat specularLight[] = {0.4f, 0.4f, 0.4f, 1.0f}; //光源镜面反射光强度数组
    GLfloat positionLight[] = {20.0f, 20.0f, 20.0f, 0.0f}; //光源位置数组

    glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); //设置0号光源的环境光属性
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); //设置0号光源的散射光属性
    glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); //设置0号光源的镜面反射光属性
    glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1.0);
    glLightfv(GL_LIGHT0, GL_POSITION, positionLight); //设置0号光源的位置属性

    glEnable(GL_LIGHTING);   //启用光照
    glEnable(GL_LIGHT0);     //打开光源
    glEnable(GL_DEPTH_TEST); //隐藏表面消除
    glEnable(GL_NORMALIZE);

    glClearColor(0.0, 0.0, 0.0, 1.0);
}

void BaseGLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* 清除屏幕和深度缓存 */
    glPushMatrix();
    glTranslated(0, 0, m_zoom);
    glTranslated(m_xTrans, m_yTrans, 0);
    glRotated(m_xRotate / 16.0, 1.0, 0.0, 0.0); /* 绕x轴旋转 */
    glRotated(m_yRotate / 16.0, 0.0, 1.0, 0.0); /* 绕y轴旋转 */
    glRotated(+90.0, 1.0, 0.0, 0.0);
    drawGL();
    glPopMatrix();
}

void BaseGLWidget::resizeGL(int w, int h)
{
    if (w < 0 || h < 0)
    {
        return;
    }
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(35.0, w / float(h), 1.0, 20000.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslated(0.0, 0.0, -40.0);
}

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

void BaseGLWidget::mouseMoveEvent(QMouseEvent *event)
{
    int dx = event->x() - lastPos.x();
    int dy = event->y() - lastPos.y();
    if (event->buttons() & Qt::LeftButton)
    {
        setXRotation(m_xRotate + 4 * dy);
        setYRotation(m_yRotate - 4 * dx);
    }
    else if (event->buttons() & Qt::MidButton)
    {
        setXYTranslate(0.5 * dx, 0.5 * dy);
    }
    lastPos = event->pos();
}

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

void BaseGLWidget::setGLMaterialColor(int r, int g, int b)
{
    /*
     * 参数1的取值可以是GL_FRONT、GL_BACK或GL_FRONT_AND_BACK,指出材质属性将应用于物体的哪面
     * 参数2指出要设置的哪种材质属性,GL_AMBIENT_AND_DIFFUSE材质的环境颜色和散射颜色
     */
    GLfloat color[] = {r / 255.0f, g / 255.0f, b / 255.0f};
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
}

void BaseGLWidget::setXRotation(int angle)
{
    int tangle = angle;
    if (tangle != m_xRotate)
    {
        m_xRotate = tangle;
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        updateGL();
    }
}

void BaseGLWidget::setYRotation(int angle)
{
    int tangle = angle;
    if (tangle != m_yRotate)
    {
        m_yRotate = tangle;
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }
}

void BaseGLWidget::setXYTranslate(int dx, int dy)
{
    m_xTrans += dx;
    m_yTrans -= dy;
    updateGL();
}

void BaseGLWidget::setZoom(int zoom)
{
    m_zoom = zoom;
    if(m_zoom < -300)
    {
        m_zoom = -300;
    }
    if(m_zoom > 35)
    {
        m_zoom = 35;
    }
    updateGL();
}

void BaseGLWidget::drawMeshline(float size, int count)
{
    glPushMatrix();
    GLfloat color[] = {8.0f / 255, 108.0f / 255, 162.0f / 255};
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
    float start = count * (size / 2);
    float posX = start, posZ = start;
    for (int i = 0; i <= count; ++i)
    {
        glBegin(GL_LINES);
        glVertex3f(posX, start, 0);
        glVertex3f(posX, -start, 0);
        glVertex3f(start, posZ, 0);
        glVertex3f(-start, posZ, 0);
        glEnd();

        posX = posX - size;
        posZ = posZ - size;
    }
    glPopMatrix();
}

void BaseGLWidget::drawCoordAxis(float length)
{
    glPushMatrix();

    glLineWidth(4.0f);

    glBegin(GL_LINES);
    setGLMaterialColor(255, 0, 0);  // X axis is red.
    glVertex3f(0, 0, 0);
    glVertex3f(length, 0, 0);
    setGLMaterialColor(0, 255, 0);  // Y axis is green.

    glVertex3f(0, 0, 0);
    glVertex3f(0, length, 0);
    setGLMaterialColor(0, 0, 255);   // Z axis is blue.
    glVertex3f(0, 0, 0);
    glVertex3f(0, 0, length);
    glEnd();

    // Draw labels
    glColor3f(0.0, 1.0, 1.0);
    renderText(0, 0, length, "+Z", QFont("helvetica", 12, QFont::Bold, true));

    glColor3f(1.0, 0.0, 0.0);
    renderText(length, 0, 0, "+X", QFont("helvetica", 12, QFont::Bold, true));

    glColor3f(0.0, 1.0, 0.0);
    renderText(0, length, 0, "+Y", QFont("helvetica", 12, QFont::Bold, true));

    glLineWidth(1.0f);
    glPopMatrix();
}


PointCloudGLWidget.h


#ifndef POINTCLOUD3DWIDGET_H
#define POINTCLOUD3DWIDGET_H

#include "BaseGLWidget.h"
#include <QVector3D>

class OPENGLLIBSHARED_EXPORT PointCloudGLWidget: public BaseGLWidget
{
    Q_OBJECT

public:
    explicit PointCloudGLWidget(QWidget *parent = 0);
    ~PointCloudGLWidget();
    void updatePoints(const QVector<QVector3D> &points);
    void loadCsvFile(const QString &path);

protected:
    virtual void drawGL() override;

private:
    void drawPointdata();

private:
    QVector<QVector3D> m_pointVector;
};

#endif // POINTCLOUD3DWIDGET_H


PointCloudGLWidget.cpp


#include "PointCloudGLWidget.h"

#include <QFile>
#include <QTextStream>
#include <QDebug>

PointCloudGLWidget::PointCloudGLWidget(QWidget *parent)
    : BaseGLWidget(parent)
{

}

PointCloudGLWidget::~PointCloudGLWidget()
{

}

void PointCloudGLWidget::updatePoints(const QVector<QVector3D> &points)
{
    m_pointVector.clear();
    m_pointVector = points;
}

void PointCloudGLWidget::loadCsvFile(const QString &path)
{
    m_pointVector.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_pointVector.append(QVector3D(x, y, z));
        }
        inFile.close();
    }
}

void PointCloudGLWidget::drawGL()
{
    drawMeshline(2, 16);
    drawCoordAxis(4.0);
    drawPointdata();
}

void PointCloudGLWidget::drawPointdata()
{
    glPushMatrix();
    setGLMaterialColor(255 * 0.5, 255, 255);
    glBegin(GL_POINTS);
    for(auto vec3d : m_pointVector)
    {
        glVertex3d(vec3d.x(), vec3d.y(), vec3d.z());
    }
    glEnd();
    glPopMatrix();
}