【问题标题】:HoloToolkit Spatial Understanding and Object PlacementHoloToolkit 空间理解和对象放置
【发布时间】:2017-03-25 07:19:38
【问题描述】:

我一直在尝试使用从空间理解示例场景中获取的数据将对象放入房间。但是代码对我来说真的无法理解。有人使用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 中,我尝试了以下方法将我的全息图带到那里,但没有任何显示。

  mydummy.SetActive(true);
  mydummy.transform.position = new Vector3(center.x,center.y,center.z);

【问题讨论】:

  • 根据您之前的问题 (stackoverflow.com/questions/40728179/…),您已经成功地将默认框替换为您自己的全息图,但您很难让它正确放置并缩放到正确的大小,之前我发布了一个答案,对吗?
  • 我以为我做到了,但这是我忘记关闭的游戏对象。所以我又回到了那里:(
  • 如果你能把你当前的代码贴在某个地方,我会看看。
  • 已更新,感谢卡梅隆

标签: hololens


【解决方案1】:

我将首先尝试解释此示例中发生的情况。从 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 循环遍历放置结果工作队列中的每个结果并调用 LineDrawer.cs 中的 Draw_AnimatedBox
  6. 这就是我们在上一个问题中讨论的对 Draw_Box 的调用的方式。

所以另一个问题是我如何修改这个例子来放置你自己的模型。我建议在 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 中添加类似这样的方法。 (在我借用的代码中,我正在创建一棵树)

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 用于在每一帧中绘制一个框。我们想要一个队列,因为我们将实例化一个新对象一次并让统一引擎管理它。找线:

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

并将其更改为:

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

进行更改后,您需要修复几个地方。删除方法 Draw_PlacementResults,反正它不再使用了。将调用placementResults.Add的两个地方改成placementResults.Enqueue。

【讨论】:

  • 这是您的实际代码吗?在 MyProcessPlacementResults() 中,我无法将放置结果出列,它不允许我这样做。我试着一一搞定还是不行……
  • 是的,它是我的代码,我从一个更大的项目中提取了它,这不是基于您正在处理的示例。你是对的,我的placementResults 是一个实际的队列,我将编辑我的答案以尝试修复它。
  • 不,这也不起作用。我想我现在将手动定位它们,感谢您的所有帮助。你介意和我分享你的项目吗?
  • 这让我很烦恼,因为我们没有让它工作......所以我做了一个 repo 并进行了所有更改并自己构建了它,然后修复了一些没有的东西对。此外,我定义了变量 ThisIsYourCustomModelInMineItWasATree、TheSizeIPassedToSpatialUnderstanding,因此它实际上可以按原样工作,无需更改。
  • 所有更新都在编辑后的答案中,几乎每一块代码都发生了一些变化,包括我完全错过的一个
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-03
  • 2018-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-26
  • 1970-01-01
相关资源
最近更新 更多