Skip to content
Snippets Groups Projects
Commit e3f0a1e6 authored by ganthern's avatar ganthern
Browse files

add kd-tree & kd-tree-mesh

add camera panning with right click
add zoom with scroll wheel
parent aabb86bb
No related branches found
No related tags found
No related merge requests found
Showing
with 10562 additions and 202 deletions
......@@ -31,7 +31,7 @@ namespace Cg{
CgSplatEvent = 0x0001000,
CgPickRayEvent = 0x0002000,
// unused, may be changed to whatever
CgSomeSpecialEvent3 = 0x0004000,
CgKdTreeEvent = 0x0004000,
CgSomeSpecialEvent4 = 0x0008000,
CgEventGroup1 = 0x000f000,
......
Source diff could not be displayed: it is too large. Options to address this: view the blob.
#include "CgKdTreeEvent.h"
CgBaseEvent* CgKdTreeEvent::clone()
{
return new CgKdTreeEvent(m_type, m_tree_display_depth);
}
Cg::EventType CgKdTreeEvent::getType()
{
return m_type;
}
std::ostream& operator<<(std::ostream& os,const CgKdTreeEvent& e)
{
os << "CgKdTreeEvent: display depth of " << e.m_tree_display_depth << " ";
return os;
}
CgKdTreeEvent::CgKdTreeEvent(Cg::EventType type, int tree_display_depth)
{
m_type=type;
m_tree_display_depth=tree_display_depth;
}
CgKdTreeEvent::CgKdTreeEvent()
{
m_type=Cg::CgKdTreeEvent;
}
#ifndef CG_KDTREEEVENT
#define CG_KDTREEEVENT
#include "../CgBase/CgBaseEvent.h"
#include "../CgBase/CgEnums.h"
#include <iostream>
#include <string>
class CgKdTreeEvent : public CgBaseEvent
{
public:
CgKdTreeEvent();
CgKdTreeEvent(Cg::EventType type, int tree_display_depth);
~CgKdTreeEvent(){};
//inherited
Cg::EventType getType();
CgBaseEvent* clone();
// CgKdTreeEvent
int displayDepth(){return m_tree_display_depth;}
friend std::ostream& operator <<(std::ostream& os, const CgKdTreeEvent& e);
private:
Cg::EventType m_type;
// -1 none, 0 all, otherwise number of levels.
int m_tree_display_depth;
};
#endif // CG_KDTREEEVENT
\ No newline at end of file
......@@ -5,8 +5,6 @@
#include "../CgBase/CgBaseEvent.h"
#include "../CgBase/CgEnums.h"
#include <iostream>
#include <string>
......@@ -27,17 +25,6 @@ public:
private:
Cg::EventType m_type;
bool m_show_pickray;
};
#endif // CGLOADOBJFILEEVENT
......@@ -123,8 +123,7 @@ void CgQtGLRenderWidget::render(CgBaseRenderableObject* obj,glm::mat4 mv_matrix,
setUniformValue("uselighting",(int)m_lighting);
if(m_gl_buffer_objects.find(obj->getID())!=m_gl_buffer_objects.end())
{
if(m_gl_buffer_objects.find(obj->getID()) != m_gl_buffer_objects.end()) {
m_gl_buffer_objects[obj->getID()]->draw(obj);
}
......
......@@ -12,6 +12,7 @@
#include "../CgEvents/CgTrackballEvent.h"
#include "../CgEvents/CgSplatEvent.h"
#include "../CgEvents/CgPickRayEvent.h"
#include "../CgEvents/CgKdTreeEvent.h"
#include "../CgEvents/CgWheelEvent.h"
#include <QSlider>
......@@ -51,14 +52,14 @@ CgQtGui::CgQtGui(CgQtMainApplication *mw)
QHBoxLayout *container = new QHBoxLayout;
QWidget *opt = new QWidget;
createOptionPanelExample1(opt);
QWidget *kdTreeOptionsWidget = new QWidget;
createKdTreeOptionPanel(kdTreeOptionsWidget);
QWidget *otheropt = new QWidget;
createOptionPanelExample2(otheropt);
QTabWidget* m_tabs = new QTabWidget();
m_tabs->addTab(opt,"&My Tab1");
m_tabs->addTab(kdTreeOptionsWidget,"&k-d tree");
m_tabs->addTab(otheropt,"&My Tab2");
container->addWidget(m_tabs);
......@@ -102,7 +103,6 @@ CgQtGui::CgQtGui(CgQtMainApplication *mw)
show_pickray->setCheckable(true);
show_pickray->setChecked(false);
QActionGroup* polygonmode_group = new QActionGroup(this);
polygonmode_group->setExclusive(true);
......@@ -118,23 +118,16 @@ CgQtGui::CgQtGui(CgQtMainApplication *mw)
filled->setCheckable(true);
filled->setChecked(false);
polygonmode_group->addAction(points);
polygonmode_group->addAction(lines);
polygonmode_group->addAction(filled);
// todo: Add Quit-Action
m_menuBar->addMenu( file_menu );
m_menuBar->addMenu( settings_menu );
m_menuBar->addMenu( polygon_mode_menu );
m_mainWindow->setMenuBar(m_menuBar);
}
QSlider *CgQtGui::createSlider()
......@@ -148,57 +141,44 @@ QSlider *CgQtGui::createSlider()
return slider;
}
void CgQtGui::createOptionPanelExample1(QWidget* parent)
void CgQtGui::createKdTreeOptionPanel(QWidget* parent)
{
QVBoxLayout *tab1_control = new QVBoxLayout();
/* checkbox for toggling the plane display*/
/*Example for using a label */
QLabel *options_label = new QLabel("Options");
tab1_control->addWidget(options_label);
options_label->setAlignment(Qt::AlignCenter);
display_kd_tree_checkbox = new QCheckBox("display k-d tree planes");
display_kd_tree_checkbox->setCheckable(true);
display_kd_tree_checkbox->setChecked(false);
connect(display_kd_tree_checkbox, SIGNAL( clicked() ), this, SLOT(slotKdDepthSpinboxChanged()) );
tab1_control->addWidget(display_kd_tree_checkbox);
/*Example for using a spinbox */
mySpinBox1 = new QSpinBox();
tab1_control->addWidget(mySpinBox1);
mySpinBox1->setMinimum(1);
mySpinBox1->setMaximum(50);
mySpinBox1->setValue(3);
// mySpinBox1->setSuffix(" suffix");
// mySpinBox1->setPrefix("Prefix: ");
connect(mySpinBox1, SIGNAL(valueChanged(int) ), this, SLOT(slotMySpinBox1Changed()) );
tab1_control->addWidget(mySpinBox1);
/*Example for using a checkbox */
myCheckBox1 = new QCheckBox("enable Option 1");
myCheckBox1->setCheckable(true);
myCheckBox1->setChecked(false);
connect(myCheckBox1, SIGNAL( clicked() ), this, SLOT(slotMyCheckBox1Changed()) );
tab1_control->addWidget(myCheckBox1);
/* label */
QLabel *max_depth_label = new QLabel("depth limit (0 for none):");
tab1_control->addWidget(max_depth_label);
max_depth_label->setAlignment(Qt::AlignTop);
max_depth_label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
/*Example for using a button */
QPushButton* myButton1 = new QPushButton("&drueck mich");
tab1_control->addWidget(myButton1);
connect(myButton1, SIGNAL( clicked() ), this, SLOT(slotMyButton1Pressed()) );
/*Example for using a spinbox */
max_kd_depth_spinbox = new QSpinBox();
tab1_control->addWidget(max_kd_depth_spinbox);
max_kd_depth_spinbox->setMinimum(0);
max_kd_depth_spinbox->setMaximum(50);
max_kd_depth_spinbox->setValue(0);
connect(max_kd_depth_spinbox, SIGNAL(valueChanged(int) ), this, SLOT(slotKdDepthSpinboxChanged()) );
tab1_control->addWidget(max_kd_depth_spinbox);
max_kd_depth_spinbox->setAlignment(Qt::AlignTop);
max_kd_depth_spinbox->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
// fill space
QWidget *filler = new QWidget();
tab1_control->addWidget(filler);
filler->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
parent->setLayout(tab1_control);
}
void CgQtGui::createOptionPanelExample2(QWidget* parent)
......@@ -244,34 +224,25 @@ void CgQtGui::createOptionPanelExample2(QWidget* parent)
}
void CgQtGui::slotButtonGroupSelectionChanged()
{
}
void CgQtGui::slotMySpinBox1Changed()
{
}
void CgQtGui::slotMyCheckBox1Changed()
{
void CgQtGui::slotKdDepthSpinboxChanged() {
int depth = display_kd_tree_checkbox->isChecked()
? max_kd_depth_spinbox->value()
: -1;
CgBaseEvent* e = new CgKdTreeEvent(Cg::CgKdTreeEvent, depth);
notifyObserver(e);
m_glRenderWidget->redraw();
}
void CgQtGui::slotLoadPointCloudFile()
{
QString file= QFileDialog::getOpenFileName(this, tr("Open Obj-File"),"",tr("Model Files (*.obj)"));
CgBaseEvent* e = new CgLoadPointCloudEvent(Cg::CgLoadPointCloudEvent, file.toStdString());
notifyObserver(e);
}
......@@ -279,34 +250,22 @@ void CgQtGui::slotLoadPointCloudFile()
void CgQtGui::slotSplatting()
{
m_use_spats=!m_use_spats;
CgBaseEvent* e = new CgSplatEvent(Cg::CgSplatEvent, m_use_spats);
notifyObserver(e);
}
void CgQtGui::slotPickRay()
{
m_show_pickray=!m_show_pickray;
CgBaseEvent* e = new CgPickRayEvent(Cg::CgPickRayEvent, m_show_pickray);
notifyObserver(e);
}
void CgQtGui::slotLoadMeshFile()
{
QString file= QFileDialog::getOpenFileName(this, tr("Open Obj-File"),"",tr("Model Files (*.obj)"));
CgBaseEvent* e = new CgLoadMeshEvent(Cg::CgLoadMeshEvent, file.toStdString());
notifyObserver(e);
}
......@@ -317,13 +276,6 @@ void CgQtGui::slotTrackballChanged()
notifyObserver(e);
}
void CgQtGui::slotMyButton1Pressed()
{
std::cout << "button 1 pressed " << std::endl;
}
void CgQtGui::mouseEvent(QMouseEvent* event)
{
......@@ -344,6 +296,15 @@ void CgQtGui::mouseEvent(QMouseEvent* event)
notifyObserver(e);
}
if(event->type() == QEvent::MouseButtonRelease)
{
CgBaseEvent* e = new CgMouseEvent(Cg::CgMouseButtonRelease,
glm::vec2(event->localPos().x() ,event->localPos().y()),
(Cg::MouseButtons)event->button());
notifyObserver(e);
}
if(event->type()==QEvent::MouseMove)
{
CgBaseEvent* e= new CgMouseEvent(Cg::CgMouseMove,
......
......@@ -87,51 +87,42 @@ private:
CgQtGuiEventHandler* m_event_handler;
QWidget* m_option_panel_ex1;
QWidget* m_option_panel_ex2;
QWidget* m_option_panel_ex3;
QWidget* m_option_panel_ex4;
QWidget* m_option_panel_ex5;
/* example for usage of qt gui elements, feel free to add what you like */
void createOptionPanelExample1(QWidget* panel);
/* kdtree panel */
QWidget* m_option_panel_ex1;
void createKdTreeOptionPanel(QWidget* panel);
QSpinBox* max_kd_depth_spinbox;
QCheckBox* display_kd_tree_checkbox;
/* additional stuff */
void createOptionPanelExample2(QWidget* panel);
QButtonGroup* myButtonGroup;
QCheckBox* myCheckBox1;
QSpinBox* mySpinBox1;
bool m_use_spats;
bool m_show_pickray;
private slots:
/* slots to catch events directly from renderer */
void mouseEvent(QMouseEvent* event);
void wheelEvent(QWheelEvent* event);
void viewportChanged(int,int);
void slotTrackballChanged();
/* slots example qt gui elements */
void slotMySpinBox1Changed();
void slotMyCheckBox1Changed();
void slotMyButton1Pressed();
/* kd tree options slot */
void slotKdDepthSpinboxChanged();
/* additional stuff*/
void slotButtonGroupSelectionChanged();
void slotLoadMeshFile();
void slotLoadPointCloudFile();
void slotSplatting();
void slotPickRay();
};
#endif
#ifndef CGAABB_H
#define CGAABB_H
#include <glm/glm.hpp>
struct CgAABB {
glm::vec3 position;
glm::vec3 extent;
};
#endif // CGAABB_H
\ No newline at end of file
#include "CgKdTree.h"
// nodes
CgKdTree::TreeNode::TreeNode(glm::vec3 point) {
m_point = point;
m_lower = nullptr;
m_higher = nullptr;
}
CgKdTree::TreeNode::~TreeNode() {
if(m_lower) delete m_lower;
if(m_higher) delete m_higher;
}
// kdtree API
CgKdTree::CgKdTree() {
}
CgKdTree::~CgKdTree() {
m_points.clear();
if(m_root) delete m_root;
}
// builds a kd-tree out of the glm::vec3 between
// begin (inclusive) and end (exklusive)
CgKdTree::TreeNode* CgKdTree::buildTree(glm::vec3* begin, glm::vec3* end, int depth) {
auto half_size = (end - begin) / 2;
if(begin == end) { // array is empty
return nullptr;
} else if(half_size == 0) { // there is one element
return new CgKdTree::TreeNode(*begin);
} else { // more than one element!
// partially sort and ensure median element is in the middle (runs in O(n))
// about 4x faster on tyra.obj than std::sort
std::nth_element(begin, begin + half_size, end, [=](glm::vec3 a, glm::vec3 b) {
return a[depth % 3] < b[depth % 3];
});
// create node with median point
auto node = new CgKdTree::TreeNode(begin[half_size]);
// split array in two (excluding median) and recurse
node->m_lower = buildTree(begin, begin + half_size, depth + 1);
node->m_higher = buildTree(begin + half_size + 1, end, depth + 1);
return node;
}
}
void CgKdTree::init(std::vector<glm::vec3>& points) {
// copy points for now.
m_points = points;
m_root = buildTree(&points.front(), &(*(points.end() - 1)), 0);
}
std::vector<int> CgKdTree::getNearestNeighbors(int current_point, unsigned int k) {
std::vector<int> erg(k);
std::iota(erg.begin(), erg.end(), 0);
return erg;
}
// return the locations of the split planes in a breadth-first manner
std::vector<double> CgKdTree::getSplits() {
std::vector<double> erg;
std::queue<CgKdTree::TreeNode*> q;
if(m_root == nullptr) return erg;
int depth = 0;
q.push(m_root);
while(!q.empty()) {
int level_count = q.size();
for(int i = 0; i < level_count; i++) {
CgKdTree:TreeNode* curr = q.front();
erg.push_back(curr->m_point[depth % 3]);
if(curr->m_lower != nullptr) q.push(curr->m_lower);
if(curr->m_higher != nullptr) q.push(curr->m_higher);
q.pop();
}
depth += 1;
}
return erg;
}
\ No newline at end of file
#ifndef CGKDTREE_H
#define CGKDTREE_H
#include <vector>
#include <queue>
#include <glm/glm.hpp>
#include <string>
#include <iostream>
#include <algorithm>
#include <numeric>
class CgKdTree
{
public:
CgKdTree();
~CgKdTree();
void init(std::vector<glm::vec3>& points);
std::vector<int> getNearestNeighbors(int current_point,unsigned int k);
std::vector<double> getSplits();
private:
class TreeNode
{
private:
TreeNode(glm::vec3 point);
~TreeNode();
glm::vec3 m_point;
TreeNode* m_lower;
TreeNode* m_higher;
friend class CgKdTree;
};
private:
CgKdTree::TreeNode* m_root;
CgKdTree::TreeNode* buildTree(glm::vec3* begin, glm::vec3* end, int depth);
std::vector<glm::vec3> m_points;
};
#endif // CGKDTREE_H
\ No newline at end of file
......@@ -56,6 +56,10 @@ void CgPointCloud::calculateSplatOrientations()
}
CgKdTree* CgPointCloud::getKdTree() {
return &m_kd_tree;
}
void CgPointCloud::init( std::string filename, bool cheat_normals)
{
......@@ -70,7 +74,8 @@ void CgPointCloud::init( std::string filename, bool cheat_normals)
ObjLoader loader;
loader.load(filename);
loader.getPositionData(m_vertices);
m_kd_tree.init(m_vertices);
//run_timed(10, [=]{m_kd_tree.init(m_vertices);});
// do this for cheating with the normals
// you need to replace this by a normal estimation algorithm
......@@ -94,7 +99,7 @@ void CgPointCloud::init( std::string filename, bool cheat_normals)
// generates blue dots on the tail of the bunny
unsigned int k=50;
std::vector<int> neighbors = getNearestNeighbors(0,k);
std::vector<int> neighbors = m_kd_tree.getNearestNeighbors(0,k);
for(unsigned int i=0;i<k;i++)
{
......@@ -147,20 +152,40 @@ glm::vec3 CgPointCloud::getPerpendicularVector(glm::vec3 arg)
return glm::normalize(glm::vec3(-arg[1],arg[0],0.0));
}
const glm::vec3 CgPointCloud::getCenter() const
{
glm::vec3 center(0.);
for(unsigned int i=0;i<m_vertices.size();i++)
{
for(unsigned int i=0;i<m_vertices.size();i++) {
center+=m_vertices[i];
}
center/=(double)m_vertices.size();
return center;
}
// returns the point clouds AABB
const CgAABB CgPointCloud::getAABB() const {
double max_x = -std::numeric_limits<double>::infinity();
double max_y = -std::numeric_limits<double>::infinity();
double max_z = -std::numeric_limits<double>::infinity();
double min_x = std::numeric_limits<double>::infinity();
double min_y = std::numeric_limits<double>::infinity();
double min_z = std::numeric_limits<double>::infinity();
CgAABB aabb;
for(unsigned int i=0; i < m_vertices.size(); i++) {
glm::vec3 curr = m_vertices[i];
max_x = max_x < curr[0] ? curr[0] : max_x;
min_x = min_x > curr[0] ? curr[0] : min_x;
max_y = max_y < curr[1] ? curr[1] : max_y;
min_y = min_y > curr[1] ? curr[1] : min_y;
max_z = max_z < curr[2] ? curr[2] : max_z;
min_z = min_z > curr[2] ? curr[2] : min_z;
}
aabb.position = glm::vec3((max_x + min_x) * 0.5, (max_y + min_y) * 0.5, (max_z + min_z) * 0.5);
aabb.extent = glm::vec3((max_x - min_x) * 0.5, (max_y - min_y) * 0.5, (max_z - min_z) * 0.5);
return aabb;
}
const std::vector<glm::vec2>& CgPointCloud::getSplatScalings() const
{
return m_splat_scaling;
......
......@@ -2,9 +2,12 @@
#define CGPOINTCLOUD_H
#include <vector>
#include <limits>
#include <glm/glm.hpp>
#include <string>
#include "CgBase/CgBasePointCloud.h"
#include "CgSceneGraph/CgKdTree.h"
#include "CgSceneGraph/CgAABB.h"
class CgPointCloud : public CgBasePointCloud
{
......@@ -42,9 +45,14 @@ public:
// read a dataset from file, can cheat the normals, i.e read the mormals from file
void init( std::string filename, bool cheat_normals=false);
CgKdTree* getKdTree();
// the center of gravity of the object, for rendering
const glm::vec3 getCenter() const;
// returns the point clouds AABB
const CgAABB getAABB() const;
private:
// the following demonstration methods have to be replaced by your own calculations
......@@ -62,6 +70,7 @@ private:
std::vector<glm::vec3> m_vertices;
std::vector<glm::vec3> m_vertex_normals;
std::vector<glm::vec3> m_vertex_colors;
CgKdTree m_kd_tree;
// indices of vertices for which a splat will be rendered
std::vector<unsigned int> m_splat_indices;
......
#include "CgQuad.h"
#include "CgBase/CgEnums.h"
CgQuad::CgQuad():
m_type(Cg::Polyline),
m_id(43)
{
}
CgQuad::CgQuad(int id):
m_type(Cg::Polyline),
m_id(id),
m_linewidth(1.0)
{
}
CgQuad::CgQuad(
int id,
glm::vec3 position,
glm::vec3 span1,
glm::vec3 span2
) : m_type(Cg::Polyline), m_id(id), m_linewidth(1.0) {
m_vertices.clear();
glm::vec3 normal = glm::normalize(glm::cross(span1, span2));
glm::vec3 corners[6] = {
position + span1,
position + span2,
position - span1,
position - span2,
position + span1,
position - span1,
};
std::vector<glm::vec3> corner_vec(corners, corners + sizeof(corners)/sizeof(corners[0]));
m_vertices = corner_vec;
for(unsigned int i=0;i<m_vertices.size();i++) {
m_vertex_colors.push_back(normal);
}
}
CgQuad::~CgQuad()
{
m_vertices.clear();
m_vertex_colors.clear();
}
const std::vector<glm::vec3>& CgQuad::getVertices() const {return m_vertices;}
const std::vector<glm::vec3>& CgQuad::getVertexColors() const{return m_vertex_colors;}
unsigned int CgQuad::getLineWidth() const {return m_linewidth;}
\ No newline at end of file
#ifndef CGRAY_H
#define CGRAY_H
#ifndef CG_Quad
#define CG_Quad
#include <vector>
#include <glm/glm.hpp>
#include <string>
#include "CgBase/CgBasePolyline.h"
class CgRay: public CgBasePolyline
// four vertices arranged in a rectangle,
//rendered as a wireframe
class CgQuad : public CgBasePolyline
{
public:
CgRay();
CgQuad();
CgQuad(int);
CgQuad(int, glm::vec3 position, glm::vec3 span1, glm::vec3 span2);
~CgQuad();
//inherited from CgBaseRenderableObject
Cg::ObjectType getType() const;
......@@ -21,6 +27,18 @@ public:
const std::vector<glm::vec3>& getVertexColors() const;
unsigned int getLineWidth() const;
private:
const Cg::ObjectType m_type;
const unsigned int m_id;
std::vector<glm::vec3> m_vertices;
std::vector<glm::vec3> m_vertex_colors;
unsigned int m_linewidth;
};
#endif // CGRAY_H
inline Cg::ObjectType CgQuad::getType() const {return m_type;}
inline unsigned int CgQuad::getID() const {return m_id;}
#endif // CG_Quad
\ No newline at end of file
......@@ -11,9 +11,11 @@
#include "CgEvents/CgTrackballEvent.h"
#include "CgEvents/CgSplatEvent.h"
#include "CgEvents/CgPickRayEvent.h"
#include "CgEvents/CgKdTreeEvent.h"
#include "CgBase/CgBaseRenderer.h"
#include "CgPointCloud.h"
#include "CgPolyLine.h"
#include "CgQuad.h"
#include "CgTriangleMesh.h"
#include <iostream>
#include <glm/gtc/matrix_transform.hpp>
......@@ -28,12 +30,10 @@ using namespace Eigen;
CgSceneControl::CgSceneControl()
{
m_pointcloud=nullptr;
m_current_transformation=glm::mat4(1.);
resetTransform();
m_lookAt_matrix= glm::lookAt(glm::vec3(0.0,0.0,1.0),glm::vec3(0.0,0.0,0.0),glm::vec3(0.0,1.0,0.0));
m_proj_matrix= glm::mat4x4(glm::vec4(1.792591, 0.0, 0.0, 0.0), glm::vec4(0.0, 1.792591, 0.0, 0.0), glm::vec4(0.0, 0.0, -1.0002, -1.0), glm::vec4(0.0, 0.0, -0.020002, 0.0));
m_trackball_rotation=glm::mat4(1.);
m_select_ray=NULL;
m_disc = new CgTriangleMesh(78);
m_pointcloud = NULL;
......@@ -41,6 +41,15 @@ CgSceneControl::CgSceneControl()
m_triangle_mesh= NULL;
m_show_splats=false;
m_show_pickray=false;
m_is_dragging=false;
m_drag_center=glm::vec2(0.0,0.0);
}
void CgSceneControl::resetTransform() {
m_current_translation = glm::mat4(1.0);
m_current_scale = glm::mat4(1.0);
m_current_rotation = glm::mat4(1.0);
m_current_transformation = glm::mat4(1.0);
}
......@@ -89,7 +98,7 @@ void CgSceneControl::calculatePickRay(double x, double y)
//construct current modelview matrix by hand, since there is no scenegraph
m_current_transformation = glm::translate(m_current_transformation,-m_center);
glm::mat4 mv_matrix = m_lookAt_matrix * m_trackball_rotation* m_current_transformation ;
glm::mat4 mv_matrix = m_lookAt_matrix * m_current_rotation* m_current_transformation ;
m_current_transformation = glm::translate(m_current_transformation,m_center);
......@@ -107,7 +116,6 @@ void CgSceneControl::calculatePickRay(double x, double y)
m_select_ray = new CgPolyLine(33,pointlist);
m_renderer->init(m_select_ray);
m_renderer->redraw();
}
......@@ -159,16 +167,103 @@ void CgSceneControl::calculateSingularValueDecomposition()
std::cout << C_plus << std::endl;
}
// deletes the old kd-tree-mesh and creates a new one
// down to max_depth
void CgSceneControl::createKdTreeViz(int max_depth) {
// clear old quads
for(int i = 0; i < m_kd_tree_mesh.size(); i++) delete m_kd_tree_mesh[i];
m_kd_tree_mesh.clear();
// recalculate mesh
max_depth = max_depth == 0 ? 7 : max_depth;
if(m_pointcloud != nullptr && max_depth != -1) {
std::vector<double> splits = m_pointcloud->getKdTree()->getSplits();
std::queue<CgAABB> aabb_queue;
aabb_queue.push(m_pointcloud->getAABB());
unsigned int index = 0;
unsigned int depth = 0;
while(index < splits.size() && depth < max_depth) {
CgAABB current_aabb = aabb_queue.front();
double current_split = splits[index];
unsigned int current_axis = depth % 3;
unsigned int next_axis = (depth + 1) % 3;
aabb_queue.pop();
// create quad
glm::vec3 span1 = current_aabb.extent;
glm::vec3 span2 = current_aabb.extent;
glm::vec3 quad_position = current_aabb.position;
quad_position[current_axis] = current_split;
span1[current_axis] = 0.0;
span2[current_axis] = 0.0;
span2[next_axis] = -span2[next_axis];
CgQuad* new_quad = new CgQuad(34 + index, quad_position, span1, span2);
m_renderer->init(new_quad);
m_kd_tree_mesh.push_back(new_quad);
// push children of current aabb
glm::vec3 new_position1 = current_aabb.position;
glm::vec3 new_position2 = current_aabb.position;
double delta = current_split - current_aabb.position[current_axis];
new_position1[current_axis] -= (current_aabb.extent[current_axis] - delta) * 0.5;
new_position2[current_axis] += (current_aabb.extent[current_axis] + delta) * 0.5;
glm::vec3 new_extent1 = current_aabb.extent;
glm::vec3 new_extent2 = current_aabb.extent;
new_extent1[current_axis] += delta;
new_extent2[current_axis] -= delta;
new_extent1[current_axis] *= .5;
new_extent2[current_axis] *= .5;
aabb_queue.push({new_position1, new_extent1});
aabb_queue.push({new_position2, new_extent2});
index += 1;
if(index >= ((0x01 << (depth + 1)) - 1)) depth += 1;
}
}
}
void CgSceneControl::handleEvent(CgBaseEvent* e)
{
// any kind of MouseEvents can be checked via CgEvent::CgMouseEvent a
// see CgEvent enums in CgEnums.h
if(e->getType() & Cg::CgMouseEvent)
if(e->getType() & Cg::CgMouseButtonPress)
{
CgMouseEvent* ev = (CgMouseEvent*)e;
if(ev->button()== Cg::RightButton)
calculatePickRay((double)ev->x(),(double)ev->y());
else if(ev->button() == Cg::MiddleButton)
{
m_drag_center = glm::vec2((double)ev->x(), (double)ev->y());
m_is_dragging = true;
}
}
if(e->getType() & Cg::CgMouseButtonRelease)
{
CgMouseEvent* ev = (CgMouseEvent*) e;
if(ev->button() == Cg::MiddleButton)
{
m_is_dragging = false;
}
}
if(e->getType() & Cg::CgMouseMove)
{
if(!m_is_dragging) return;
CgMouseEvent* ev = (CgMouseEvent*) e;
glm::vec2 new_center = glm::vec2(ev->x(), ev->y());
glm::vec3 delta = glm::vec3(
new_center.x - m_drag_center.x,
m_drag_center.y - new_center.y,
0.0
);
m_drag_center = new_center;
glm::vec4 curr_trans = m_current_translation[3];
glm::vec3 translation = 0.01 * delta + glm::vec3(curr_trans.x, curr_trans.y, curr_trans.z);
m_current_translation = glm::translate(glm::mat4(1.0), translation);
m_renderer->redraw();
}
if(e->getType() & Cg::CgMouseWheel)
......@@ -176,9 +271,7 @@ void CgSceneControl::handleEvent(CgBaseEvent* e)
CgWheelEvent* ev = (CgWheelEvent*)e;
//scaling of scene, i.e. of the one single object
float scaleFactor = 1.0f + 0.01f * ev->numDegrees();
glm::mat4 scalemat = glm::mat4(1.);
scalemat = glm::scale(scalemat, glm::vec3(scaleFactor,scaleFactor,scaleFactor));
m_current_transformation = m_current_transformation * scalemat;
m_current_scale = m_current_scale * glm::scale(glm::mat4(1.), glm::vec3(scaleFactor));
m_renderer->redraw();
}
......@@ -186,7 +279,7 @@ void CgSceneControl::handleEvent(CgBaseEvent* e)
{
CgTrackballEvent* ev = (CgTrackballEvent*)e;
m_trackball_rotation=ev->getRotationMatrix();
m_current_rotation = ev->getRotationMatrix();
m_renderer->redraw();
}
......@@ -209,6 +302,12 @@ void CgSceneControl::handleEvent(CgBaseEvent* e)
calculateSingularValueDecomposition();
}
if(ev->text() == "c")
{
resetTransform();
m_renderer->redraw();
}
if(ev->text()=="+")
{
//scaling of scene, i.e. of the one single object
......@@ -245,6 +344,12 @@ void CgSceneControl::handleEvent(CgBaseEvent* e)
m_renderer->redraw();
}
// build a wireframe 'mesh' to display the kd-tree
if(e->getType() & Cg::CgKdTreeEvent) {
CgKdTreeEvent* ev = (CgKdTreeEvent*)e;
createKdTreeViz(ev->displayDepth());
m_renderer->redraw();
}
if(e->getType() & Cg::WindowResizeEvent)
{
......@@ -316,7 +421,6 @@ void CgSceneControl::handleEvent(CgBaseEvent* e)
}
}
// delete event
delete e;
}
......@@ -366,47 +470,45 @@ void CgSceneControl::renderObjects()
m_renderer->setUniformValue("shininess",27.8974f);
m_current_transformation = m_current_scale * m_current_translation * m_current_rotation ;
if(m_triangle_mesh!=NULL)
{
if(m_triangle_mesh!=NULL) {
m_current_transformation = glm::translate(m_current_transformation,-m_center);
glm::mat4 mv_matrix = m_lookAt_matrix * m_trackball_rotation* m_current_transformation ;
glm::mat4 mv_matrix = m_lookAt_matrix * m_current_transformation ;
m_renderer->render(m_triangle_mesh, mv_matrix, m_proj_matrix);
m_current_transformation = glm::translate(m_current_transformation,m_center);
}
if((m_pointcloud!=NULL)&&(!m_show_splats))
{
if((m_pointcloud!=NULL)&&(!m_show_splats)) {
m_current_transformation = glm::translate(m_current_transformation,-m_center);
glm::mat4 mv_matrix = m_lookAt_matrix * m_trackball_rotation* m_current_transformation ;
glm::mat4 mv_matrix = m_lookAt_matrix * m_current_transformation ;
m_renderer->render(m_pointcloud, mv_matrix, m_proj_matrix);
m_current_transformation = glm::translate(m_current_transformation,m_center);
}
if((m_select_ray!=NULL)&&(m_show_pickray))
{
if((m_select_ray!=NULL)&&(m_show_pickray)) {
m_current_transformation = glm::translate(m_current_transformation,-m_center);
glm::mat4 mv_matrix = m_lookAt_matrix * m_trackball_rotation* m_current_transformation ;
glm::mat4 mv_matrix = m_lookAt_matrix * m_current_transformation;
m_renderer->render(m_select_ray, mv_matrix, m_proj_matrix);
m_current_transformation = glm::translate(m_current_transformation, m_center);
}
if(m_kd_tree_mesh.size() != 0) {
for(int i = 0; i < m_kd_tree_mesh.size(); i++) {
m_current_transformation = glm::translate(m_current_transformation, -m_center);
glm::mat4 mv_matrix = m_lookAt_matrix * m_current_transformation;
m_renderer->render(m_kd_tree_mesh[i], mv_matrix, m_proj_matrix);
m_current_transformation = glm::translate(m_current_transformation, m_center);
}
}
// you would never ever render splats like this, a splat is never a scenegraph object
// just to have not much effort to show the shape, inefficient rendering!
if((m_pointcloud!=NULL)&&(m_show_splats))
{
if((m_pointcloud!=NULL)&&(m_show_splats)) {
m_renderer->setUniformValue("rendersplats",1);
const std::vector<glm::vec3>& vertex_colors = m_pointcloud->getVertexColors();
//const std::vector<glm::vec3>& vertex_colors = m_pointcloud->getVertexColors();
const std::vector<glm::vec3>& vertices = m_pointcloud->getVertices();
const std::vector<unsigned int>& splat_indices= m_pointcloud->getSplatIndices();
const std::vector<glm::mat4>& orientations = m_pointcloud->getSplatOrientations();
......@@ -414,8 +516,7 @@ void CgSceneControl::renderObjects()
glm::mat4 mv_matrix;
for(unsigned int i=0;i<splat_indices.size();i++)
{
for(unsigned int i=0;i<splat_indices.size();i++) {
//m_renderer->setUniformValue("mycolor",glm::vec4(vertex_colors[splat_indices[i]],1.0));
m_current_transformation = glm::translate(m_current_transformation,-m_center);
......@@ -423,7 +524,7 @@ void CgSceneControl::renderObjects()
m_current_transformation=glm::scale(m_current_transformation,glm::vec3(scalings[splat_indices[i]][0],scalings[splat_indices[i]][1],1.0));
mv_matrix = m_lookAt_matrix * m_trackball_rotation* m_current_transformation ;
mv_matrix = m_lookAt_matrix * m_current_rotation* m_current_transformation ;
if(m_disc!=NULL)
m_renderer->render(m_disc,mv_matrix,m_proj_matrix);
......@@ -435,6 +536,5 @@ void CgSceneControl::renderObjects()
}
}
}
......@@ -3,13 +3,18 @@
#include "CgBase/CgObserver.h"
#include "CgBase/CgBaseSceneControl.h"
#include "CgAABB.h"
#include <glm/glm.hpp>
#include <vector>
#include <queue>
#include <iostream>
class CgBaseEvent;
class CgBaseRenderer;
class CgPointCloud;
class CgTriangleMesh;
class CgPolyLine;
class CgQuad;
class CgSceneControl : public CgObserver, public CgBaseSceneControl
......@@ -26,14 +31,16 @@ private:
// since there is only one object, the select ray is in "bunny"-coordinates
void calculatePickRay(double x, double y);
void resetTransform();
bool m_show_pickray;
bool m_is_dragging;
glm::vec2 m_drag_center;
CgPolyLine* m_select_ray;
std::vector<CgQuad*> m_kd_tree_mesh;
// example: how to calculate an Eigen decomosition of a 3x3 matrix
void calculateEigenDecomposition3x3();
// example: calculate a singular value decomposition an a Moore Penrose inverse of a (n,m)-matrix
void calculateSingularValueDecomposition();
void createKdTreeViz(int max_depth);
// one single Disc used as Object to render the spats (in own local coordinates)
CgTriangleMesh* m_disc;
......@@ -44,15 +51,16 @@ private:
CgTriangleMesh* m_triangle_mesh;
// all the things that you would normally find in a scenegraph
glm::mat4 m_current_rotation;
glm::mat4 m_current_scale;
glm::mat4 m_current_translation;
glm::mat4 m_current_transformation;
glm::mat4 m_trackball_rotation;
glm::mat4 m_lookAt_matrix;
glm::mat4 m_proj_matrix;
glm::vec3 m_center;
// interface for OpenGl Rendering
CgBaseRenderer* m_renderer;
};
#endif // CGSCENECONTROL_H
#ifndef TIMER_H
#define TIMER_H
#include <iostream>
#include <functional>
#include <chrono>
// benchmarking utility
// takes a closure without params that returns void and runs it
// amount times, printing the duration in milliseconds to stdout afterwards
void run_timed(unsigned int amount, std::function<void ()> fn) {
auto t1 = std::chrono::high_resolution_clock::now();
for(int i = 0; i < amount; i++) fn();
auto t2 = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> ms_double = t2 - t1;
std::cout << ms_double.count() << "ms" << std::endl;
}
#endif // TIMER_H
\ No newline at end of file
QT += core gui opengl widgets
TEMPLATE = app
TARGET = PointViewer
QMAKE_CXXFLAGS += -std=c++11
QMAKE_CXXFLAGS += -g -std=c++11
CONFIG += c++11
SOURCES += main.cpp \
CgEvents/CgLoadMeshEvent.cpp \
CgEvents/CgLoadPointCloudEvent.cpp \
CgEvents/CgPickRayEvent.cpp \
CgEvents/CgKdTreeEvent.cpp \
CgEvents/CgSplatEvent.cpp \
CgMath/CgEigenDecomposition3x3.cpp \
CgQtViewer/CGQtGLRenderWidget.cpp \
......@@ -18,12 +19,14 @@ SOURCES += main.cpp \
CgQtViewer/CgQtMainApplication.cpp \
CgSceneGraph/CgPointCloud.cpp \
CgSceneGraph/CgPolyLine.cpp \
CgSceneGraph/CgQuad.cpp \
CgSceneGraph/CgSceneControl.cpp \
CgEvents/CgKeyEvent.cpp \
CgQtViewer/CgQtGlBufferObject.cpp \
CgQtViewer/CgTrackball.cpp \
CgEvents/CgWindowResizeEvent.cpp \
CgSceneGraph/CgTriangleMesh.cpp \
CgSceneGraph/CgKdTree.cpp \
CgUtils/ObjLoader.cpp \
CgEvents/CgTrackballEvent.cpp
......@@ -31,6 +34,7 @@ HEADERS += \
CgEvents/CgLoadMeshEvent.h \
CgEvents/CgLoadPointCloudEvent.h \
CgEvents/CgPickRayEvent.h \
CgEvents/CgKdTreeEvent.h \
CgEvents/CgSplatEvent.h \
CgMath/CgEigenDecomposition3x3.h \
CgMath/Eigen/Core \
......@@ -47,6 +51,7 @@ HEADERS += \
CgQtViewer/CgQtMainApplication.h \
CgSceneGraph/CgPointCloud.h \
CgSceneGraph/CgPolyLine.h \
CgSceneGraph/CgQuad.h \
CgSceneGraph/CgSceneControl.h \
CgEvents/CgKeyEvent.h \
CgBase/CgBaseRenderer.h \
......@@ -60,7 +65,10 @@ HEADERS += \
CgQtViewer/CgTrackball.h \
CgEvents/CgWindowResizeEvent.h \
CgSceneGraph/CgTriangleMesh.h \
CgSceneGraph/CgKdTree.h \
CgSceneGraph/CgAABB.h \
CgUtils/ObjLoader.h \
CgUtils/Timer.h \
CgBase/CgBaseImage.h \
CgEvents/CgTrackballEvent.h
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment