SpatialUnderstanding

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

SpatialUnderstanding_第1张图片
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()
{
    new ShapeComponent(
       //形状组件约束
      new List()
      {
                  //定义高度
            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 placementRules = null;
  //对象位置约束
        List 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)