美文网首页
SpatialUnderstanding

SpatialUnderstanding

作者: Moment__格调 | 来源:发表于2017-08-09 09:53 被阅读112次

    首先,进行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

    相关文章

      网友评论

          本文标题:SpatialUnderstanding

          本文链接:https://www.haomeiwen.com/subject/cujfrxtx.html