//======= 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 } } } } }