EasyAR4.0开发 (SpatialMap空间地图四)

这篇文章主要通过SpatialMap_Sparse_ImageTarget这个场景,说明一下实现稀疏空间地图的脚本。

一、SparseSpatialMapController脚本

     public enum DataSource
        {
            MapBuilder,
            MapManager,
        }

      public class SparseSpatialMapInfo
        {
            public string ID = string.Empty;
            public string Name = string.Empty;
        }

这是指定稀疏地图的数据来自哪里,MapBuilder是自身建造,就是通过相机自己识别空间。MapManager是加载从服务器下载的数据使用。  SparseSpatialMapInfo就是用来区别地图信息的

 private void LoadMapBuilderInfo()
        {
            MapInfo = new SparseSpatialMapInfo(); //地图信息
            if (MapInfoAvailable != null)  //地图信息可用,回调
            {
                MapInfoAvailable();
            }
            UpdateMapInLocalizer();
        }

  private void LoadMapManagerInfo(MapManagerSourceData source)
        {
            if (!string.IsNullOrEmpty(source.ID))
            {
                MapInfo = new SparseSpatialMapInfo() { ID = source.ID, Name = source.Name };
                if (MapInfoAvailable != null)
                {
                    MapInfoAvailable();
                }
                UpdateMapInLocalizer();
            }
        }

MapBuilder首先创建一个默认的地图信息ID和Name,然后更新地图

MapManager会传入MapManagerSourceData,这个类包含的数据和SparseSpatialMapInfo一样,就相当于传入准备好的地图的id和name

 private void UpdateMapInLocalizer()  //在定位器中更新地图
        {
            if (MapInfo == null)  //不管哪种方式都需要SparseSpatialMapInfo数据
            {
                return;
            }
            if ((SourceType == DataSource.MapBuilder && !string.IsNullOrEmpty(MapInfo.ID)) ||
                (SourceType != DataSource.MapBuilder && string.IsNullOrEmpty(MapInfo.ID)))
            {   //如果属于MapBuilder,那么你的地图id就应该是空的
                return;     //如果属于MapManager,地图id就不能是空的
            }
            if (loader && loader != mapWorker)  //loader没有被刷新,相当于使用之前的loader
            {
                switch (SourceType)
                {
                    case DataSource.MapBuilder:
                        loader.UnloadSparseSpatialMapBuild(this);  //卸载这个地图
                        loader = null;
                        break;
                    case DataSource.MapManager:
                        loader.UnloadSparseSpatialMap(this, (map, status, error) =>
                        {
                            if (MapUnload != null)       //卸载地图回调
                            {
                                MapUnload(map, status, error);
                            }
                        });
                        loader = null;
                        break;
                    default:
                        break;
                }
            }
            if (mapWorker && mapWorker != loader) //mapWorker 保存对应的地图处理SparseSpatialMapWorkerFrameFilter类
            {
                var worker = mapWorker;
                switch (SourceType)
                {
                    case DataSource.MapBuilder:                 
                        mapWorker.LoadSparseSpatialMapBuild(this); //初始化地图建造
                        loader = mapWorker;
                        break;
                    case DataSource.MapManager:
                        mapWorker.LoadSparseSpatialMap(this, (map, status, error) =>  //加载地图数据
                        {
                            if (worker == mapWorker && !status)
                            {
                                loader = null;
                            }
                            if (MapLoad != null)
                            {
                                MapLoad(map, status, error);
                            }
                        });
                        loader = mapWorker;
                        break;
                    default:
                        break;
                }
            }
        }
 internal void UpdatePointCloud(Buffer buffer)
        {
            var bufferFloat = new float[buffer.size() / 4];

            if (buffer.size() > 0)
            {
                Marshal.Copy(buffer.data(), bufferFloat, 0, bufferFloat.Length);
            }
            PointCloud = Enumerable.Range(0, bufferFloat.Length / 3).Select(k =>
            {
                return new Vector3(bufferFloat[k * 3], bufferFloat[k * 3 + 1], -bufferFloat[k * 3 + 2]);
            }).ToList();

            UpdatePointCloud();
        }

获取到数据后SparseSpatialMapWorkerFrameFilter会调用UpdatePointCloud让你更新数据,Buffer这个类保存和数据地址,和数据长度。数据保存的方式是Byte,因此创建float数据,长度除以4。Marshal.Copy通过地址和长度复制出数据。float数组就是3个为一组,组成一个点的坐标保存再PointCloud中。

 private void UpdatePointCloud()
        {
            if (!PointCloudParticleSystem)
            {
                return;
            }

            if (!ShowPointCloud || PointCloud == null)
            {
                PointCloudParticleSystem.Clear();
                return;
            }

            var particles = PointCloud.Select(p =>
            {
                var particle = new ParticleSystem.Particle();
                particle.position = p;
                particle.startLifetime = pointCloudParticleParameter.StartLifetime;
                particle.remainingLifetime = pointCloudParticleParameter.RemainingLifetime;
                particle.startSize = pointCloudParticleParameter.StartSize;
                particle.startColor = pointCloudParticleParameter.StartColor;
                return particle;
            }).ToArray();
            PointCloudParticleSystem.SetParticles(particles, particles.Length);
        }

这个就是根据点数据,更新粒子的数据。就是屏幕上看到的很多点。要修改点的效果,就可以把粒子改成其他的东西

  // pointInView should be normalized to [0, 1]
        public List<Vector3> HitTest(Vector2 pointInView)
        {
            var points = new List<Vector3>();
            if (!IsLocalizing || !mapWorker || mapWorker.Localizer == null)
            {
                return points;
            }

            var session = mapWorker.Session;
            if (!session || session.FrameCameraParameters.OnNone || session.Assembly == null || !session.Assembly.Camera)
            {
                return points;
            }

            var coord = EasyARController.Instance.Display.ImageCoordinatesFromScreenCoordinates(pointInView, session.FrameCameraParameters.Value, session.Assembly.Camera);
            var hitPoints = mapWorker.Localizer.hitTestAgainstPointCloud(coord.ToEasyARVector());
            foreach (var p in hitPoints)
            {
                points.Add(new Vector3(p.data_0, p.data_1, -p.data_2));
            }
            return points;
        }

这个函数是测试是否点击到点云的,如果点击到,那么就会按照点云从近到远的顺序返回一个坐标数组。传入的是屏幕坐标

 public void Host(string name, Optional<Image> preview)
        {
            if (SourceType != DataSource.MapBuilder || MapInfo == null || !string.IsNullOrEmpty(MapInfo.ID) || !mapWorker || mapWorker.Builder == null)
            {
                throw new Exception("Map Unhostable");
            }
            mapWorker.HostSparseSpatialMap(this, name, preview, (map, status, error) =>
            {
                if (MapHost != null)
                {
                    MapHost(map, status, error);
                }
            });
        }

上传数据到服务器 preview是一张相机的截屏,就是方便你区分那个场景。上传成功会回调一个id,用于下载。

下篇文章讲解SparseSpatialMapWorkerFrameFilter这个类。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值