Visualizing point clouds in Godot

I’ve previously visualized lines, using clickable meshes as geometry. The advantage of this approach is that you get clickable objects and can access their attributes. The downside is speed, as each vertex and line segment is its own object with both a visual mesh and a collider mesh. For displaying point clouds, this approach would be too slow. Instead it is better to display point clouds as points, and do so using a MultiMesh. Getting this to work took a bit of fiddling, but here’s the code for the resulting point cloud class:

class_name Pointcloud
extends MultiMeshInstance3D

# Called when the node enters the scene tree for the first time.
func _ready():
    pass # Replace with function body.

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
    pass
    
func draw(points:Array[Vector3],colors:Array[Vector3]):
    multimesh = MultiMesh.new()
    multimesh.transform_format = MultiMesh.TRANSFORM_3D
    multimesh.use_colors=true
        
    var pmesh := PointMesh.new()
    var material := StandardMaterial3D.new()
    material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
    material.albedo_color=Color(1,1,1)
    material.point_size=1
    material.vertex_color_use_as_albedo=true
    pmesh.material=material	
    
    multimesh.mesh=pmesh
    multimesh.instance_count = len(points)
    
    for i in multimesh.instance_count:
        multimesh.set_instance_transform(i, Transform3D(Basis(), points[i]))	
        multimesh.set_instance_color(i,Color(colors[i].x/256.0,colors[i].y/256.0,colors[i].z/256.0))

The point cloud is loaded outside of this class, using the csv reading functionality described in the previous post. I also added reading of the RGB color of each point. The following then happens:

  1. A MultiMesh is instantiated and told to use individual instance colors.
  2. The geometry for each mesh instance is defined as being a PointMesh, and the material to use is defined. The color needs to be set to white for the coloring to work. Godot uses float colors (from 0 to 1), not 8 bit or 16 bit integer colors.
  3. All the previously loaded points are then used to set the position and color of each instance. As the colors that I read from the file are 8 bit, I have to rescale them for proper coloring. It might be smarter to do this inside the function that reads the file.

Here’s the result with intensity-based vertex colors:

As you can see, I get 36fps in debug mode, with 16 million points, which is not bad at all in my opinion.

Leave a comment

Your email address will not be published. Required fields are marked *