Exemplo n.º 1
0
        /// Detection Center should be in Global Space.
        protected void UpdateSolitaryBrushDetection(Vector3 vDetectionCenter_GS)
        {
            if (m_CurrentCanvas == null)
            {
                m_CurrentCanvas = App.ActiveCanvas;
            }
            TrTransform canvasPose          = m_CurrentCanvas.Pose;
            Vector3     vDetectionCenter_CS = canvasPose.inverse * vDetectionCenter_GS;
            Transform   rCanvas             = m_CurrentCanvas.transform;
            int         iNumCanvasChildren  = rCanvas.childCount;

            m_TimesUp = false;

            //reset detection if we've moved or adjusted our size
            float fDetectionRadius   = GetSize();
            float fDetectionRadiusSq = fDetectionRadius * fDetectionRadius;

            m_DetectionStopwatch.Reset();
            m_DetectionStopwatch.Start();

            //early out if there's nothing to look at
            if (iNumCanvasChildren > 0 && m_DetectionObjectIndex < iNumCanvasChildren)
            {
                Plane rTestPlane = new Plane();
                m_ResetDetection = false;

                //spin until we've taken up too much time
                while (!m_TimesUp)
                {
                    //check child bounds
                    Transform rChild = rCanvas.GetChild(m_DetectionObjectIndex);
                    if (rChild.gameObject.activeSelf)
                    {
                        MeshFilter rMeshFilter = rChild.GetComponent <MeshFilter>();
                        if (rMeshFilter)
                        {
                            Bounds rMeshBounds = rMeshFilter.mesh.bounds;
                            rMeshBounds.Expand(fDetectionRadius);
                            Vector3 vTransformedCenter = rChild.InverseTransformPoint(vDetectionCenter_CS);

                            if (rMeshBounds.Contains(vTransformedCenter))
                            {
                                //bounds valid, check triangle intersections with sphere
                                int       iMeshVertCount = rMeshFilter.mesh.vertexCount;
                                Vector3[] aVerts         = rMeshFilter.mesh.vertices;
                                Vector3[] aNorms         = rMeshFilter.mesh.normals;
                                while (m_DetectionVertIndex < iMeshVertCount - 2)
                                {
                                    //check to see if we're within the sphere radius to the plane of this triangle
                                    Vector3 vVert = aVerts[m_DetectionVertIndex];
                                    Vector3 vNorm = aNorms[m_DetectionVertIndex];
                                    rTestPlane.SetNormalAndPosition(vNorm, vVert);
                                    float fDistToPlane = rTestPlane.GetDistanceToPoint(vTransformedCenter);
                                    if (Mathf.Abs(fDistToPlane) < fDetectionRadius)
                                    {
                                        //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 = vTransformedCenter - vPlaneOffsetVector;

                                        Vector3 vVert2 = aVerts[m_DetectionVertIndex + 1];
                                        Vector3 vVert3 = aVerts[m_DetectionVertIndex + 2];

                                        //walk the projected point toward the triangle center to find the triangle test position
                                        Vector3 vTriCenter = (vVert + vVert2 + vVert3) * 0.33333f;

                                        bool    bIntersecting     = false;
                                        Vector3 vPointToTriCenter = vTriCenter - vTransformedCenter;
                                        if (vPointToTriCenter.sqrMagnitude < fDetectionRadiusSq)
                                        {
                                            //if the triangle center is within the detection distance, we're definitely intersecting
                                            bIntersecting = true;
                                        }
                                        else
                                        {
                                            //figure out how far we have left to move toward the tri-center
                                            float fNormAngle = Mathf.Acos(Mathf.Abs(fDistToPlane) / fDetectionRadius);
                                            float fDistLeft  = Mathf.Sin(fNormAngle) * fDetectionRadius;

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

                                            //see if this projected point is in the triangle
                                            if (PointInTriangle(ref vPlaneIntersection, ref vVert, ref vVert2, ref vVert3))
                                            {
                                                bIntersecting = true;
                                            }
                                        }

                                        if (bIntersecting)
                                        {
                                            if (HandleIntersectionWithSolitaryObject(rChild.gameObject))
                                            {
                                                DoIntersectionResets();
                                                break;
                                            }
                                        }
                                    }

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

                    //if we're not flagged as done, we just finished this object, so move on to the next
                    if (!m_TimesUp)
                    {
                        //move to the next object
                        ++m_DetectionObjectIndex;

                        m_DetectionVertIndex = 0;
                        if (m_DetectionObjectIndex >= iNumCanvasChildren)
                        {
                            //if we reached the end of the line, we're done
                            break;
                        }

                        //might as well check our clock per object
                        m_TimesUp = m_DetectionStopwatch.ElapsedTicks > m_TimeSliceInTicks;
                    }
                }
            }
            m_DetectionStopwatch.Stop();
        }
Exemplo n.º 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();
        }