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:
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;
QString axisVShaderSource;
QString axisFShaderSource;
GLuint axisProgramID;
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;
};
#endif
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;
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()
{
initializeOpenGLFunctions();
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);
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()
{
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, 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);
}