HoloToolkit空间理解和对象放置

时间:2016-11-23 17:42:27

标签: hololens

我一直在尝试使用从spatialunderstandingExample场景中获取的数据将对象放入房间。但是代码对我来说真是不可理解。是否有人使用spatialtoolkitexample实现了这一目标?有什么帮助吗?

https://github.com/Microsoft/HoloToolkit-Unity/tree/master/Assets/HoloToolkit-Examples/SpatialUnderstanding/SpatialUnderstanding-FeatureOverview/Scripts

所有脚本都在这里,在UI脚本中调用Query_OnFloor_AwayFromMe()然后我有点忘记了代码,直到调用了linedrawer脚本的draw_box。在draw_box中,我尝试了以下方法将全息图放在那里,但没有任何显示。

 @android:style/Theme.Holo.Light.DarkActionBar

1 个答案:

答案 0 :(得分:0)

我将首先尝试解释此示例中发生的情况。从UI.cs中的调用开始到Query_OnFloor_AwayFromMe()...

  1. 这会调用LevelSolver.cs。在这个方法中,它创建一个新的PlacementQuery对象并调用PlaceObjectAsync。
  2. PlaceObjectAsync通过调用System.Threading.Tasks.Task.Run创建一个新线程,其中调用空间理解的实际工作即将完成。这项工作必须在一个单独的线程中完成,因为它需要很长时间,因此需要跨多个帧执行,否则您的应用程序将在执行期间锁定。
  3. 在调用新线程PlaceObject时,这会调用空间理解(SpatialUnderstandingDllObjectPlacement.Solver_PlaceObject),这是对C ++ HoloToolkit的调用,这是需要很长时间的调用。完成后,结果将添加到placementResults,这基本上是一个工作队列。
  4. 在LevelSolver.cs中有一个Update方法,每次unity绘制一个新帧时都会调用它。这里有一个调用Draw_PlacementResults。
  5. Draw_PlacementResults循环遍历placementResults工作队列中的每个结果,并在LineDrawer.cs中调用Draw_AnimatedBox
  6. 这就是你如何看待我们在上一个问题中讨论过的Draw_Box。
  7. 所以另一个问题是我如何修改这个例子来建立你自己的模型。我建议你在LevelSolver.cs中进行修改。尝试将Update()更改为以下内容:

    private void Update()
    {
        // Can't do any of this till we're done with the scanning phase
        if (SpatialUnderstanding.Instance.ScanState != SpatialUnderstanding.ScanStates.Done)
        {
            return;
        }
    
        // Make sure the solver has been initialized
        if (!IsSolverInitialized &&
            SpatialUnderstanding.Instance.AllowSpatialUnderstanding)
        {
            InitializeSolver();
        }
    
        // Constraint queries
        if (SpatialUnderstanding.Instance.ScanState == SpatialUnderstanding.ScanStates.Done)
        {
            Update_Queries();
        }
    
        // Handle async query results
        ProcessPlacementResults();
    
        MyProcessPlacementResults();
    }
    

    这将导致它停止绘制框,而是调用" MyProcessPlacementResults"处理结果的事情。我会在LevelSolver.cs中添加类似这样的方法。 (在代码I' m借用我正在创建一棵树)

    private void MyProcessPlacementResults()
    {
        if (placementResults.Count > 0)
        {
            var toPlace = placementResults.Dequeue();
    
            var rotation = Quaternion.LookRotation(toPlace.Result.Forward, Vector3.up);
            CreateTree(toPlace.Result.Position, rotation);
    
        }
    }
    

    以下是我用来在正确的位置实际实例化树的代码:

    private GameObject ThisIsYourCustomModelInMineItWasATree;
    private Vector3 TheSizeIPassedToSpatialUnderstanding = new Vector3(1, 1, 1);
    
    public void CreateHologram(Vector3 positionCenter, Quaternion rotation)
    {
        ThisIsYourCustomModelInMineItWasATree = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    
        GameObject newObject = Instantiate(ThisIsYourCustomModelInMineItWasATree, positionCenter, rotation) as GameObject;
    
        if (newObject != null)
        {
            // Set the parent of the new object the GameObject it was placed on
            newObject.transform.parent = gameObject.transform;
    
            newObject.transform.localScale = StretchToFit(ThisIsYourCustomModelInMineItWasATree, TheSizeIPassedToSpatialUnderstanding);
            newObject.AddComponent<MeshCollider>();
        }
    }
    

    为了完整起见,这里是我用来将其缩放到所需大小的代码:

    private Vector3 StretchToFit(GameObject obj, Vector3 desiredSize)
    {
        var curBounds = GetBoundsForAllChildren(obj).size;
    
        return new Vector3(desiredSize.x / curBounds.x / 2, desiredSize.y, desiredSize.z / curBounds.z / 2);
    }
    
    private Bounds GetBoundsForAllChildren(GameObject findMyBounds)
    {
        Bounds result = new Bounds(Vector3.zero, Vector3.zero);
    
        foreach (var renderer in findMyBounds.GetComponentsInChildren<Renderer>())
        {
            if (result.extents == Vector3.zero)
            {
                result = renderer.bounds;
            }
            else
            {
                result.Encapsulate(renderer.bounds);
            }
        }
    
        return result;
    }
    

    我还将私有变量placementResults从List更改为Queue。我这样做是因为List用于在每一帧中绘制一个框。我们想要一个队列,因为我们要实例化一个新对象,让统一引擎管理它。找到这一行:

    private List<PlacementResult> placementResults = new List<PlacementResult>();
    

    并将其更改为:

    private Queue<PlacementResult> placementResults = new Queue<PlacementResult>();
    

    完成更改后,您需要修复几个地方。删除Draw_PlacementResults方法,无论如何都不再使用它。将调用placementResults.Add的两个地方更改为placementResults.Enqueue。