Point Cloud Scene Node

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.

Point Cloud Scene Node

Postby Wol101 » 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.


cpp Code: Select all
#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
    PointCloudSceneNode(irr::scene::ISceneNode* parent, irr::scene::ISceneManager* mgr, irr::s32 id);
    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);
    irr::core::aabbox3d<irr::f32> Box;
    irr::video::SMaterial Material;
    irr::video::S3DVertex *Vertices;
    irr::u32 *IndexList;
    irr::u32 NumVertices;


cpp 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;
    if (Vertices) delete [] Vertices;
    if (IndexList) delete [] IndexList;
void PointCloudSceneNode::OnRegisterSceneNode()
    if (IsVisible)
void PointCloudSceneNode::render()
    irr::video::IVideoDriver* driver = SceneManager->getVideoDriver();
    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;
        // 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;
                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;
        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();
            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);
Posts: 9
Joined: Sat Apr 23, 2016 6:39 am

Re: Point Cloud Scene Node

Postby CuteAlien » Tue Oct 04, 2016 9:43 am

Nice. You should maybe add setter/getter to set the color and length directly. Using DEBUG_NORMAL_COLOR and DEBUG_NORMAL_LENGTH is probably because it's based on Irrrlicht internal code. We use that in debug - but it's rather slow (using a string comparison). Also be aware that DebugDataVisible is something that has to be explicitely set. If you use an explicit PointCloudSceneNode you probably want it rather to show when it's "Visible" instead (already checked in OnRegisterSceneNode), so maybe you can remove the DebugDataVisible code in render.
IRC: #irrlicht on irc.freenode.net
Code snippets, patches&stuff: http://www.michaelzeilfelder.de/irrlicht.htm
Free racer created with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
User avatar
Posts: 8468
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany

Re: Point Cloud Scene Node

Postby Wol101 » Tue Oct 04, 2016 10:14 am

Well spotted - the debug code is more or less straight from CAnimatedMeshSceneNode. But actually that's what I want. The bounding box and normals are only there for debugging so performance isn't really an issue. Multiple calls of draw3DLine must be very slow! I guess if I wanted it faster I could do something with drawVertexPrimitiveList and EPT_LINES. If I was smarter I'd unify my storage format with the Irrlicht vertex format and avoid unnecessary copying but it only happens relatively infrequently and so isn't a huge bottleneck. And my point clouds aren't all that big. 500,000 points or so...
Posts: 9
Joined: Sat Apr 23, 2016 6:39 am

Re: Point Cloud Scene Node

Postby chronologicaldot » Tue Oct 04, 2016 6:38 pm

*sigh* This reminds me of the fact that I never got around to implementing the multiple rendering types for Burnings. It still can't render points, which is silly because that's rather simple, but it'll have to do with a vertex cache overall because of the triangle fan more than anything else.
User avatar
Competition winner
Posts: 556
Joined: Mon Sep 10, 2012 8:51 am

Re: Point Cloud Scene Node

Postby AReichl » Wed Oct 05, 2016 7:49 am

where is PointCloud.h ?
Posts: 239
Joined: Wed Jul 13, 2011 2:34 pm

Re: Point Cloud Scene Node

Postby Wol101 » Wed Oct 05, 2016 8:35 am

It's here but it isn't useful as an Irrlicht snippet. It has a lot of dependencies. However you can see how the points are stored and the bounds are accessed which might be useful. The code is part of a program for measuring locations on point cloud movies and I'll release it open source when it's finished (which should be this year).


cpp Code: Select all
#include "octree/octree.h"
#include "pipeline/math_3d.h"
#include "geometric_tools/Wm5ApprLineFit3.h"
#include "geometric_tools/Wm5ApprPlaneFit3.h"
struct Point
    float x;
    float y;
    float z;
    float nx;
    float ny;
    float nz;
    unsigned char r;
    unsigned char g;
    unsigned char b;
    unsigned char a;
class PointCloud
    enum AlphaCodes {selected = 0, unselected = 255};
    int ImportPLY(const char *filename);
    int ExportPLY(const char *filename);
    int SaveMatrix(const char * filename);
    int LoadMatrix(const char * filename);
    void SetAlpha(AlphaCodes alphaCode);
    void SetAlphaBounded(const Vector3f &bound1, const Vector3f &bound2, const Matrix4f &worldTrans, AlphaCodes alphaCode);
    void SetAlphaLine(const Vector3f &startLine, const Vector3f &endLine, float screenRadius, const Matrix4f &worldTrans, AlphaCodes alphaCode, bool useScreenPixelRadius, bool ignoreZ);
    void SetAlphaSphere(const Vector3f &screenSelect, float screenRadius, const Matrix4f &worldTrans, AlphaCodes alphaCode, bool useScreenPixelRadius);
    int FitLineToAlpha(AlphaCodes oldAlphaCode, AlphaCodes newAlphaCode);
    int FitPlaneToAlpha(AlphaCodes oldAlphaCode, AlphaCodes newAlphaCode);
    int FitPointToAlpha(AlphaCodes oldAlphaCode, AlphaCodes newAlphaCode);
    int FitPointToSphere(const Vector3f &screenSelect, float screenRadius, const Matrix4f &worldTrans);
    void RotateToVector(float x, float y, float z);
    void RotateToVector(float x, float y, float z, float ax, float ay, float az);
    void RotateByQuaternion(float x, float y, float z, float w);
    void RotateByAxisAngle(float x, float y, float z, float degrees);
    void Translate(float x, float y, float z);
    void Scale(float x, float y, float z);
    void ApplyTransformation(Matrix4f &matrix);
    void FindClosestPoint(const Vector3f &screenSelect, const Matrix4f &worldTrans, Vector3f *closestPoint);
    const Matrix4f &GetTransformation() { return m_Transformation; }
    const Vector3f &GetLastPoint() { return m_LastPoint; }
    const Vector3f &GetLastVector() { return m_LastVector; }
    const Point &GetPoint(int index) { return m_PointList[index]; }
    const Point *GetPointList() { return m_PointList; }
    int GetNPoints() { return m_NPoints; }
    int GetNSelected() { return m_NSelected; }
    const Vector3f &GetMinBound() { return m_MinBound; }
    const Vector3f &GetMaxBound() { return m_MaxBound; }
    bool GetLineFitted() { return m_lineFitted; }
    bool GetPointFitted() { return m_pointFitted; }
    static int TypeSize(const char *type);
    Point *m_PointList;
    int m_NPoints;
    int m_NSelected;
    Octree<int> *m_PointOctree;
    int m_OctreeSize;
    double m_OctreeIndexEpsilon;
    Vector3f m_MinBound;
    Vector3f m_MaxBound;
    double m_XDel;
    double m_YDel;
    double m_ZDel;
    bool m_UseOctree;
    Wm5::Line3<float> m_bestFitLine;
    Wm5::Plane3<float> m_BestFitPlane;
    Vector3f m_LastPoint;
    Vector3f m_LastVector;
    Matrix4f m_Transformation;
    bool m_lineFitted;
    bool m_pointFitted;
#endif // POINTCLOUD_H
Posts: 9
Joined: Sat Apr 23, 2016 6:39 am

Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 1 guest