//======= Copyright (c) Stereolabs Corporation, All rights reserved. ===============
using UnityEngine;
///
/// Displays the point cloud of the real world in front of the camera.
/// Can be attached to any GameObject in a scene, but requires a ZEDManager component to exist somewhere.
///
///
namespace sl
{
public class ZEDFusedPointCloudRenderer : MonoBehaviour
{
///
/// Instance of the ZEDManager interface
///
public ZEDManager zedManager = null;
///
/// Point size of the Fused Point cloud. If > 0, then disk shader will be used to generate spheres around points
///
public float _pointSize = 0.001f;
///
/// Fused point cloud resolution (sent to spatial mapping parameters)
///
public float resolution = 0.5f;
///
/// Fused point cloud range (sent to spatial mapping parameters)
///
public float range = 5.0f;
///
/// zed Camera controller by zedManager.
///
private sl.ZEDCamera zed = null;
///
/// Point Material
///
private Material _pointMaterial;
///
/// Disk material (sphere around point)
///
private Material _diskMaterial;
///
/// Array of points as point buffer (compute buffer). Send to shaders
///
private ComputeBuffer _pointBuffer;
///
/// Size of Vector4
///
private const int elementSize = sizeof(float) * 4;
///
/// Array of vertex points
///
private Vector4[] vertPoints;
private bool notStarted = true;
private bool canUpdate = false;
private float updateTime = 0;
void Start()
{
if (zedManager == null)
{
zedManager = FindObjectOfType();
if (ZEDManager.GetInstances().Count > 1) //We chose a ZED arbitrarily, but there are multiple cams present. Warn the user.
{
Debug.Log("Warning: " + gameObject.name + "'s zedManager was not specified, so the first available ZEDManager instance was " +
"assigned. However, there are multiple ZEDManager's in the scene. It's recommended to specify which ZEDManager you want to " +
"use to display a point cloud.");
}
}
if (zedManager != null)
zed = zedManager.zedCamera;
if (_pointMaterial == null)
{
_pointMaterial = new Material(Resources.Load("Materials/PointCloud/Mat_ZED_FusedPC_Point") as Material);
}
if (_diskMaterial == null)
{
_diskMaterial = new Material(Resources.Load("Materials/PointCloud/Mat_ZED_FusedPC_Disk") as Material);
}
_diskMaterial.hideFlags = HideFlags.DontSave;
_pointMaterial.hideFlags = HideFlags.DontSave;
zedManager.OnGrab += startMap;
}
///
/// Start Map linked to grab callback. Wait for one frame to start point cloud fusion
///
private void startMap()
{
if (zed != null && notStarted)
{
zed.EnableSpatialMapping(sl.SPATIAL_MAP_TYPE.FUSED_POINT_CLOUD, resolution, range);
notStarted = false;
canUpdate = true;
}
}
void OnDestroy()
{
canUpdate = false;
if (zed != null)
zed.DisableSpatialMapping();
if (_pointBuffer != null)
{
_pointBuffer.Release();
_pointBuffer = null;
}
if (_pointMaterial != null)
{
if (Application.isPlaying)
{
Destroy(_pointMaterial);
Destroy(_diskMaterial);
}
else
{
DestroyImmediate(_pointMaterial);
DestroyImmediate(_diskMaterial);
}
}
}
///
/// Update to request Map every 1 second
///
void Update()
{
if (zed.IsCameraReady && canUpdate) //Don't do anything unless the ZED has been initialized.
{
updateTime += Time.deltaTime;
if (updateTime >= 1)
{
zed.RequestMesh();
updateTime = 0;
}
}
}
///
/// On Render Fct
///
void OnRenderObject()
{
if (zed != null)
{
int nbPoints = 0;
zed.UpdateFusedPointCloud(ref nbPoints);
if (nbPoints > 0)
{
vertPoints = new Vector4[nbPoints];
zed.RetrieveFusedPointCloud(vertPoints);
if (_pointBuffer != null)
{
_pointBuffer.Release();
_pointBuffer = null;
}
_pointBuffer = new ComputeBuffer(nbPoints, elementSize);
_pointBuffer.SetData(vertPoints);
}
}
if (_pointBuffer != null)
{
//Draw with Point shader
if (_pointSize == 0)
{
_pointMaterial.SetPass(0);
_pointMaterial.SetMatrix("_Transform", transform.localToWorldMatrix);
_pointMaterial.SetBuffer("_PointBuffer", _pointBuffer);
#if UNITY_2019_1_OR_NEWER
Graphics.DrawProceduralNow(MeshTopology.Points, _pointBuffer.count, 1);
#else
Graphics.DrawProcedural(MeshTopology.Points, _pointBuffer.count, 1);
#endif
}
//Draw with Disk shader
else
{
_diskMaterial.SetPass(0);
_diskMaterial.SetMatrix("_Transform", transform.localToWorldMatrix);
_diskMaterial.SetBuffer("_PointBuffer", _pointBuffer);
_diskMaterial.SetFloat("_PointSize", _pointSize);
#if UNITY_2019_1_OR_NEWER
Graphics.DrawProceduralNow(MeshTopology.Points, _pointBuffer.count, 1);
#else
Graphics.DrawProcedural(MeshTopology.Points, _pointBuffer.count, 1);
#endif
}
}
}
}
}