Component that builds a point-cloud style mesh from added points. It stores vertex and index lists, creates quads for each lidar point, and rebuilds a ModelRenderer mesh at a controlled rate.
using System;
public sealed class Lidar : Component
{
[Property] public float RebuildRate { get; set; } = 0.25f;
[Property] public float PointSize { get; set; } = 5.0f;
[Property] public Material DotMaterial { get; set; }
[Property] public ModelRenderer Model { get; set; }
private float lastUpdate = 0f;
private bool isDirty = false;
private readonly List<Vertex> vertices = new();
private readonly List<int> indices = new();
protected override void OnStart()
{
DotMaterial ??= Material.Load( "materials/default.vmat" );
Model ??= Components.GetOrCreate<ModelRenderer>();
}
protected override void OnUpdate()
{
if ( !isDirty )
return;
float nowTime = Time.Now;
if ( (nowTime - lastUpdate) < RebuildRate )
return;
lastUpdate = nowTime;
RebuildModel();
}
public void AddPoint( Vector3 pos, Vector3 normal )
{
normal = normal.Normal;
Vector3 tangent = Vector3.Cross(
normal,
MathF.Abs( normal.z ) < 0.99f
? Vector3.Up
: Vector3.Forward
).Normal;
Vector3 bitangent = Vector3.Cross( normal, tangent ).Normal;
float half = PointSize * 0.5f;
int baseIndex = vertices.Count;
vertices.Add( new Vertex(
pos + (tangent + bitangent) * half,
normal,
new Vector4( tangent, 1 ),
new Vector2( 0, 0 )
) );
vertices.Add( new Vertex(
pos + (tangent - bitangent) * half,
normal,
new Vector4( tangent, 1 ),
new Vector2( 0, 1 )
) );
vertices.Add( new Vertex(
pos + (-tangent - bitangent) * half,
normal,
new Vector4( tangent, 1 ),
new Vector2( 1, 1 )
) );
vertices.Add( new Vertex(
pos + (-tangent + bitangent) * half,
normal,
new Vector4( tangent, 1 ),
new Vector2( 1, 0 )
) );
indices.Add( baseIndex + 0 );
indices.Add( baseIndex + 1 );
indices.Add( baseIndex + 2 );
indices.Add( baseIndex + 0 );
indices.Add( baseIndex + 2 );
indices.Add( baseIndex + 3 );
isDirty = true;
}
public void ClearPoints()
{
vertices.Clear();
indices.Clear();
isDirty = true;
}
public void RebuildModel()
{
isDirty = false;
if ( vertices.Count == 0 )
return;
var mesh = new Mesh( DotMaterial );
mesh.CreateVertexBuffer( vertices.Count, vertices );
mesh.CreateIndexBuffer( indices.Count, indices.ToArray() );
Model.Model = new ModelBuilder()
.AddMesh( mesh )
.Create();
}
}