之前的文章写了如何在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
#include
#include
#include
using namespace std;
namespace CCLib
{
class Octree;
class PointCloud
{
public:
PointCloud();
~PointCloud();
typedef std::vector 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<= 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(static_cast(maxDD)* (1.0 + enlargeFactor));
//build corresponding 'square' box
{
CCVector3 dd(maxDD, maxDD, maxDD);
CCVector3 md = dimMax + dimMin;
dimMin = (md - dd) * static_cast(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::
#ifndef Tuple_H
#define Tuple_H
#include
template 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 Tuple3ub;
typedef Tuple3 Tuple3s;
typedef Tuple3 Tuple3i;
typedef Tuple3 Tuple3ui;
template class Vector3 :public Tuple3
{
public:
using Tuple3::x;
using Tuple3::y;
using Tuple3::z;
using Tuple3::u;
inline Vector3() : Tuple3() {}
inline Vector3(Type _a, Type _b, Type _c) : Tuple3(_a, _b, _c) {}
inline explicit Vector3(const Type P[]) : Tuple3(P) {}
inline Vector3(const Vector3& v) : Tuple3(v) {}
static inline Vector3 fromArray(const int a[3]) { return Vector3(static_cast(a[0]), static_cast(a[1]), static_cast(a[2])); }
//! Constructor from a float array
static inline Vector3 fromArray(const float a[3]) { return Vector3(static_cast(a[0]), static_cast(a[1]), static_cast(a[2])); }
//! Constructor from a double array
static inline Vector3 fromArray(const double a[3]) { return Vector3(static_cast(a[0]), static_cast(a[1]), static_cast(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(x)*x + static_cast(y)*y + static_cast(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 CCVector3;
//! Double 3D Vector
typedef Vector3 CCVector3d;
//2D Vector
//! 2D Vector
template 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 CCVector2;
//! Int 2D Vector
typedef Vector2Tpl CCVector2i;
#endif
最后重点来了,在main函数里面实现点云的可视化,根据learnopengl的相关教程,定义了一个相机类Camera.h:
#pragma once
// Std. Includes
#include
// GL Includes
#include
#include
#include
// 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
#include
// GLEW
#define GLEW_STATIC
#include
// GLFW
#include
//GLM
#include
#include
#include
// Other Libs
#include
// Other includes
#include "Shader.h"
#include "Camera.h"
//pointCloud
#include "PointCloud.h"
#include
#include
#include "Octree.h"
#include "Neighborhood.h"
#include
#include "Tuple.h"
#include "triangle.h"
#ifdef SINGLE
#define REAL float
#else /* not SINGLE */
#define REAL double
#endif /* not SINGLE */
#include
#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::vectorvertice;
//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);
}
最后显示的点云如图所示:
笔者在实验时,卡在坐标变换那儿好久,有兴趣的同学门可以尝试以下