diff --git a/CgMath/CgPointMath.h b/CgMath/CgPointMath.h index b550ebb5f7c9f4e5260ba04c30bd5045ed404d33..49d1ea0ce5cd940abbb0b64be13d55f4ed4a6ef9 100644 --- a/CgMath/CgPointMath.h +++ b/CgMath/CgPointMath.h @@ -14,6 +14,15 @@ using namespace Eigen; #include "CgAABB.h" +struct PCA { + glm::vec3 evec0; + glm::vec3 evec1; + glm::vec3 evec2; + float eval0; + float eval1; + float eval2; +}; + /* * simple geometric calculations used in multiple places */ @@ -24,7 +33,7 @@ class CgPointMath { static glm::vec3 calculateCentroid(const std::vector<glm::vec3> &points); static CgAABB calculateAABB(const std::vector<glm::vec3>& vertices); static glm::mat3 getCovarianceMatrix(const std::vector<glm::vec3> &points); - static glm::vec3 estimateNormalFromPCA(const std::vector<glm::vec3> &points); + static PCA calculatePCA(const std::vector<glm::vec3> &points); static glm::vec3 getPerpendicularVector(glm::vec3 arg); private: CgPointMath(){} @@ -141,7 +150,7 @@ inline glm::mat3 CgPointMath::getCovarianceMatrix(const std::vector<glm::vec3> & return ret; } -inline glm::vec3 CgPointMath::estimateNormalFromPCA(const std::vector<glm::vec3> &points) { +inline PCA CgPointMath::calculatePCA(const std::vector<glm::vec3> &points) { // calculate covariance matrix unsigned int size = points.size(); Eigen::MatrixXd mat(size, 3); @@ -160,8 +169,17 @@ inline glm::vec3 CgPointMath::estimateNormalFromPCA(const std::vector<glm::vec3> // The eigenvalues of a selfadjoint matrix are always real. // the eigenvalues are sorted in ascending order - Eigen::Vector3d normal = es.eigenvectors().col(0); - return glm::vec3(normal(0), normal(1), normal(2)); + Eigen::Vector3d evec0 = es.eigenvectors().col(0); + Eigen::Vector3d evec1 = es.eigenvectors().col(1); + Eigen::Vector3d evec2 = es.eigenvectors().col(2); + return { + glm::vec3(evec0(0), evec0(1), evec0(2)), + glm::vec3(evec1(0), evec1(1), evec1(2)), + glm::vec3(evec2(0), evec2(1), evec2(2)), + es.eigenvalues()(0), + es.eigenvalues()(1), + es.eigenvalues()(2) + }; } // calculates an arbitrary verctor perpendicular to the given one diff --git a/CgMath/CgPointWrangler.h b/CgMath/CgPointWrangler.h index d06f6fa79116ea5f9855dca232ad016bf07475e3..3bea1a2104e21733e200a8ad65f404d489ce73e0 100644 --- a/CgMath/CgPointWrangler.h +++ b/CgMath/CgPointWrangler.h @@ -223,6 +223,7 @@ inline std::vector<glm::vec3> CgPointWrangler::estimateNormals(unsigned int neig std::vector<std::thread> threads; threads.reserve(thread_count); + // worker for the threads that calculate all k-neighbourhoods auto worker = [&]( const unsigned int start_index, const unsigned int count @@ -231,13 +232,12 @@ inline std::vector<glm::vec3> CgPointWrangler::estimateNormals(unsigned int neig std::vector<glm::vec3> nh(neighbourhood_size); for(unsigned int i = start_index; i < start_index + count; i++) { neighbourhoods[i] = getNearestNeighborsFast(i, neighbourhood_size, vertices, aabb); - for(int j = 0; j < neighbourhood_size; j++) { - nh[j] = vertices[neighbourhoods[i][j]]; - } - normals[i] = CgPointMath::estimateNormalFromPCA(nh); + for(int j = 0; j < neighbourhood_size; j++) nh[j] = vertices[neighbourhoods[i][j]]; + normals[i] = CgPointMath::calculatePCA(nh).evec0; } }; + // start some workers unsigned int slice_size = vertices.size() / thread_count; unsigned int slice_rest = vertices.size() % thread_count; unsigned int t = 0; diff --git a/CgSceneGraph/CgPointCloud.cpp b/CgSceneGraph/CgPointCloud.cpp index a7cec1c16e21e43c2de0bf4ceaba3b78c8c48da0..332f93626d2e97b5eab1751c27e2b5930c559742 100644 --- a/CgSceneGraph/CgPointCloud.cpp +++ b/CgSceneGraph/CgPointCloud.cpp @@ -35,31 +35,6 @@ CgPointCloud::~CgPointCloud() { m_splat_indices.clear(); } -void CgPointCloud::calculateSplatOrientations() { - // calculate local coordinate system for splats (arbitrary orientation of ellipse in plane) - // replace this if you have the real coordinate system, use up vector = y-Axis of your local coordinate system instead of getPerpendicularVector(...) - - m_splat_orientations.clear(); - m_splat_scaling.clear(); - m_splat_indices.clear(); - - for(unsigned int i = 0; i < m_vertices.size(); i++) { - // eye, center, up - // look from vertex position to the point the normal points at - glm::mat4 lookAt_matrix(glm::lookAt( - glm::vec3(m_vertices[i]), - glm::vec3(m_vertices[i] - m_vertex_normals[i]), - CgPointMath::getPerpendicularVector(m_vertex_normals[i]) - )); - m_splat_orientations.push_back(lookAt_matrix); - m_splat_scaling.push_back(glm::vec2(0.02,0.02)); - - // use all points for splatting by default - m_splat_indices.push_back(i); - } - -} - void CgPointCloud::setColors(std::vector<unsigned int> indices, glm::vec3 color) { for(unsigned int i = 0; i < indices.size(); i++) m_vertex_colors[indices[i]] = color; } diff --git a/CgSceneGraph/CgPointCloud.h b/CgSceneGraph/CgPointCloud.h index d7d9decf1e83c26d63e22ac637c2ae3099b72e74..2d7cb9f92a24345ae9fcc4e3c304e2ed85a25fdb 100644 --- a/CgSceneGraph/CgPointCloud.h +++ b/CgSceneGraph/CgPointCloud.h @@ -56,19 +56,12 @@ private: CgPointCloud(int id): m_type(Cg::PointCloud), m_id(id) {}; - //for demonstration: find local coordinate system (normal plus arbitrary tangent spanning directions) - void calculateSplatOrientations(); - std::vector<glm::vec3> m_vertices; std::vector<glm::vec3> m_vertex_normals; std::vector<glm::vec3> m_vertex_colors; glm::vec3 m_centroid; CgAABB m_aabb; - - // indices of vertices for which a splat will be rendered std::vector<unsigned int> m_splat_indices; - - std::vector<glm::mat4> m_splat_orientations; std::vector<glm::vec2> m_splat_scaling; diff --git a/CgSceneGraph/CgSceneControl.cpp b/CgSceneGraph/CgSceneControl.cpp index c92078abdb6203b1ceb243aa714852b227145805..5becc4bfc7723e7615497220ec27659631b3c9e7 100644 --- a/CgSceneGraph/CgSceneControl.cpp +++ b/CgSceneGraph/CgSceneControl.cpp @@ -372,6 +372,9 @@ void CgSceneControl::handleEvent(CgBaseEvent* e) { std::vector<glm::vec3> positions; std::vector<glm::vec3> normals; std::vector<glm::vec3> colors; + std::vector<glm::mat4> splat_orientations; + std::vector<glm::vec2> splat_scalings; + std::vector<unsigned int> splat_indices; loader->getPositionData(positions); std::cout << "loaded " << positions.size() << " points" << std::endl; @@ -379,17 +382,27 @@ void CgSceneControl::handleEvent(CgBaseEvent* e) { run_timed("build kd", 1, [&](){CgPointWrangler::buildKdTree(positions.data(), positions.data() + positions.size(), 0);}); run_timed("est. normals", 1, [&](){normals = CgPointWrangler::estimateNormals(15, positions);}); colors.resize(positions.size()); + splat_orientations.resize(positions.size()); + splat_scalings.resize(positions.size()); + splat_indices.resize(positions.size()); for(unsigned int i = 0; i < positions.size(); i++) { colors[i] = (normals[i] + glm::vec3(1.0)) * .5; + splat_orientations[i] = glm::lookAt( + positions[i], + positions[i] - normals[i], + CgPointMath::getPerpendicularVector(normals[i]) + ); + splat_scalings[i] = glm::vec2(0.01, 0.01); + splat_indices[i] = i; } m_pointcloud = new CgPointCloud( positions, normals, colors, - std::vector<glm::mat4>(positions.size()), - std::vector<glm::vec2>(positions.size()), - std::vector<unsigned int>(positions.size()) + splat_orientations, + splat_scalings, + splat_indices ); // save away a copy