Point Cloud Scene Node
Posted: Mon Oct 03, 2016 7:33 pm
Here is a quick implementation of a custom scene node to render point clouds where each point has a colour and a normal. I use it for data generated using 3D photogrammetry (e.g. with VisualSFM). I feed the data in as a structure array (x,y,z),(a,r,g,b),(nx,ny,nz) but it would be easy to adapt. I have also precalculated the bounding box but that is trivial to add if you want it done in the initialiser. All the work is done via drawVertexPrimitiveList. You use the code exactly like Tutorial 03 except that you have to call initializeVertices after creation.
PointCloudSceneNode.h
PointCloudSceneNode.cpp
PointCloudSceneNode.h
Code: Select all
#ifndef POINTCLOUDSCENENODE_H
#define POINTCLOUDSCENENODE_H
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wuninitialized"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <irrlicht.h>
#pragma GCC diagnostic pop
class PointCloud;
class PointCloudSceneNode : public irr::scene::ISceneNode
{
public:
PointCloudSceneNode(irr::scene::ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id);
~PointCloudSceneNode();
virtual void OnRegisterSceneNode();
virtual void render();
virtual const irr::core::aabbox3d<irr::f32>& getBoundingBox() const;
virtual irr::u32 getMaterialCount() const;
virtual irr::video::SMaterial& getMaterial(irr::u32 i );
// custom initialiser for this scene node
void initializeVertices(PointCloud *pointCloud, irr::s32 maxPointsToRender);
protected:
irr::core::aabbox3d<irr::f32> Box;
irr::video::SMaterial Material;
irr::video::S3DVertex *Vertices;
irr::u32 *IndexList;
irr::u32 NumVertices;
};
#endif // POINTCLOUDSCENENODE_H
Code: Select all
#include "PointCloudSceneNode.h"
#include "PointCloud.h"
PointCloudSceneNode::PointCloudSceneNode(irr::scene::ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id)
: irr::scene::ISceneNode(parent, mgr, id)
{
Material.Wireframe = false;
Material.Lighting = false;
Material.PointCloud = true;
Vertices = 0;
IndexList = 0;
NumVertices = 0;
}
PointCloudSceneNode::~PointCloudSceneNode()
{
if (Vertices) delete [] Vertices;
if (IndexList) delete [] IndexList;
}
void PointCloudSceneNode::OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}
void PointCloudSceneNode::render()
{
irr::video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setMaterial(Material);
driver->setTransform(irr::video::ETS_WORLD, AbsoluteTransformation);
driver->drawVertexPrimitiveList(Vertices, NumVertices, IndexList, NumVertices, irr::video::EVT_STANDARD, irr::scene::EPT_POINTS, irr::video::EIT_32BIT);
// for debug purposes only:
if (DebugDataVisible)
{
irr::video::SMaterial debug_mat;
debug_mat.Lighting = false;
debug_mat.AntiAliasing=0;
driver->setMaterial(debug_mat);
// show normals
if (DebugDataVisible & irr::scene::EDS_NORMALS)
{
const irr::f32 debugNormalLength = SceneManager->getParameters()->getAttributeAsFloat(irr::scene::DEBUG_NORMAL_LENGTH);
const irr::video::SColor debugNormalColor = SceneManager->getParameters()->getAttributeAsColor(irr::scene::DEBUG_NORMAL_COLOR);
// draw normals
for (irr::u32 i=0; i < NumVertices; ++i)
{
irr::core::vector3df normalizedNormal = Vertices[i].Normal;
normalizedNormal.normalize();
const irr::core::vector3df& pos = Vertices[i].Pos;
driver->draw3DLine(pos, pos + (normalizedNormal * debugNormalLength), debugNormalColor);
}
}
debug_mat.ZBuffer = irr::video::ECFN_DISABLED;
debug_mat.Lighting = false;
driver->setMaterial(debug_mat);
if (DebugDataVisible & irr::scene::EDS_BBOX || DebugDataVisible & irr::scene::EDS_BBOX_BUFFERS)
driver->draw3DBox(Box, irr::video::SColor(255,255,255,255));
}
}
const irr::core::aabbox3d<irr::f32>& PointCloudSceneNode::getBoundingBox() const
{
return Box;
}
irr::u32 PointCloudSceneNode::getMaterialCount() const
{
return 1;
}
irr::video::SMaterial& PointCloudSceneNode::getMaterial(irr::u32 /* i */)
{
return Material;
}
// this is the custom initiation function
void PointCloudSceneNode::initializeVertices(PointCloud *pointCloud, irr::s32 maxPointsToRender)
{
if (pointCloud) // load up the buffer objects
{
irr::u32 stride;
if (maxPointsToRender >= pointCloud->GetNPoints())
{
stride = 1;
NumVertices = pointCloud->GetNPoints();
}
else
{
stride = pointCloud->GetNPoints() / maxPointsToRender;
if (pointCloud->GetNPoints() % maxPointsToRender) stride++;
NumVertices = pointCloud->GetNPoints() / stride;
}
if (Vertices) delete [] Vertices;
Vertices = new irr::video::S3DVertex[NumVertices];
if (IndexList) delete [] IndexList;
IndexList = new irr::u32[NumVertices];
irr::video::S3DVertex v;
irr::u32 i, j;
const Point *pointList = pointCloud->GetPointList();
for (j = 0; j < NumVertices; j++)
{
i = j * stride;
v.Pos.set(pointList[i].x, pointList[i].y, pointList[i].z);
v.Color.set(pointList[i].a, pointList[i].r, pointList[i].g, pointList[i].b);
v.Normal.set(pointList[i].nx, pointList[i].ny, pointList[i].nz);
// v.TCoords.set(tu, tv);
Vertices[j] = v;
IndexList[j] = j;
}
Vector3f minBound = pointCloud->GetMinBound();
Vector3f maxBound = pointCloud->GetMaxBound();
Box = irr::core::aabbox3df(minBound.x, minBound.y, minBound.z, maxBound.x, maxBound.y, maxBound.z);
}
}