예제 #1
0
            // ------------------------------------------------------------------------------------------ //
            // Private Internals
            // ------------------------------------------------------------------------------------------ //

            override protected void OnReadResults()
            {
                // Mark results as ready.
                m_ResultCount = 0;
                if (m_ResultList != null)
                {
                    m_ResultList.Clear();
                }

                uint[] resultColors = GetTextureColors();

                //
                // Process the color buffer into result objects, if requested.
                //
                UnityEngine.Profiling.Profiler.BeginSample("Intersection: Process Results");
                HashSet <object> seen = AllocateHashSet();

                uint c;

                for (int i = 0; i < resultColors.Length; i++)
                {
                    if (m_ResultCount == m_MaxResults)
                    {
                        break;
                    }

                    c = resultColors[i];

                    if (c > 0)
                    {
                        // Don't bother looking up the batch if the exact result set wasn't requested.
                        if (m_ResultList == null)
                        {
                            m_ResultCount++;
                            continue;
                        }

                        // TODO: the Color32 -> object lookup is deterministic and O(n), so 'seen'
                        // should store the Color32, not the object.

                        int         triIndex = (int)(c & 0xffff) * 3;
                        ushort      batchId  = (ushort)((c & 0xffff0000) >> 16);
                        GrabWidget  widget   = null;
                        Batch       batch    = null;
                        BatchSubset subset   = null;

                        // See if this batch refers to a brush stroke.
                        batch = App.ActiveCanvas.BatchManager.GetBatch(batchId);
                        if (batch != null)
                        {
                            // TODO: move this into Batch, so can do binary search if necessary
                            for (int j = 0; j < batch.m_Groups.Count; j++)
                            {
                                BatchSubset bs = batch.m_Groups[j];
                                if (triIndex >= bs.m_iTriIndex && triIndex < bs.m_iTriIndex + bs.m_nTriIndex)
                                {
                                    subset = bs;
                                    break;
                                }
                            }

                            // A stroke may be deleted by the time this executes. This is due to the delay between
                            // sending an intersection request and processing the results.
                            if (subset == null)
                            {
                                // This actually happens in practice!
                                // TODO: investigate if it's okay
                                // Debug.LogWarningFormat(
                                //     "Unexpected: Nonexistent subset for c = {0:x} {1:x}",
                                //     (ushort)(c >> 16),
                                //     (ushort)(c & 0xffff));
                                continue;
                            }

                            if (!seen.Add(subset))
                            {
                                continue;
                            }
                        }
                        else
                        {
                            // Not a brush stroke?  See if this is a widget.
                            widget = WidgetManager.m_Instance.GetBatch(batchId);

                            // A widget may be deleted by the time this executes. This is due to the delay between
                            // sending an intersection request and processing the results.
                            if (widget == null)
                            {
                                continue;
                            }

                            if (!seen.Add(widget))
                            {
                                continue;
                            }
                        }

                        // A batch should never be null, but in the future that may change. This is possible due
                        // to the delay between sending an intersection request and processing the results.
                        if (batch == null && widget == null)
                        {
                            Debug.LogWarningFormat(
                                "Unexpected: Null batch {0} and widget {1}",
                                ReferenceEquals(batch, null), ReferenceEquals(widget, null));
                            continue;
                        }

                        // These cannot both be valid.
                        Debug.Assert(subset == null || widget == null);
                        m_ResultList.Add(
                            new BatchResult {
                            widget = widget, subset = subset
                        });
                        m_ResultCount++;
                    }
                }

                DeallocateHashSet(seen);
                UnityEngine.Profiling.Profiler.EndSample();
            }
예제 #2
0
        /// Detection Center should be in Global Space.
        protected void UpdateBatchedBrushDetection(Vector3 vDetectionCenter_GS)
        {
            // The CPU intersection code still needs to be updated to iterate over multiple canvases.
            //
            // TODO: Update CPU intersection checking to work on multiple canvases,
            //       then get rid of automatic defaulting to ActiveCanvas.
            //       Possibly let m_CurrentCanvas be null to represent a desire to intersect
            //       with all canvases.
            if (m_CurrentCanvas == null)
            {
                m_CurrentCanvas = App.ActiveCanvas;
            }

            // If we changed canvases, abandon any progress we made on checking for
            // intersections in the previous canvas.
            if (m_CurrentCanvas != m_PreviousCanvas)
            {
                ResetDetection();
                m_PreviousCanvas = m_CurrentCanvas;
            }

            TrTransform canvasPose          = m_CurrentCanvas.Pose;
            Vector3     vDetectionCenter_CS = canvasPose.inverse * vDetectionCenter_GS;

            m_TimesUp = false;

            // Reset detection if we've moved or adjusted our size
            float fDetectionRadius_CS   = GetSize() / canvasPose.scale;
            float fDetectionRadiusSq_CS = fDetectionRadius_CS * fDetectionRadius_CS;

            // Start the timer!
            m_DetectionStopwatch.Reset();
            m_DetectionStopwatch.Start();

            int  iSanityCheck    = 10000;
            bool bNothingChecked = true;

            if (App.Config.m_GpuIntersectionEnabled)
            {
                // Run GPU intersection if enabled; will update m_TimesUp.
                if (UpdateGpuIntersection(vDetectionCenter_GS, GetSize()))
                {
                    IntersectionHappenedThisFrame();
                    m_DetectionStopwatch.Stop();
                    DoIntersectionResets();
                    return;
                }
            }

            m_TimesUp = m_DetectionStopwatch.ElapsedTicks > m_TimeSliceInTicks;

            //check batch pools first
            int iNumBatchPools = m_CurrentCanvas.BatchManager.GetNumBatchPools();

            if (!App.Config.m_GpuIntersectionEnabled &&
                iNumBatchPools > 0 &&
                m_BatchPoolIndex < iNumBatchPools)
            {
                bNothingChecked  = false;
                m_ResetDetection = false;
                Plane     rTestPlane = new Plane();
                BatchPool rPool      = m_CurrentCanvas.BatchManager.GetBatchPool(m_BatchPoolIndex);

                //spin until we've taken up too much time
                while (!m_TimesUp)
                {
                    --iSanityCheck;
                    if (iSanityCheck == 0)
                    {
                        Batch tmpBatch = rPool.m_Batches[m_BatchObjectIndex];
                        Debug.LogErrorFormat("Stroke while loop error.  NumPools({0}) BatchPoolIndex({1}) NumBatchStrokes({2}) BatchStrokeIndex({3}) NumStrokeGroups({4})",
                                             iNumBatchPools, m_BatchPoolIndex, rPool.m_Batches.Count, m_BatchObjectIndex, tmpBatch.m_Groups.Count);
                    }

                    Batch batch = rPool.m_Batches[m_BatchObjectIndex];
                    if (m_BatchVertGroupIndex < batch.m_Groups.Count)
                    {
                        var    subset      = batch.m_Groups[m_BatchVertGroupIndex];
                        Bounds rMeshBounds = subset.m_Bounds;
                        rMeshBounds.Expand(2.0f * fDetectionRadius_CS);

                        if (subset.m_Active && rMeshBounds.Contains(vDetectionCenter_CS))
                        {
                            //bounds valid, check triangle intersections with sphere
                            int       nTriIndices = subset.m_nTriIndex;
                            Vector3[] aVerts;
                            int       nVerts;
                            int[]     aTris;
                            int       nTris;
                            batch.GetTriangles(out aVerts, out nVerts, out aTris, out nTris);
                            while (m_BatchTriIndexIndex < nTriIndices - 2)
                            {
                                //check to see if we're within the brush size (plus some) radius to this triangle
                                int     iTriIndex            = subset.m_iTriIndex + m_BatchTriIndexIndex;
                                Vector3 v0                   = aVerts[aTris[iTriIndex]];
                                Vector3 v1                   = aVerts[aTris[iTriIndex + 1]];
                                Vector3 v2                   = aVerts[aTris[iTriIndex + 2]];
                                Vector3 vTriCenter           = (v0 + v1 + v2) * 0.33333f;
                                Vector3 vToTestCenter        = vDetectionCenter_CS - vTriCenter;
                                float   fTestSphereRadius_CS = Vector3.Distance(v1, v2) + fDetectionRadius_CS;
                                if (vToTestCenter.sqrMagnitude < fTestSphereRadius_CS * fTestSphereRadius_CS)
                                {
                                    //check to see if we're within the sphere radius to the plane of this triangle
                                    Vector3 vNorm = Vector3.Cross(v1 - v0, v2 - v0).normalized;
                                    rTestPlane.SetNormalAndPosition(vNorm, v0);
                                    float fDistToPlane = rTestPlane.GetDistanceToPoint(vDetectionCenter_CS);
                                    if (Mathf.Abs(fDistToPlane) < fDetectionRadius_CS)
                                    {
                                        //we're within the radius to this triangle's plane, find the point projected on to the plane
                                        fDistToPlane *= -1.0f;
                                        Vector3 vPlaneOffsetVector = vNorm * fDistToPlane;
                                        Vector3 vPlaneIntersection = vDetectionCenter_CS - vPlaneOffsetVector;

                                        //walk the projected point toward the triangle center to find the triangle test position
                                        bool    bIntersecting     = false;
                                        Vector3 vPointToTriCenter = vTriCenter - vDetectionCenter_CS;
                                        if (vPointToTriCenter.sqrMagnitude < fDetectionRadiusSq_CS)
                                        {
                                            //if the triangle center is within the detection distance, we're definitely intersecting
                                            bIntersecting = true;
                                        } //check against triangle segments
                                        else if (SegmentSphereIntersection(v0, v1, vDetectionCenter_CS, fDetectionRadiusSq_CS))
                                        {
                                            bIntersecting = true;
                                        }
                                        else if (SegmentSphereIntersection(v1, v2, vDetectionCenter_CS, fDetectionRadiusSq_CS))
                                        {
                                            bIntersecting = true;
                                        }
                                        else if (SegmentSphereIntersection(v2, v0, vDetectionCenter_CS, fDetectionRadiusSq_CS))
                                        {
                                            bIntersecting = true;
                                        }
                                        else
                                        {
                                            //figure out how far we have left to move toward the tri-center
                                            float fNormAngle = Mathf.Acos(Mathf.Abs(fDistToPlane) / fDetectionRadius_CS);
                                            float fDistLeft  = Mathf.Sin(fNormAngle) * fDetectionRadius_CS;

                                            Vector3 vToTriCenter = vTriCenter - vPlaneIntersection;
                                            vToTriCenter.Normalize();
                                            vToTriCenter       *= fDistLeft;
                                            vPlaneIntersection += vToTriCenter;

                                            //see if this projected point is in the triangle
                                            if (PointInTriangle(ref vPlaneIntersection, ref v0, ref v1, ref v2))
                                            {
                                                bIntersecting = true;
                                            }
                                        }

                                        if (bIntersecting)
                                        {
                                            if (HandleIntersectionWithBatchedStroke(subset))
                                            {
                                                DoIntersectionResets();
                                                break;
                                            }
                                        }
                                    }
                                }

                                //after each triangle, check our time
                                m_BatchTriIndexIndex += 3;
                                m_TimesUp             = m_DetectionStopwatch.ElapsedTicks > m_TimeSliceInTicks;
                                if (m_TimesUp)
                                {
                                    break;
                                }
                            }
                        }
                    }

                    //if we're not flagged as done, we just finished this group, so move on to the next group
                    if (!m_TimesUp)
                    {
                        m_BatchTriIndexIndex = 0;
                        ++m_BatchVertGroupIndex;

                        //if we're done with groups, go to the next object
                        if (m_BatchVertGroupIndex >= batch.m_Groups.Count)
                        {
                            m_BatchVertGroupIndex = 0;
                            ++m_BatchObjectIndex;

                            //aaaand if we're done with objects, go on to the next pool
                            if (m_BatchObjectIndex >= rPool.m_Batches.Count)
                            {
                                m_BatchObjectIndex = 0;
                                ++m_BatchPoolIndex;
                                if (m_BatchPoolIndex >= iNumBatchPools)
                                {
                                    //get out if we've traversed the last pool
                                    break;
                                }
                                rPool = m_CurrentCanvas.BatchManager.GetBatchPool(m_BatchPoolIndex);
                            }
                        }

                        //we check again here in case the early checks fail
                        m_TimesUp = m_DetectionStopwatch.ElapsedTicks > m_TimeSliceInTicks;
                    }
                }
            }

            if (App.Config.m_GpuIntersectionEnabled && m_GpuFutureResult != null)
            {
                // We have an intersection test in flight, make sure we don't reset detection.
                // This ensures consistency between collision tests and avoids strobing of the result (e.g.
                // without this, one test will return "no result" and the next may return some result and this
                // oscillation will continue).
                bNothingChecked  = false;
                m_ResetDetection = false;
                return;
            }

            // If our scene doesn't have anything in it, reset our detection.
            if (bNothingChecked)
            {
                m_ResetDetection = true;
            }

            m_DetectionStopwatch.Stop();
        }