Exemple #1
0
        /// Side effects:
        /// - May cause HandleIntersectionWithXxx to be called
        ///
        /// Returns true if and only if any "intersection actions" were carried out (ie,
        /// if at least one HandleIntersectionWithXxx call returned true)
        ///
        private bool UpdateGpuIntersection(Vector3 vDetectionCenter_GS, float size_GS)
        {
            // Possible states of m_GpuFutureResult and m_GpuFutureResultlist:
            //
            //   m_GpuFutureResult = null       No outstanding GPU request. m_GpuFutureResultList
            //                                  is unused, might contain garbage, and is ready to pass
            //                                  to a new GpuFutureResult
            //   m_GpuFutureResult != null
            //      IsReady = false             Request is running; will fill in m_GpuFutureResultList
            //      IsReady = true              Request is done; m_GpuFutureResultList is filled in
            //
            // Possible states of m_GpuOldResultList and m_GpuConsumedResults:
            //
            //   m_GpuOldResultList             Always not-null, but may have been fully-processed
            //   m_GpuConsumedResults           Indices >= this have yet to be consumed
            //
            // m_GpuFutureResult may be pending for multiple frames.
            // m_GpuOldResultList may be processed over multiple frames.

            if (m_GpuFutureResult == null)
            {
                // Note that m_GpuFutureResultList will be cleared and populated at some future point
                // after this call.
                int intersectionLayer = (1 << m_CurrentCanvas.gameObject.layer) |
                                        AdditionalGpuIntersectionLayerMasks();

                // The new request will only be null when the intersector is disabled.
                // Given the logic in this function, this should be fine without any special handling.
                // TODO: use a pool of List<BatchResult> instead of being so stateful
                m_GpuFutureResult = App.Instance.GpuIntersector
                                    .RequestBatchIntersections(vDetectionCenter_GS,
                                                               size_GS,
                                                               m_GpuFutureResultList,
                                                               255,
                                                               intersectionLayer);
            }
            else if (m_GpuFutureResult.IsReady)
            {
                // We could go use GpuResultList, but as we're swapping the buffers here, it feels better
                // to be explicit about which buffers we're swapping.

                // TODO: use m_GpuFutureResult.GetResults() instead
                List <GpuIntersector.BatchResult> results = m_GpuFutureResultList;
                m_GpuFutureResultList = m_GpuOldResultList;
                // Note that this throws away any results that have yet to be consumed.
                m_GpuOldResultList   = results;
                m_GpuConsumedResults = 0;

                // We could immediately submit another request, however we have likely already hit our budget
                // when there are intersections, so it should generally feel better to allow this to be a
                // three frame cycle.
                m_GpuFutureResult = null;
            }

            if (m_GpuConsumedResults < m_GpuOldResultList.Count)
            {
                int hitCount = 0;
                for (int i = m_GpuConsumedResults; i < m_GpuOldResultList.Count && !m_TimesUp; i++)
                {
                    // Prefer to find widgets, although the results struct should never have both.
                    if (m_GpuOldResultList[i].widget)
                    {
                        if (HandleIntersectionWithWidget(m_GpuOldResultList[i].widget))
                        {
                            hitCount++;
                        }
                    }
                    else
                    {
                        BatchSubset subset = m_GpuOldResultList[i].subset;
                        if (subset.m_ParentBatch == null)
                        {
                            // The stroke was deleted between creating the result and processing the result. This
                            // could happen due to the inherent latency in GPU intersection, although in practice,
                            // this should be very rare. But this will also happen if the selection tool intersects
                            // more than a single stroke in the same group. In this case, the following happens:
                            //
                            //   * HandleIntersectionWithBatchedStroke() is called once with one of the strokes in
                            //     the group.
                            //   * All the strokes in that group are moved to the selection canvas and thus, a
                            //     different subset.
                            //   * HandleIntersectionWithBatchedStroke() is called once with another stroke in the
                            //     same group.
                            continue;
                        }
                        if (HandleIntersectionWithBatchedStroke(subset))
                        {
                            hitCount++;
                        }
                    }

                    // Always process at least 1 hit. This number can be tuned to taste, but in initial
                    // tests, it kept the deletion time under the frame budget while still feeling responsive.
                    if (hitCount > 0)
                    {
                        m_TimesUp = m_DetectionStopwatch.ElapsedTicks > m_TimeSliceInTicks;
                    }
                }
                m_GpuConsumedResults += hitCount;
                if (hitCount > 0)
                {
                    return(true);
                }
            }

            return(false);
        }
        // TODO: We're disabling "duplicate on hover" until we've had a chance to UER test
        // the basic functionality. Once that's been tested, we can experiment with what we do
        // when the selection tool hovers over an existing selection.
        //override public bool HasHoverInteractions() { return true; }
        //
        //override public void AssignHoverControllerMaterials(InputManager.ControllerName controller) {
        //  // If we're intersecting with the brush hand, allow additional actions.
        //  if (controller == InputManager.ControllerName.Brush) {
        //    InputManager.GetControllerGeometry(controller).ShowSelectionOptions();
        //  }
        //}

        override public float GetActivationScore(
            Vector3 vControllerPos_GS, InputManager.ControllerName name)
        {
            if (!PointInCollider(vControllerPos_GS))
            {
                return(-1);
            }

            // If the data we've got is old, delete it all.
            if ((Time.frameCount - m_IntersectionFrame) > 3)
            {
                m_CurrentIntersectionController = null;
                m_NextIntersectionController    = null;
                m_IntersectionFuture            = null;
            }

            // If we have an intersection in the pipe, set up the next one if it is of a different type.
            // This is so that if we're looking for both Wand and Brush, it will toggle between them.
            // If the results are ready, then store them off and clear the current intersection.
            if (m_CurrentIntersectionController.HasValue)
            {
                if (m_CurrentIntersectionController.Value != name)
                {
                    m_NextIntersectionController = name;
                }
                if (m_IntersectionFuture.IsReady)
                {
                    m_LastIntersectionResult[m_CurrentIntersectionController.Value] =
                        m_IntersectionFuture.HasAnyIntersections() ? 1 : -1;
                    m_CurrentIntersectionController = null;
                    m_IntersectionFuture            = null;
                }
            }

            // If we don't have a current intersection in the pipe, grab the next one if there is one,
            // or just start off the intersection we have been asked for.
            if (!m_CurrentIntersectionController.HasValue)
            {
                if (!m_NextIntersectionController.HasValue)
                {
                    m_NextIntersectionController = name;
                }
                m_CurrentIntersectionController = m_NextIntersectionController.Value;
                m_NextIntersectionController    = null;
                Debug.Assert(m_CurrentIntersectionController.Value == InputManager.ControllerName.Wand ||
                             m_CurrentIntersectionController.Value == InputManager.ControllerName.Brush);
                // Because we may be requesting an intersection on another controller's behalf, don't use
                // the passed position, but instead the position respective of the enum.
                Vector3 pos = (m_CurrentIntersectionController.Value == InputManager.ControllerName.Brush) ?
                              InputManager.Brush.Geometry.ToolAttachPoint.position :
                              InputManager.Wand.Geometry.ToolAttachPoint.position;
                m_IntersectionFuture = App.Instance.GpuIntersector.RequestBatchIntersection(
                    pos, m_CollisionRadius, (1 << m_SelectionCanvas.gameObject.layer));
                m_IntersectionFrame = Time.frameCount;
            }

            float result = -1;

            m_LastIntersectionResult.TryGetValue(name, out result);
            return(result);
        }
Exemple #3
0
 protected void ClearGpuFutureLists()
 {
     m_GpuFutureResultList.Clear();
     m_GpuOldResultList.Clear();
     m_GpuFutureResult = null;
 }