private async void Update()
        {
            // even though this is an 'async' function, unity will call Update each frame
            // even if a previous update is awaiting.
            if (_awaiting)
            {
                return;
            }

            Action nextAction;
            Tuple <ObjectAnchorsBoundingBox, IEnumerable <ObjectQuery> > nextQuery;

            if (UpdateQueue.TryDequeue(out nextAction))
            {
                nextAction();
            }
            else if (_queryQueue.TryDequeue(out nextQuery))
            {
                _awaiting     = true;
                QueryActive   = true;
                ActiveQueries = nextQuery;
                await _objectAnchorsService.DetectObjectAsync(nextQuery.Item2.ToArray());

                ActiveQueries = null;
                QueryActive   = false;
                _awaiting     = false;
            }
            else if (_objectAnchorsService.Status == ObjectAnchorsServiceStatus.Running)
            {
                if (TrackingStrategy == TrackingModeStrategy.Auto)
                {
                    ManageLocatedObjectTrackingStates();
                }

                // If nothing has been found, try another query.
                if (_instanceToTrackedObject.Count == 0 && ActiveDetectionStrategy == DetectionStrategy.Auto)
                {
                    RefillGlobalQueryQueue();
                }
            }
        }
예제 #2
0
    private Task DetectObjectAsync(Microsoft.Azure.ObjectAnchors.SpatialGraph.SpatialGraphCoordinateSystem?coordinateSystem, ObjectAnchorsLocation cameraLocation)
    {
        //
        // Coordinate system may not be available at this time, try it later.
        //

        if (!coordinateSystem.HasValue)
        {
            return(Task.CompletedTask);
        }

        //
        // Get camera location and coordinate system.
        //

        var cameraForward           = cameraLocation.Orientation * Vector3.forward;
        var estimatedTargetLocation = new ObjectAnchorsLocation
        {
            Position    = cameraLocation.Position + cameraForward * SearchFrustumFarDistance * 0.5f,
            Orientation = Quaternion.Euler(0.0f, cameraLocation.Orientation.eulerAngles.y, 0.0f),
        };

        //
        // Remove detected objects far away from the camera.
        //

        foreach (var instance in _objectAnchorsService.TrackingResults)
        {
            var location = instance.Location;
            if (location.HasValue)
            {
                var modelBbox = _objectAnchorsService.GetModelBoundingBox(instance.ModelId);
                Debug.Assert(modelBbox.HasValue);

                // Compute the coordinate of instance bounding box center in Unity world.
                var instancePosition = location.Value.Position + location.Value.Orientation * modelBbox.Value.Center;

                var offset = instancePosition - cameraLocation.Position;

                if (offset.magnitude > SearchFrustumFarDistance * 1.5f)
                {
                    _objectAnchorsService.RemoveObjectInstance(instance.InstanceId);
                }
            }
        }

        //
        // Detect object(s) in field of view, bounding box, or sphere.
        //

        var objectQueries = new List <Microsoft.Azure.ObjectAnchors.ObjectQuery>();

        var trackingResults = _objectAnchorsService.TrackingResults;

        lock (_objectQueries)
            foreach (var objectQuery in _objectQueries)
            {
                var modelId = objectQuery.Key;
                var query   = objectQuery.Value.Query;

                //
                // Optionally skip a model detection if an instance is already found.
                //

                if (SearchSingleInstance)
                {
                    if (trackingResults.Where(r => r.ModelId == modelId).Count() > 0)
                    {
                        continue;
                    }
                }

                var modelBox = _objectAnchorsService.GetModelBoundingBox(modelId);
                Debug.Assert(modelBox.HasValue);

                query.SearchAreas.Clear();
                switch (SearchAreaShape)
                {
                case SearchAreaKind.Box:
                {
                    // Adapt bounding box size to model size. Note that Extents.z is model's height.
                    float modelXYSize = new Vector2(modelBox.Value.Extents.x, modelBox.Value.Extents.y).magnitude;

                    var boundingBox = new ObjectAnchorsBoundingBox
                    {
                        Center      = estimatedTargetLocation.Position,
                        Orientation = estimatedTargetLocation.Orientation,
                        Extents     = new Vector3(modelXYSize * SearchAreaScaleFactor, modelBox.Value.Extents.z * SearchAreaScaleFactor, modelXYSize * SearchAreaScaleFactor),
                    };

                    query.SearchAreas.Add(
                        Microsoft.Azure.ObjectAnchors.ObjectSearchArea.FromOrientedBox(
                            coordinateSystem.Value,
                            boundingBox.ToSpatialGraph()));
                    break;
                }

                case SearchAreaKind.FieldOfView:
                {
                    var fieldOfView = new ObjectAnchorsFieldOfView
                    {
                        Position    = cameraLocation.Position,
                        Orientation = cameraLocation.Orientation,
                        FarDistance = SearchFrustumFarDistance,
                        HorizontalFieldOfViewInDegrees = SearchFrustumHorizontalFovInDegrees,
                        AspectRatio = SearchFrustumAspectRatio,
                    };

                    query.SearchAreas.Add(
                        Microsoft.Azure.ObjectAnchors.ObjectSearchArea.FromFieldOfView(
                            coordinateSystem.Value,
                            fieldOfView.ToSpatialGraph()));
                    break;
                }

                case SearchAreaKind.Sphere:
                {
                    // Adapt sphere radius to model size.
                    float modelDiagonalSize = modelBox.Value.Extents.magnitude;

                    var sphere = new ObjectAnchorsSphere
                    {
                        Center = estimatedTargetLocation.Position,
                        Radius = modelDiagonalSize * 0.5f * SearchAreaScaleFactor,
                    };

                    query.SearchAreas.Add(
                        Microsoft.Azure.ObjectAnchors.ObjectSearchArea.FromSphere(
                            coordinateSystem.Value,
                            sphere.ToSpatialGraph()));
                    break;
                }
                }

                objectQueries.Add(query);
            }

        //
        // Pause a while if detection is not required.
        //

        if (objectQueries.Count == 0)
        {
            Thread.Sleep(100);

            return(Task.CompletedTask);
        }

        //
        // Run detection.
        //

        // Add event to the queue.
        _objectAnchorsEventQueue.Enqueue(
            new ObjectAnchorsServiceEvent
        {
            Kind = ObjectAnchorsServiceEventKind.DetectionAttempted,
            Args = null
        });

        return(_objectAnchorsService.DetectObjectAsync(objectQueries.ToArray()));
    }