zoukankan      html  css  js  c++  java
  • HoloLens开发手记

    本文主要讨论如何在Unity项目中集成空间映射功能。Unity内置了对空间映射功能的支持,通过以下两种方式提供给开发者:

    1. HoloToolkit项目中你可以找到空间映射组件,这可以让你便捷快速地开始使用空间映射特性。
    2. Unity还提供更多底层的空间映射API,以便开发者能够完全控制空间映射特性,满足定制复杂的应用需求

    为了在应用使用空间映射特性,你必须在应用权限清单中启用SpatialPerception能力。

    Setting the SpatialPerception capability 设置SpatialPerception能力


     

    为了使应用能够使用空间映射数据,SpatialPerception能力必须被启用。

    使用以下步骤启用此能力:

    1. 在Unity编辑器中,进入Player Settings选项(Edit > Project Settings > Player)
    2. 点击Window Store选项卡
    3. 展开Publish Settings选项,并在Capabilities列表勾选SpatialPerception选项

    注意:如果你已经把Unity项目导出为Visual Studio项目,你需要重新导出修改后的项目到新文件夹或者手动在VS中修改AppxManifest应用清单

    空间映射特性也要求项目MaxVersionTested版本最低为10.0.10586.0

    1. 在VS项目解决方案中,双击Package.appxmanifest文件,并右键选中查看源码方式打开
    2. 找到TargetDeviceFamily这一行,并将MaxVersionTested="10.0.10240.0" 修改为 MaxVersionTested="10.0.10586.0"
    3. 保存Package.appmanifest文件

    Spatial mapping components 空间映射组件


     

    HoloToolkit项目提供了几个方案帮助你简单快速集成空间映射特性。

    对于默认的空间映射需求,我们推荐使用SpatialMappingComponent目录下的 SpatialMappingCollider.csSpatialMapppingRenderer.cs脚本。如果你需要从网络或者文件载入空间网格,可以使用SpatialMapping目录下的脚本。

    额外的信息可以在HoloToolkit项目Github主页上找到。

    How to use the API 如何使用底层API


     

    命名空间UnityEngine.VR.WSA

    类型: SurfaceObserverSurfaceChangeSurfaceDataSurfaceId

    SurfaceObserver是主要使用到的API对象,下面是应用使用空间映射特性推荐的大致流程。

    Set up the SurfaceObserver(s) 设定SurfaceObserver对象

    你要为每一个需要空间映射数据的空间区域在应用中初始化一个SurfaceObserver对象。

    SurfaceObserver surfaceObserver;
    
     void Start () {
         surfaceObserver = new SurfaceObserver();
     }

    通过调用SetVolumeAsSphere、SetVolumeAsAxisAlignedBox、 SetVolumeAsOrientedBox、 或 SetVolumeAsFrustum方法可以为每个SurfaceObserver对象指定它们需要获取数据的空间范围。以后你还可以通过再次调用它们来重新设定检测的空间范围。

    void Start () {
        ...
         surfaceObserver.SetVolumeAsAxisAlignedBox(Vector3.zero, new Vector3(3, 3, 3));
    }

    当你调用SurfaceObserver.Update()方法时,需要每一个SurfaceObserver对象检测区域中的空间表面(spatial surface)指定事件处理方法。

    private void OnSurfaceChanged(SurfaceId surfaceId, SurfaceChange changeType, Bounds bounds, System.DateTime updateTime)
     {
        //处理空间表面变化
     }

    Handling Surface Changes 处理空间表面变化

     

    关于空间表面变化,有几个典型情形需要处理。Added状态和Updated状态可以使用相同的代码处理,Removed状态则使用另一种代码来处理。

    • 在Added和Updated情形下,我们从字典中添加或者获取代码当前网格的对象,使用必要的组件来创建一个SurfaceData结构体,然后调用RequestMeshDataAsync方法在场景中使用网格数据和位置来填充对象。
    • 在Removed情形下,我们从字典中移除当前网格代表的对象并销毁它。
    System.Collections.Generic.Dictionary<SurfaceId, GameObject> spatialMeshObjects = new System.Collections.Generic.Dictionary<SurfaceId, GameObject>();
    
       private void OnSurfaceChanged(SurfaceId surfaceId, SurfaceChange changeType, Bounds bounds, System.DateTime updateTime)
       {
           switch (changeType)
           {
               case SurfaceChange.Added:
               case SurfaceChange.Updated:
                   if (!spatialMeshObjects.ContainsKey(surfaceId))
                   {
                       spatialMeshObjects[surfaceId] = new GameObject("spatial-mapping-" + surfaceId);
                       spatialMeshObjects[surfaceId].transform.parent = this.transform;
                       spatialMeshObjects[surfaceId].AddComponent<MeshRenderer>();
                   }
                   GameObject target = spatialMeshObjects[surfaceId];
                   SurfaceData sd = new SurfaceData(
                       //系统返回的surface id,
                       //当前对象的MeshFilter组件
                       target.GetComponent<MeshFilter>() ?? target.AddComponent<MeshFilter>(),
                       //用于在空间中定位对象的空间锚
                       target.GetComponent<WorldAnchor>() ?? target.AddComponent<WorldAnchor>(),
                       //当前网格对象的MeshCollider组件
                       target.GetComponent<MeshCollider>() ?? target.AddComponent<MeshCollider>(),
                       //每立方米网格三角形的数量
                       1000,
                       //bakeMeshes -如果是true,MeshCollider会被数据填充,反之MeshCollider为空
                       true
                       );
    
                   SurfaceObserver.RequestMeshAsync(sd, OnDataReady);
                   break;
               case SurfaceChange.Removed:
                   var obj = spatialMeshObjects[surfaceId];
                   spatialMeshObjects.Remove(surfaceId);
                   if (obj != null)
                   {
                       GameObject.Destroy(obj);
                   }
                   break;
               default:
                   break;
           }
       }

    Handing Data Ready 处理DataReady事件

     

    OnDataReady事件方法会接收到一个SurfaceData对象,它包含了WorldAnchor、MeshFilter和MeshCollider对象数据,表示了当前关联的空间表面最新状态。通过访问Mesh Filter对象的Mesh数据可以进行性能分析或者处理网格。使用最新的Mesh数据来渲染空间表面并将它用于物理碰撞或者射线击中对象。确认SurfaceData内容不为空很重要。

    Start processing on updates 处理更新操作

    SurfaceObserver.Update()方法只能延时调用,可以每帧更新都调用。

    void Start () {
        ...
         StartCoroutine(UpdateLoop());
    }
    
     IEnumerator UpdateLoop()
        {
            var wait = new WaitForSeconds(2.5f);
            while(true)
            {
                surfaceObserver.Update(OnSurfaceChanged);
                yield return wait;
            }
        }

    HoloToolKit


     

    HoloToolkit项目是基于Unity API封装的一系列很有用的全息开发代码工具集合,能帮助开发者快速集成HoloLens特性。

    Troubleshooting 问题诊断


    • 确保你启用了 SpatialPreception能力

    • 当追踪焦点丢失时,在接下来的OnSurfaceChanged事件处理中将会移除现有所有的网格。
  • 相关阅读:
    1058 A+B in Hogwarts (20)
    1036. Boys vs Girls (25)
    1035 Password (20)
    1027 Colors in Mars (20)
    1009. Product of Polynomials (25)
    1006. Sign In and Sign Out
    1005 Spell It Right (20)
    1046 Shortest Distance (20)
    ViewPager页面滑动,滑动到最后一页,再往后滑动则执行一个事件
    IIS7.0上传文件限制的解决方法
  • 原文地址:https://www.cnblogs.com/mantgh/p/5626796.html
Copyright © 2011-2022 走看看