OPENGL+点云可视化

之前的文章写了如何在VS2015 下配置 opengl可视化环境,本文介绍如何使用opengl 来进行点云的简单显示,主要参考资料为:

 learnopengl: https://learnopengl-cn.github.io/。

 cloudcompare:https://github.com/CloudCompare/CloudCompare

首先需要构建一个点云类PointCloud,用于点云的读取,计算点的个数、重心等基本功能。

下面是PointCloud.h文件

#ifndef POINTCLOUD_H
#define POINTCLOUD_H
#include "Tuple.h"
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
namespace CCLib
{
    class Octree;
 
    class PointCloud
    {
    public:
        PointCloud();
        ~PointCloud();
 
        typedef std::vector<CCVector3> cloud;
    public:
 
        float m_Xmin;
        float m_Ymin;
        float m_Zmin;
        CCVector3 Gravity;
        CCVector3 minCoordinate;
        CCVector3 maxCoordinate;
        CCVector3 bounding;
        unsigned numberOfpoints;
        Octree* octree;
 
        //functions
        void read(char*p);
        void save(char*q);
        void getMinXCoordinate();
        void getMinYCoordinate();
        void getMinZCoordinate();
        void getMaxXCoordinate();
        void getMaxYCoordinate();
        void getMaxZCoordinate();
        Octree* computeOctree(bool autoAddChild/*=true*/);
        CCVector3& computeGravity();
        void getBounding(CCVector3&min,CCVector3&max);
        const CCVector3* getPoint(unsigned);
        void ConstructMinCube(CCVector3& dimMin, CCVector3& dimMax, double enlargeFactor/*=0.01*/);
        unsigned size();
        //add Point
        void addPoint(CCVector3);
        float getWidth()
        {
            getMinXCoordinate();
            getMaxXCoordinate();
            return maxCoordinate.x - minCoordinate.x;
        }
        float getLength()
        {
            getMinYCoordinate();
            getMaxYCoordinate();
            return maxCoordinate.y - minCoordinate.y;
        }
        float getHeight()
        {
            getMinZCoordinate();
            getMaxZCoordinate();
            return maxCoordinate.z - minCoordinate.z;
        }
    private:    cloud c1;
 
    };
}
#endif
 
然后是PointCloud源文件:

#include "PointCloud.h"
#include "Octree.h"
using namespace CCLib;
PointCloud::PointCloud()
{
    
}
void PointCloud::read(char *p)
{
        CCVector3 temp;
        ifstream fin(p);
        
        if (!fin)
        {
            cout << "open file failed!";
            //return -1;
        }
        while (fin >> temp.x >> temp.y >> temp.z)
        {    
            c1.push_back(temp);
        }
        fin.close();
}
void PointCloud::save(char* q)
{
    ofstream fout(q);
 
    if (!fout)
    {
        cout << "open file failed!";
        //return -1;
    }
    for (unsigned i = 0; i < c1.size(); i++)
    {
        fout << c1[i].x<<" "<< c1[i].y <<" "<< c1[i].z<<endl;
    }
    fout.close();
}
void PointCloud::getMinXCoordinate()
{
 
    minCoordinate.x = c1[0].x;
    for (unsigned i = 0; i < c1.size(); i++)
    {
        if (minCoordinate.x >= c1[i].x)
            minCoordinate.x = c1[i].x;
    }
 
 
}
void PointCloud::getMinYCoordinate()
{
 
    minCoordinate.y = c1[0].y;
    for (unsigned i = 0; i < c1.size(); i++)
    {
        if (minCoordinate.y >= c1[i].y)
            minCoordinate.y = c1[i].y;
    }
 
 
}
void PointCloud::getMinZCoordinate()
{
 
    minCoordinate.z = c1[0].z;
    for (unsigned i = 0; i < c1.size(); i++)
    {
        if (minCoordinate.z>= c1[i].z)
            minCoordinate.z = c1[i].z;
    }
 
 
}
void PointCloud::getMaxXCoordinate()
{
 
    maxCoordinate.x = c1[0].x;
    for (unsigned i = 0; i < c1.size(); i++)
    {
        if (maxCoordinate.x <= c1[i].x)
            maxCoordinate.x = c1[i].x;
    }
 
 
}
void PointCloud::getMaxYCoordinate()
{
 
    maxCoordinate.y = c1[0].y;
    for (unsigned i = 0; i < c1.size(); i++)
    {
        if (maxCoordinate.y <= c1[i].y)
            maxCoordinate.y = c1[i].y;
    }
 
 
}
void PointCloud::getMaxZCoordinate()
{
 
    maxCoordinate.z = c1[0].z;
    for (unsigned i = 0; i < c1.size(); i++)
    {
        if (maxCoordinate.z <= c1[i].z)
            maxCoordinate.z = c1[i].z;
    }
 
 
}
 
void PointCloud:: getBounding(CCVector3&min,CCVector3&max)
{
    getMinXCoordinate();
    getMinYCoordinate();
    getMinZCoordinate();
    getMaxXCoordinate();
    getMaxYCoordinate();
    getMaxZCoordinate();
    
    min = minCoordinate;
    max = maxCoordinate;
 
}
const CCVector3* PointCloud::getPoint(unsigned i)
{
    size();
    CCVector3* theGettingPoint=NULL;
    if (numberOfpoints == 0)
    {
        cout << "NO POINTS IN THE CLOUD" << endl;
        
    }
    else
    {
         theGettingPoint= &c1[i];
 
    }
 
    
    return theGettingPoint;
}
unsigned PointCloud::size()
{
    numberOfpoints = c1.size();
    return numberOfpoints;
 
}
CCVector3& PointCloud::computeGravity()
{
    for (unsigned i = 0; i < size(); i++)
    {
        Gravity.x += c1[i].x;
        Gravity.y += c1[i].y;
        Gravity.z += c1[i].z;
    }
    Gravity.x = Gravity.x / numberOfpoints;
    Gravity.y = Gravity.y / numberOfpoints;
    Gravity.z = Gravity.z / numberOfpoints;
    return Gravity;                                                          
 
}
void PointCloud::ConstructMinCube(CCVector3& dimMin, CCVector3& dimMax, double enlargeFactor/*=0.01*/)
{
    float maxDD = 0;
    getBounding(dimMin, dimMax);
    {
        CCVector3 diag = dimMax - dimMin;
        maxDD = std::max(diag.x, diag.y);
        maxDD = std::max(maxDD, diag.z);
    }
    if (enlargeFactor > 0)
        maxDD = static_cast<float>(static_cast<double>(maxDD)* (1.0 + enlargeFactor));
 
    //build corresponding 'square' box
    {
        CCVector3 dd(maxDD, maxDD, maxDD);
        CCVector3 md = dimMax + dimMin;
 
        dimMin = (md - dd) * static_cast<float>(0.5);
        dimMax = dimMin + dd;
    }
 
 
}
 Octree* PointCloud::computeOctree(bool autoAddChild/*=true*/)
{
    Octree* octree = new Octree(this);
     getMinXCoordinate();
     getMinYCoordinate();
     getMinZCoordinate();
     getMaxXCoordinate();
     getMaxYCoordinate();
     getMaxZCoordinate();
 
    int a = octree->build(minCoordinate,maxCoordinate);
    if (a > 0)
        cout << "compute Octree sucessful" << endl;
    return octree;
    
 
}
 void PointCloud::addPoint(CCVector3 point)
 {
    
         c1.push_back(point);
 
    
     
 }
PointCloud::~PointCloud()
{
}
读取的点云通过std::<CCVECTOR3>point 容器保存,CCVECTOR 的定义在Tuple头文件,这部分完全参考CC:

#ifndef Tuple_H
#define Tuple_H
#include <math.h>
template <class Type> class Tuple3
{
    public:
        union 
        {
            struct
            {
                Type x, y, z;
            };
             Type u[3];
        };
        inline Tuple3() :x(0), y(0), z(0)  {}
        inline Tuple3(Type a, Type b, Type c) :x(a), y(b), z(c) {}
        inline explicit Tuple3(const Type P[]) :x(P[0]), y(P[1]), z(P[2]) {}
        inline Tuple3(const Tuple3& v) :x(v.x), y(v.y), z(v.z) {}
 
        //Invers operator
        inline Tuple3 operator -() const  { Tuple3 V(-x, -y, -z); return V; }
        inline Tuple3 operator +=(const Tuple3& V) { x += V.x;  y += V.y;  z += V.z; return *this; }
        inline Tuple3 operator *=(Type v)   { x *=v;  y *= v;  z *= v; return *this; }
        inline Tuple3 operator /=(Type v)   { x /=v;  y /= v;  z /= v; return *this; }
        inline Tuple3 operator -=(const Tuple3& V) { x -= V.x;  y -= V.y;  z -= V.z; return *this; }
        inline Tuple3 operator +(const Tuple3& V) const  { V.x = x + V.x; V.y = y + V.y;V.z=z+V.z; return V; }
        inline Tuple3 operator -(const Tuple3& V) const  { return V(x - V.x, y - V.y, z - V.z); }
        inline Tuple3 operator *(Type s) const  { return Tuple3(x*s, y*s, z*s); }
        inline Tuple3 operator /(Type s) const  { return Tuple3(x/s, y/s, z/s); }        
};
    
        typedef Tuple3<unsigned char> Tuple3ub;
        typedef Tuple3<short> Tuple3s;
        typedef Tuple3<int> Tuple3i;
        typedef Tuple3<unsigned int> Tuple3ui;
 
template <typename Type> class Vector3 :public Tuple3<Type>
{
public:
    using Tuple3<Type>::x;
    using Tuple3<Type>::y;
    using Tuple3<Type>::z;
    using Tuple3<Type>::u;
 
    inline Vector3() : Tuple3<Type>() {}
    inline Vector3(Type _a, Type _b, Type _c) : Tuple3<Type>(_a, _b, _c)  {}
    inline explicit Vector3(const Type P[]) : Tuple3<Type>(P) {}
    inline Vector3(const Vector3& v) : Tuple3<Type>(v) {}
 
    static inline Vector3 fromArray(const int a[3]) { return Vector3(static_cast<Type>(a[0]), static_cast<Type>(a[1]), static_cast<Type>(a[2])); }
    //! Constructor from a float array
    static inline Vector3 fromArray(const float a[3]) { return Vector3(static_cast<Type>(a[0]), static_cast<Type>(a[1]), static_cast<Type>(a[2])); }
    //! Constructor from a double array
    static inline Vector3 fromArray(const double a[3]) { return Vector3(static_cast<Type>(a[0]), static_cast<Type>(a[1]), static_cast<Type>(a[2])); }
    // you can add other options here dot product,cross product and so on
 
    inline Type dot(const Vector3& v) const { return (x*v.x) + (y*v.y) + (z*v.z); }
    //! Cross product
    inline Vector3 cross(const Vector3 &v) const { return Vector3((y*v.z) - (z*v.y), (z*v.x) - (x*v.z), (x*v.y) - (y*v.x)); }
    inline Type norm2() const { return (x*x) + (y*y) + (z*z); }
    inline double norm2d() const { return static_cast<double>(x)*x + static_cast<double>(y)*y + static_cast<double>(z)*z ; }
 
    inline Vector3 operator -(const Vector3& V) const { return Vector3(x - V.x, y - V.y, z - V.z); }
    inline Vector3 operator +(const Vector3& V) const { return Vector3(x + V.x, y + V.y, z + V.z); }
    inline Vector3 operator *(Type s) const { return Vector3(s*x,s*y,s*z); }
    inline Type& operator [](unsigned i)  { return u[i]; }
    inline const Type& operator []  (unsigned i) const { return u[i]; }
 
    inline void normalize() { Type n = norm2(); if (n>0) *this /= sqrt(n); }
    //! Returns a normalized vector which is orthogonal to this one
    static inline void vdivide(Type p[], Type s) { p[0] /= s; p[1] /= s; p[2] /= s; }
    static inline void vdivide(const Type p[], Type s, Type r[]) { r[0] = p[0] / s; r[1] = p[1] / s; r[2] = p[2] / s; }
    static inline Type vnorm2(const Type p[]) { return (p[0] * p[0]) + (p[1] * p[1]) + (p[2] * p[2]); }
    inline Vector3 orthogonal() const { Vector3 ort; vorthogonal(u, ort.u); return ort; }
    static inline void vnormalize(Type p[]) { Type n = vnorm2(p); if (n>0) vdivide(p, sqrt(n)); }
    static inline void vorthogonal(const Type p[], Type q[])
    {
        if (fabs(p[0]) <= fabs(p[1]) && fabs(p[0]) <= fabs(p[2]))
        {
            q[0] = 0; q[1] = p[2]; q[2] = -p[1];
        }
        else if (fabs(p[1]) <= fabs(p[0]) && fabs(p[1]) <= fabs(p[2]))
        {
            q[0] = -p[2]; q[1] = 0; q[2] = p[0];
        }
        else
        {
            q[0] = p[1]; q[1] = -p[0]; q[2] = 0;
        }
        vnormalize(q);
    }
 
 
};
//! Default 3D Vector
typedef Vector3<float> CCVector3;
//! Double 3D Vector
typedef Vector3<double> CCVector3d;
 
 
//2D Vector
//! 2D Vector
template <class Type> class Vector2Tpl
{
public:
 
    union
    {
        struct
        {
            Type x, y;
        };
        Type u[2];
    };
 
    //! Default constructor
    /** Inits vector to (0,0).
    \param s default init value for both coordinates
    **/
    inline Vector2Tpl(Type s = 0) : x(s), y(s) {}
 
    //! Constructor from a couple of coordinates
    /** Inits vector to (x,y).
    \param _x x coordinate
    \param _y y coordinate
    **/
    inline Vector2Tpl(Type _x, Type _y) : x(_x), y(_y) {}
 
    //! Copy constructor
    inline Vector2Tpl(const Vector2Tpl& v) : x(v.x), y(v.y) {}
 
    //! Returns vector square norm
    inline Type norm2() const { return (x*x) + (y*y); }
    //! Returns vector norm
    inline Type norm() const { return sqrt(norm2()); }
    //! Sets vector norm to unity
    inline void normalize() { Type n = norm2(); if (n>0) *this /= sqrt(n); }
 
    //! Dot product
    inline Type dot(const Vector2Tpl& v) const { return (x*v.x) + (y*v.y); }
 
    //! Inverse operator
    inline Vector2Tpl& operator - () { x = -x; y = -y; return *this; }
    //! In-place addition operator
    inline Vector2Tpl& operator += (const Vector2Tpl& v) { x += v.x; y += v.y; return *this; }
    //! In-place substraction operator
    inline Vector2Tpl& operator -= (const Vector2Tpl& v) { x -= v.x; y -= v.y; return *this; }
    //! In-place multiplication (by a scalar) operator
    inline Vector2Tpl& operator *= (Type v) { x *= v; y *= v; return *this; }
    //! In-place division (by a scalar) operator
    inline Vector2Tpl& operator /= (Type v) { x /= v; y /= v; return *this; }
    //! Addition operator
    inline Vector2Tpl operator + (const Vector2Tpl& v) const { return Vector2Tpl(x + v.x, y + v.y); }
    //! Substraction operator
    inline Vector2Tpl operator - (const Vector2Tpl& v) const { return Vector2Tpl(x - v.x, y - v.y); }
    //! Multiplication operator
    inline Vector2Tpl operator * (Type s) const { return Vector2Tpl(x*s, y*s); }
    //! Division operator
    inline Vector2Tpl operator / (Type s) const { return Vector2Tpl(x / s, y / s); }
    //! Copy operator
    inline Vector2Tpl& operator = (const Vector2Tpl &v) { x = v.x; y = v.y; return *this; }
    //! Direct coordinate access
    inline Type& operator [] (unsigned i) { return u[i]; }
    //! Direct coordinate access (const)
    inline const Type& operator [] (unsigned i) const { return u[i]; }
};
 
//! Default 2D Vector
typedef Vector2Tpl<float> CCVector2;
 
//! Int 2D Vector
typedef Vector2Tpl<int> CCVector2i;
 
#endif
最后重点来了,在main函数里面实现点云的可视化,根据learnopengl的相关教程,定义了一个相机类Camera.h:

#pragma once
 
// Std. Includes
#include <vector>
 
// GL Includes
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
 
 
 
// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum Camera_Movement {
    FORWARD,
    BACKWARD,
    LEFT,
    RIGHT
};
 
// Default camera values
const GLfloat YAW = -90.0f;
const GLfloat PITCH = 0.0f;
const GLfloat ROLL = 0.0f;
const GLfloat SPEED = 3.0f;
const GLfloat SENSITIVTY = 0.25f;
const GLfloat ZOOM = 30.0f;
 
 
// An abstract camera class that processes input and calculates the corresponding Eular Angles, Vectors and Matrices for use in OpenGL
class Camera
{
public:
    // Camera Attributes
    glm::vec3 Position;
    glm::vec3 TargetPositon;
    glm::vec3 Front;
    glm::vec3 Up;
    glm::vec3 Right;
    glm::vec3 WorldUp;
    // Eular Angles
    GLfloat Yaw;
    GLfloat Pitch;
    GLfloat Roll;
    // Camera options
    GLfloat MovementSpeed;
    GLfloat MouseSensitivity;
    GLfloat Zoom;
    //Front(glm::vec3(0.0f, 0.0f, -1.0f)
    // Constructor with vectors
    Camera(glm::vec3 position , glm::vec3 up , glm::vec3 target , GLfloat yaw , GLfloat pitch , GLfloat roll ) : MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM)
    {
        this->Position = position;
        this->WorldUp = up;
        this->TargetPositon = target;
        this->Yaw = yaw;
        this->Pitch = pitch;
        this->Roll = roll;
        this->updateCameraVectors();
    }
    // Constructor with scalar values
    Camera(GLfloat posX, GLfloat posY, GLfloat posZ, GLfloat upX, GLfloat upY, GLfloat upZ, GLfloat yaw, GLfloat pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVTY), Zoom(ZOOM)
    {
        this->Position = glm::vec3(posX, posY, posZ);
        this->WorldUp = glm::vec3(upX, upY, upZ);
        this->Yaw = yaw;
        this->Pitch = pitch;
        this->updateCameraVectors();
    }
 
    // Returns the view matrix calculated using Eular Angles and the LookAt Matrix
    glm::mat4 GetViewMatrix()
    {
        //return glm::lookAt(this->Position, this->Position + this->Front, this->Up);
        return glm::lookAt(this->Position, this->TargetPositon, this->WorldUp);
    }
 
    // Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
    void ProcessKeyboard(Camera_Movement direction, GLfloat deltaTime)
    {
        GLfloat velocity = this->MovementSpeed * deltaTime;
        if (direction == FORWARD)
            this->Position += this->Front * velocity;
        if (direction == BACKWARD)
            this->Position -= this->Front * velocity;
        if (direction == LEFT)
            this->Position -= this->Right * velocity;
        if (direction == RIGHT)
            this->Position += this->Right * velocity;
    }
 
    // Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
    void ProcessMouseMovement(GLfloat xoffset, GLfloat yoffset, GLboolean constrainPitch = true)
    {
        xoffset *= this->MouseSensitivity;
        yoffset *= this->MouseSensitivity;
 
        this->Yaw += xoffset;
        this->Pitch += yoffset;
 
        // Make sure that when pitch is out of bounds, screen doesn't get flipped
        if (constrainPitch)
        {
            if (this->Pitch > 89.0f)
                this->Pitch = 89.0f;
            if (this->Pitch < -89.0f)
                this->Pitch = -89.0f;
        }
 
        // Update Front, Right and Up Vectors using the updated Eular angles
        this->updateCameraVectors();
    }
 
    // Processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
    void ProcessMouseScroll(GLfloat yoffset)
    {
        if (this->Zoom >= 1.0f && this->Zoom <= 45.0f)
            this->Zoom -= yoffset;
        if (this->Zoom <= 1.0f)
            this->Zoom = 1.0f;
        if (this->Zoom >= 45.0f)
            this->Zoom = 45.0f;
    }
 
    // Calculates the front vector from the Camera's (updated) Eular Angles
private:    void updateCameraVectors()
    {
        
 
 
 
 
        // Calculate the new Front vector
        glm::vec3 front;
        front.x = cos(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch));
        front.y = sin(glm::radians(this->Pitch));
        front.z = sin(glm::radians(this->Yaw)) * cos(glm::radians(this->Pitch));
        this->Front = glm::normalize(front);
        this->Position = this->TargetPositon - this->Front;
        this->WorldUp.x = sin(glm::radians(Roll));
        this->WorldUp.y = cos(glm::radians(Roll));
        this->WorldUp.z = 0;
        // Also re-calculate the Right and Up vector
        //this->Right = glm::normalize(glm::cross(this->Front, this->WorldUp));  // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
        //this->Up = glm::normalize(glm::cross(this->Right, this->Front));
    }
};
相应的顶点着色器(texture.vs)和片段着色器(texture.frag)也是少不了的,对读入的点云设置为统一颜色,因此顶点着色器文件中只读入顶点并进行相应的坐标变换:texture.vs文件如下;

#version 330 core
layout (location = 0) in vec3 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
    gl_Position = projection*view* model*vec4(position, 1.0f);
    
    
}
texture.frag文件如下:

#version 330 core
out vec4 color;
void main()
{
    color = vec4(1.0f,1.0f,0.1f, 1.0f);
}
主函数包括点云数据的读取,opengl显示窗口的设置,点云坐标的转换,以及鼠标键盘的响应函数:

#include <iostream>
#include <fstream>
// GLEW
#define GLEW_STATIC
#include <GL/glew.h>
// GLFW
#include <GLFW/glfw3.h>
//GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
// Other Libs
#include <SOIL.h>
// Other includes
#include "Shader.h"
#include "Camera.h"
//pointCloud
#include "PointCloud.h"
#include <iostream>
#include <iomanip>
#include "Octree.h"
#include "Neighborhood.h"
#include <stdlib.h>
#include "Tuple.h"
#include "triangle.h"
#ifdef SINGLE
#define REAL float
#else /* not SINGLE */
#define REAL double
#endif /* not SINGLE */
 
#include <stdio.h>
#include "triangle.h"
#define TRILIBABRY
// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);
void do_movement();
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
void mouse_button_callback(GLFWwindow* window, int button, int action, int mode);
// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;
GLfloat lastX = 400, lastY = 300;
 
bool firstMouse = true;
 
bool keys[1024];
bool buttons[1024];
//
GLfloat deltaTime = 0.0f;   // 当前帧与上一帧的时间差
GLfloat lastFrame = 0.0f;   // 上一帧的时间
GLfloat mix = 0.2f;
//camera Para
CCVector3 g;
GLfloat phi = asin(fabs(64 / sqrt(349*349 + 217*217 + 64*64)));
GLfloat theta = acos(fabs(3349 * 349 / sqrt(349 * 349 + 217 * 217)));
//Camera camera(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(-3.499, 2.178f, 0.642f), 0.0f, 0.0f, 0.0f);
Camera camera(glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 0.0f), 0.0, 0.0, 0.0f);
 
// The MAIN function, from here we start the application and run the game loop
int main()
{
 
 
    // Init GLFW
    glfwInit();
    // Set all the required options for GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
 
    // Create a GLFWwindow object that we can use for GLFW's functions
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
    glfwMakeContextCurrent(window);
 
 
    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);
    glfwSetMouseButtonCallback(window, mouse_button_callback);
    glfwSetCursorPosCallback(window, mouse_callback);
    glfwSetScrollCallback(window, scroll_callback);
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
 
    // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
    glewExperimental = GL_TRUE;
    // Initialize GLEW to setup the OpenGL Function pointers
    glewInit();
 
    // Define the viewport dimensions
    glViewport(0, 0, WIDTH, HEIGHT);
 
 
    // Build and compile our shader program
    Shader ourShader("textures.vs", "textures.frag");
 
    //pointCloud process
    CCLib::PointCloud* cloud = new CCLib::PointCloud;
    char* p = "wyt.xyz";
    cloud->read(p);
    cloud->computeGravity();
    g = cloud->Gravity;
    int pointCount = cloud->size();
    std::vector<GLfloat>vertice;
    //set point color acoording Cloudindex
 
    for (unsigned i = 0; i < cloud->size();i++)
    {
        const CCVector3* p = cloud->getPoint(i);
        vertice.push_back(p->x);
        vertice.push_back(p->y);
        vertice.push_back(p->z);
        
        
    }
 
 
    //dispaly
 
    GLuint VBO, VAO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
 
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertice[0])*vertice.size(), &vertice[0], GL_STATIC_DRAW);
    
 
    // Position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0); // Unbind VAO
    glEnable(GL_DEPTH_TEST);
 
    //dispaly in GL_line mode
    glPolygonMode(GL_FRONT_AND_BACK, GL_POLYGON);
 
 
    // Game loop
    while (!glfwWindowShouldClose(window))
    {
        
        GLfloat currentFrame = glfwGetTime();
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;
        // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
        glfwPollEvents();
 
        do_movement();
        // Render
        // Clear the colorbuffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        //glClear(GL_COLOR_BUFFER_BIT);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        ourShader.use();
        glBindVertexArray(VAO);
        
        glm::mat4 model(1);
        model = glm::translate(model, glm::vec3(-g.x,-g.y,-g.z));
        GLint modelLoc = glGetUniformLocation(ourShader.Program(), "model");
        glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
 
        glm::mat4 view;
        view = camera.GetViewMatrix();
        GLint viewLoc = glGetUniformLocation(ourShader.Program(), "view");
        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
 
        glm::mat4 projection;
        projection = glm::perspective(glm::radians(camera.Zoom), (GLfloat)WIDTH / (GLfloat)HEIGHT,0.1f, 100.0f);
        GLint projectionLoc = glGetUniformLocation(ourShader.Program(), "projection");
        glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
 
        glDrawArrays(GL_POINTS, 0,pointCount);
        glfwSwapBuffers(window);
    }
    // Properly de-allocate all resources once they've outlived their purpose
    glDeleteVertexArrays(1, &VAO);
    glDeleteBuffers(1, &VBO);
    // Terminate GLFW, clearing any resources allocated by GLFW.
    glfwTerminate();
    return 0;
}
 
// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
 
    if (action == GLFW_PRESS)
        keys[key] = true;
    else if (action == GLFW_RELEASE)
        keys[key] = false;
 
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
    if (key == GLFW_KEY_UP && action == GLFW_PRESS)
    {
        if (mix < 1.0f)
        {
            mix = mix + 0.1;
        }
    }
    
    if (key == GLFW_KEY_DOWN && action == GLFW_PRESS)
 
    {
        if (mix > 0.0f)
        {
            mix = mix - 0.1;
        }
    }
    /*GLfloat cameraSpeed = 0.05f;
    if (key == GLFW_KEY_W)
        cameraPos += cameraSpeed * cameraFront;
    if (key == GLFW_KEY_S)
        cameraPos -= cameraSpeed * cameraFront;
    if (key == GLFW_KEY_A)
        cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (key == GLFW_KEY_D)
        cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;*/
 
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mode)
{
    if (action == GLFW_PRESS)
        buttons[button] = true;
    else if (action == GLFW_RELEASE)
        buttons[button] = false;
    
 
}
void do_movement()
{
    // 摄像机控制
    GLfloat cameraSpeed = 5.0f * deltaTime;
    //GLfloat cameraSpeed = 0.1f;
    
    if (keys[GLFW_KEY_W])
        camera.ProcessKeyboard(Camera_Movement(0), deltaTime);
    //cameraPos += cameraSpeed * cameraFront;
    if (keys[GLFW_KEY_S])
        camera.ProcessKeyboard(Camera_Movement(1), deltaTime);
    //cameraPos -= cameraSpeed * cameraFront;
    if (keys[GLFW_KEY_A])
        camera.ProcessKeyboard(Camera_Movement(2), deltaTime);
    //cameraPos -= glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
    if (keys[GLFW_KEY_D])
        camera.ProcessKeyboard(Camera_Movement(3), deltaTime);
    //cameraPos += glm::normalize(glm::cross(cameraFront, cameraUp)) * cameraSpeed;
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
    
        if (firstMouse)
        {
            lastX = xpos;
            lastY = ypos;
            firstMouse = false;
        }
        
 
            GLfloat xoffset = xpos - lastX;
            GLfloat yoffset = lastY - ypos;
            lastX = xpos;
            lastY = ypos;
        
 
            if (buttons[GLFW_MOUSE_BUTTON_LEFT])
            {
                GLfloat sensitivity = 0.05;
                camera.ProcessMouseMovement(xoffset, yoffset);
            }
    
}
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
{
    
    camera.ProcessMouseScroll(yoffset);
    
}
最后显示的点云如图所示:
OPENGL+点云可视化

zhuan:https://blog.csdn.net/qq_27699037/article/details/90399664