SpatialUnderstanding

首先,进行Hololens项目的基本设置,并添加Spatial Mapping和Spatial Understanding 组件到Hierarchy面板中。Spatial Understanding模型主要暴露了三种类型的接口,简单平面的拓扑,空间查询,物体形状检测。要通过Spatial Understanding放置游戏对象到墙上或者椅子上,首先需要获取Spaital Understanding扫描到的房间数据。

Paste_Image.png

勾选Spatial Understanding 组件的Auto Begin Scanning参数,应用就会在启动时开始扫描房间。或者通过RequestBeginScanning()方法来手动开始扫描。无论使用哪种方法开始扫描,都要通过RequsetFinishScan()方法来结束扫描。关于扫描的进度和状态,可以通过ScanStates来获取。

      public enum ScanStates
{
        //当前没有扫描进程
        None,
           //应用已就绪,可以开始扫描
    ReadyToScan,
    //正在扫描中
    Scanning,
    //已结束扫描
    Finishing,
    //扫描进程结束
    Done
}
//如果当前扫描状态是没有扫描
if(SpatialUnderstanding.Instace.ScanState == SpatialUnderstanding.ScanState.Done){
//Do
}

SpatialUnderstandingDll.cs开始扫描后,SpatialUnderstandingDll.cs脚本就会被调用,扫描的主要逻辑都会在这个脚本中完成。此脚本中的功能主要被分成了三部分:

1 SpatialUnderstandingDllTopology
2 SpatialUnderstandingDllShapes
3 SpatialUnderstandingObjectPlacement

在使用SpatialUnderstandingDll中的功能前,必须首先调用SpatialUnderstanding_Init()方法进行初始化。以上三个部分都在单独的脚本中实现,SpatialUnderstandingDllTopology.cs、SpatialUnderstandingDllShape.cs、SpatialUnderstandingObjectPlacement.cs,每个脚本所实现的功能将在后文中介绍。SpatialUnderstandingDllTopology.cs此脚本中封装了关于当前环境的信息,它能分析出哪里是墙,哪里是地面,哪里是天花板等信息。这些信息都存储在PlaySpaceInfos结构体中。也可以根据参数指定数据,脚本中提供的方法有:

 1 QueryTopology_FindPositionsOnWalls
 2 QueryTopology_FindLargePositionsOnWalls
 3 QueryTopology_FindLargestWall
 4 QueryTopology_FindPositionsOnFloor
 5 QueryTopology_FindLargestPositionsOnFloor
 6 QueryTopology_FindPositionsSittable

具体参数可以查看脚本源码。以下是一个简单示例,查询环境中符合条件的墙的数量。

//定义存储查询结果的数组
private SpatialUnderstandingDllTopology.TopologyResult[] resultsTopology = new SpatialUnderstandingDllTopology.TopologyResult;

public void Query_Topology_FindPositionOnWall()
{
        // 确定当前SpatialUnderstanding组件状态为可用。
        if (!SpatialUnderstanding.Instance.AllowSpatialUnderstanding){
                return;
        }

        // 定义参数,分别是墙面的最小高度,最小宽度,最高点和地面的距离,最后一个我也不知道..
        float minHeightOfWallSpace = 0.5f;
        float minWidthOfWallSpace = 0.75f;
        float minHeightAboveFloor = 1.25f;
        float minFacingClearance = 1.5f;

        // 在内存中挂起resultTopology,避免内存地址变化
        IntPtr resultsTopologyPtr = SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(resultsTopology);
        //执行查询操作并将数量返回给locationCount
        int locationCount = SpatialUnderstandingDllTopology.QueryTopology_FindPositionsOnWalls(
        minHeightOfWallSpace, minWidthOfWallSpace, minHeightAboveFloor, minFacingClearance,
        resultsTopology.Length, resultsTopologyPtr);
}

SpaitalUnderstandingDllShapes.cs此脚本实现了查询某种形状的物体的功能。开发者可以指定各个参数,然后脚本会根据参数,找出环境中符合参数的地点。

//形状的组件
shapeComponents = new List<ShapeComponent>()
{
    new ShapeComponent(
       //形状组件约束
      new List<ShapeComponentConstraint>()
      {
                  //定义高度
            ShapeComponentConstraint.Create_SurfaceHeight_Between(0.2f, 0.6f),
            ShapeComponentConstraint.Create_SurfaceCount_Min(1),
            //定义面积
            ShapeComponentConstraint.Create_SurfaceArea_Min(0.035f),
      }
    ),
};
AddShape("Sittable", shapeComponents);

以上代码定义了一个可以”坐”的区域。更多示例可以在ShapeDefinition.cs中找到。SpatialUnderstandingObjectPlacement.cs如果需要放置对象在指定地点,比如放置一个方块在椅子上,就需要使用Solver.PlaceObject()方法了。这个方法是一个查询语句,如果找到符合条件的地点,就会返回一个1(即true),否则返回0(false)。

      //解算器_处对象
public static int Solver_PlaceObject(
        //注意,此参数不是需要放置的对象的名字。而是此语句的名字。
        string objectName,
        //想要放置的地点,具体参数在ObjectPlacementDefinition结构体中定义
        IntPtr placementDefinition,// ObjectPlacementDefinition
        //规则的数量
        int placementRuleCount,
        //具体有哪些规则
        IntPtr placementRules,   // ObjectPlacementRule
        //约束的数量
        int constraintCount,
        //具体的约束条件
        IntPtr placementConstraints,// ObjectPlacementConstraint
        //返回结果
        IntPtr placementResult)
        {
            return 0;
        }

以上语句会根据指定参数,在环境中找到符合要求的地点,并将结果返回到placementResult中。通过placementResult即可获得结果中的各个数据。关于放置地点的参数,ObjectPlacementDefinition结构体中定义了9种参数:

public enum PlacementType{
        Place_OnFloor,
        Place_OnWall,
        Place_OnCeiling,
        Place_OnShape,
        Place_OnEdge,
        Place_OnFloorAndCeiling,
        Place_RandomInAir,
        Place_InMidAir,
        Place_UnderPlatformEdge,
};

规则有3种:

public enum ObjectPlacementRuleType{
        Rule_AwayFromPosition,
        Rule_AwayFromWalls,
        Rule_AwayFromOtherObjects,
};

约束条件有6种:

public enum ObjectPlacementConstraintType{
Constraint_NearPoint,
Constraint_NearWall,
Constraint_AwayFromWalls,
Constraint_NearCenter,
Constraint_AwayFromOtherObjects,
Constraint_AwayFromPoint
};

下面是实际使用中的示例:

public void CreateOnFloor() {
  //对象位置规则
        List<SpatialUnderstandingDllObjectPlacement.ObjectPlacementRule> placementRules = null;
  //对象位置约束
        List<SpatialUnderstandingDllObjectPlacement.ObjectPlacementConstraint> placementConstraints = null;
      //一半的大小
        float halfDimSize = UnityEngine.Random.Range(0.15f, 0.35f);

        SpatialUnderstandingDllObjectPlacement.ObjectPlacementDefinition myPlacementDefinition =
                                    SpatialUnderstandingDllObjectPlacement.ObjectPlacementDefinition.Create_OnFloor(new Vector3(halfDimSize,
                halfDimSize, halfDimSize * 2));



        if (SpatialUnderstandingDllObjectPlacement.Solver_PlaceObject("place a chen on floor", 
            SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(myPlacementDefinition),
(placementRules != null) ? placementRules.Count : 0,
((placementRules != null) && (placementRules.Count > 0)) ? SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(placementRules.ToArray()) : IntPtr.Zero,
(placementConstraints != null) ? placementConstraints.Count : 0,
((placementConstraints != null) && (placementConstraints.Count > 0)) ? SpatialUnderstanding.Instance.UnderstandingDLL.PinObject(placementConstraints.ToArray()) : IntPtr.Zero,
            SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticObjectPlacementResultPtr()) > 0
) {SpatialUnderstandingDllObjectPlacement.ObjectPlacementResult placementResult = SpatialUnderstanding.Instance.UnderstandingDLL.GetStaticObjectPlacementResult();
        //Instantiate chan on result position
        GameObject myChan =Instantiate(chan,placementResult.Position,Quaternion.LookRotation(holoCamera.transform.position));
        if (myChan != null) {
                nofityText.text = "已定位";
        }else {
                nofityText.text = "未找到合适地点";
        }
}
}

以上代码中,首先设置规则和约束条件为null,即不进行约束。然后将查询条件设置为Create_OnFloor。随后通过If语句判断查询是否成功。如果查询到可用地点,则通过GetStaticObjectPlacementResult()方法取出查询到的结果。获取查询到的结果后,通过placementResult.Position获取符合条件的坐标点。再使用该坐标点生成游戏对象。以上代码没有设置规则和约束条件,只是指定为Floor,所以会在地面上生成对象,坐标为摄像机原点。更多详细的示例都在HoloToolkit-Examples/SpatialUnderstanding中。

查看完整版本: SpatialUnderstanding

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,926评论 6 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,629评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,761评论 25 707
  • 曾几何时,我以为拖延症离我很远,我一直觉得自己是一个想到什么就能立刻去做的急性子。当接近而立之年时,我突然意识到,...
    Boheatea阅读 266评论 0 0