Point Cloud Plugin

New Features / Improvements

  • photogammetry

XD


Point Cloud Plugin v0.5.5
Release Notes

New Features / Improvements

  • Support for LAS files
  • Modular Importers
  • ColorAdjustment options will now affect ColorOverride settings
  • ColorOverride settings will now be affected by Intensity data
  • Added option to manually specify gradient colors when using ColorOverride

Fixes

  • Fixed ability to manually set persistent Enabled status of individual points

Hi @ ,

Thank you very much for your plugin! I’m very excited about starting to try it, as it looks really promising, but would you know where to download a good point cloud to play with?

Thank you and best regards!

Hi There!

First of all, thank you for this fantastic plugin. Currently I try to calculate the points that collided with my collider sphere. Therefore I have some questions, that maybe someone more experienced could help me with. :slight_smile:

I think my main problem is to get the individual points that belong to an octree node. I first assumed that the numbers in the IBCache Array in “PointCloudOctree” where the index of the Point in the Array that stores all the Points. But the numbers in the IBCache Elements are way higher than my actual number of points, what leads to an “out of bounds” error.
So where and how can I acces only the points that belong to an certain Node?

Of course there could be many more problems with my code, I just started out learning C++…At least It compiles :smiley:

Here is my code that I added to the OctreeCpp:



//START MYCODE
TArray<FPointCloudPoint> TmpTouchedPoints;
TArray<uint32> TmpTouchedPointsIndex;
TArray<FPointCloudPoint> FPointCloudOctree::GetTouchedPoints(FVector ColliderLocation, int32 Radius, TArray<FPointCloudPoint> &PointCloudPoints, FPointCloudOctree::Node ParamRoot) const
{
    GetPointsInNode(TmpTouchedPointsIndex , ColliderLocation, Radius, PointCloudPoints, ParamRoot);
    for (auto const &pointIndex : TmpTouchedPointsIndex)
    {
        TmpTouchedPoints.Add(PointCloudPoints[pointIndex]);
    }
    return TmpTouchedPoints;
}

void FPointCloudOctree::GetPointsInNode(TArray<uint32> &TouchedPointsIndex, FVector CLocation, int32 Radius, TArray<FPointCloudPoint> &pPointCloudPoints, FPointCloudOctree::Node &pNodeToGetPoints) const
{
    FBox nodeBox = pNodeToGetPoints.LocalBounds.GetBox();
    // Is the Collider Sphere inside the node or the distance to it smaller than the sphere radius and does the node have 0 children?
    if (nodeBox.IsInsideOrOn(CLocation) && ComputeSquaredDistanceFromBoxToPoint(nodeBox.Min, nodeBox., CLocation) < (Radius*Radius) && pNodeToGetPoints.NumChildren == 0)
    {
        //For every PointIndex in IBCache
        for (auto const &pointIndex : pNodeToGetPoints.IBCache)
        {
            //Is Point inside collider sphere?
            if ((pPointCloudPoints[pointIndex].Location - CLocation).SizeSquared() < (Radius * Radius))
            {
                // Add the Index of the Point to the collection
                TouchedPointsIndex.Add(pointIndex);
            }

        }

    }
    // Is the Collider Sphere inside the node or the distance to it smaller than the sphere radius
    else if (nodeBox.IsInsideOrOn(CLocation) && ComputeSquaredDistanceFromBoxToPoint(nodeBox.Min, nodeBox., CLocation) < (Radius*Radius))
    {
        //For every PointIndex in IBCache
        for (auto const &pointIndex : pNodeToGetPoints.IBCache)
        {
            // Is Point inside collider Sphere
            if ((pPointCloudPoints[pointIndex].Location - CLocation).SizeSquared() < (Radius * Radius))
            {
                // Add the Index of the Point to the collection 
                TouchedPointsIndex.Add(pointIndex);
            }

        }
        //For every child of the node call this function and collect points
        for (int i = 0; i < pNodeToGetPoints.NumChildren; i++)  //alternative: (auto const &ChildNode : pNodeToGetPoints.Children) 
        {
            GetPointsInNode(TouchedPointsIndex, CLocation, Radius, pPointCloudPoints, *pNodeToGetPoints.Children*);
        }
    } 
}
//END MYCODE


Another Thing is, when I take the parts out, that make the “out of bounds” error happen, everything runs cool, but somehow the rendering of some points gets affected. See Pictures:


Thank you all for any help and suggestions!!!

Hi. There are some websites providing free point clouds, like:
http://www.libe57.org/data.html
http://graphics.stanford.edu/data/3Dscanrep/
http://data.duraark.eu

Keep in mind you would have to convert any e57 files to ASCII or LAS formats before you can import them to the Engine, as e57 files are not directly supported yet.

Hi and thanks for the feedback!

Unfortunately, using the IBCache will not be a good way to extract the points’ indices in the main array, as its contents and order of the data will vary depending on few factors and might be difficult to extract efficiently. Its purpose is to aid in selecting relevant rendering data to be used by the GPU and, unless you know exactly what you are doing, shouldn’t be modified manually.

The simplest solution that comes to my mind would be to add reference array inside the FPointCloudOctree::Node struct (inside PointCloudOctree.h), like so:



...
struct FPointCloudOctree
{
    struct Node
    {
        TArray<uint32> IBCache;
        TArray<uint32> PointsIndices;
        uint32 NumPrimitives;
...


Then, to modify the FPointCloudOctree::Node::BuildIBCache function (inside PointCloudOctree.cpp) to populate this array, like so:



...
    for (double i = 0; i < InPoints->Num(); i += Tree->SkipValues[LOD])
    {
        CacheNode->PointsIndices.Add((uint32)i);

        if (Tree->bUsesSprites)
...


This new array should then store correct indices used by the **Points **array, accessible via UPointCloud::Points.

Hope this helps :slight_smile:

Hi phobos,
thank you so much for your answer, it works!

While playing around I was wondering, whether I could somehow change the color of the points in the cloud, without reassigning the point cloud data as shown in your “runtime operations” tutorial. I imagine that getting all the data and change the color of some points, and then reassigning and rebuilding the cloud is rather inefficient. I tried setting the color on the reference to the points of the cloud, but that did not seem to work.

Another thing i was wondering about is the Scale / Offset setting. with my tool I register collision somewhere near the cloud and not where the actual points are rendered. Are the offsets only applied to the renderer?

Thank you so much again!

Glad it worked :slight_smile:

Currently, the cloud needs rebuilding to propagate any changes to the buffer on the GPU, otherwise, you are changing the values stored in RAM only (I have a potential solution for it tho, which I’ll try to test soon).
The scale and offset are applied to the point itself, so it should be the same everywhere.

Hi, thanks for the awesome plugin. Currently using it in an animation production for creating a “dream” effect.

I am trying to have a point cloud appear gradually. As in, it should be completely hidden in the beginning, and then points should start appearing, and finally you see the whole cloud.

I’ve achieved a close effect using a mask applied in post (Fusion). See the attached picture for how it looks midway. But is there any way of doing it using your plugin? Or maybe an Unreal method that I don’t know of?

Thanks in advance!

Hi @AutreWeg and thanks for the feedback!

Animation capacity of the current version is very limited. You could enable / disable the points manually, but it would require a rebuild for the changes to take effect and, depending on the cloud size, could quickly hit your performance limit. I think the post-processing mask is a sound approach here.

The upcoming version should make it much more usable as the points are being streamed fully dynamically, so the changes should be immediate (in theory, at least :wink: )

Plugin seems great from testing. If I wanted to import multiple point clouds aligned in software such as Scene, what process would be best for importing into Unreal. Using an XYZ file, loses the points alignment.

Thanks.

Hi @pp_rfrost

The default behavior will center the clouds after importing. You can change this by opening the asset’s settings and selecting None as its Offset, following by a rebuild. This will then use the raw coordinates from an import.

However, please be aware of the precision loss if the coordinates are too large. In such a case, the precision loss guard may trigger and will force-center the cloud. It is best if you align the cloud pieces and recenter them as a group in your software of choice, before importing into UE4.

Hope this helps. If you still experience any issues, please let me know :slight_smile:

Perfect, thanks for letting me know.

Getting Serialization Error on Build as others has before. Can’t see a fix mentioned on the thread, was any resolution found for this?

Thanks for the report. Happy to say it’s already been fixed for the v0.5.6, scheduled within the next few days.

If you need it sooner and don’t mind re-compiling the plugin, just change line 89 92 in *PointCloud.cpp *from


if (!FPaths::FileExists(Ar.GetArchiveName()))

to:


if (!FPaths::FileExists(Ar.GetArchiveName()) && !(Ar.IsCooking() && Ar.GetArchiveName().Equals(FPaths::GetBaseFilename(FStringAssetReference(this).ToString(), false))))

That’s great, thank you.

With a number of point clouds being loaded, whats the best way to optimise map loading times?

Point Cloud Plugin v0.5.6](http://pointcloudplugin.com)
Release Notes

New Features / Improvements

  • Removed the necessity of using SetEnabledOverride to mark the points’ status as persistent
  • Added more options for LAS importing

Fixes

  • Fixed many issues and potential stability problems with serialization
  • Fixed many issues and potential stability problems with importing clouds
  • Fixed issues with compiling Volumetric materials
  • Fixed issues with precision loss guard not triggering correctly is some cases
  • Fixed missing Blueprint exposure for LAS importing
  • Fixed Render Method not switching to RGB after reimport
  • Fixed incorrect behavior when providing Color Range with negative values during imports

By default, the clouds will only be pushed to the GPU if they are set as visible. You could potentially load the map with all of them invisible, then toggle one by one to somewhat limit the initial stutter. Alternatively, v0.6 (EA) is using GPU streaming, so the initial stutter should be minimal in comparison.

However, keep in mind that the engine will still load all assets referenced by the particular level when said level is being loaded itself. One way to overcome this would be to use Level Streaming and break it into several pieces, each containing a number of clouds. This way you may be able to load some of the data in the background, reducing the initial stutter.

Hope this helps :slight_smile:

Thanks ,
I’ll setup level streaming for the clouds.
Just tried v0.5.6, and getting “Fatal error!” dialog — no other information appears.