Exemplo n.º 1
0
        public void Execute(int index)
        {
            if (!m_recompute)
            {
                return;
            }

            //Compute whether a vertex is convex or concave
            //as well as its direction
            ObstacleVertexData v       = m_inputObstacles[index];
            float2             pos     = v.pos,
                               nextPos = m_inputObstacles[v.next].pos,
                               prevPos = m_inputObstacles[v.prev].pos;

            ObstacleInfos infos = m_inputObstacleInfos[v.infos];

            if (infos.length == 2)//infos.edge ||
            {
                v.convex = true;
            }
            else
            {
                v.convex = LeftOf(prevPos, pos, nextPos) >= 0.0f;
            }

            v.dir = normalize(nextPos - pos);
            m_referenceObstacles[index] = v;
        }
Exemplo n.º 2
0
        protected override void Prepare(ref Unemployed job, float delta)
        {
            int obsCount = m_obstacles == null ? 0 : m_obstacles.Count,
                refCount = m_referenceObstacles.Length, vCount = 0;

            if (m_outputObstacleInfos.Length != obsCount)
            {
                m_outputObstacleInfos.Dispose();
                m_outputObstacleInfos = new NativeArray <ObstacleInfos>(obsCount, Allocator.Persistent);

                m_recompute = true;
            }

            Obstacle      o;
            ObstacleInfos infos;

            for (int i = 0; i < obsCount; i++)
            {
                o = m_obstacles[i];
                //Keep collision infos & ORCALayer up-to-date
                //there is no need to recompute anything else.
                infos       = o.infos;
                infos.index = i;
                infos.start = vCount;
                m_outputObstacleInfos[i] = infos;

                vCount += infos.length;
            }

            if (!m_recompute)
            {
                if (refCount != vCount)
                {
                    m_recompute = true;
                }
                else
                {
                    return;
                }
            }

            if (refCount != vCount)
            {
                m_referenceObstacles.Dispose();
                m_referenceObstacles = new NativeArray <ObstacleVertexData>(vCount, Allocator.Persistent);

                m_outputObstacles.Dispose();
                m_outputObstacles = new NativeArray <ObstacleVertexData>(vCount, Allocator.Persistent);
            }

            ObstacleVertexData oData;
            int gIndex = 0, index = 0, vCountMinusOne, firstIndex, lastIndex;

            if (plane == AxisPair.XY)
            {
                for (int i = 0; i < obsCount; i++)
                {
                    o = m_obstacles[i];

                    vCount         = o.Count;
                    vCountMinusOne = vCount - 1;
                    firstIndex     = gIndex;
                    lastIndex      = gIndex + vCountMinusOne;

                    if (!o.edge)
                    {
                        //Obstacle is a closed polygon
                        for (int v = 0; v < vCount; v++)
                        {
                            oData = new ObstacleVertexData()
                            {
                                infos = i,
                                index = index,
                                pos   = o[v].XY,
                                prev  = v == 0 ? lastIndex : index - 1,
                                next  = v == vCountMinusOne ? firstIndex : index + 1
                            };
                            m_referenceObstacles[index++] = oData;
                        }
                    }
                    else
                    {
                        //Obstacle is an open path
                        for (int v = 0; v < vCount; v++)
                        {
                            oData = new ObstacleVertexData()
                            {
                                infos = i,
                                index = index,
                                pos   = o[v].XY,
                                prev  = v == 0 ? index : index - 1,
                                next  = v == vCountMinusOne ? index : index + 1
                            };
                            m_referenceObstacles[index++] = oData;
                        }
                    }

                    gIndex += vCount;
                }
            }
            else
            {
                for (int i = 0; i < obsCount; i++)
                {
                    o              = m_obstacles[i];
                    vCount         = o.Count;
                    vCountMinusOne = vCount - 1;
                    firstIndex     = gIndex;
                    lastIndex      = gIndex + vCountMinusOne;

                    if (!o.edge)
                    {
                        //Obstacle is a closed polygon
                        for (int v = 0; v < vCount; v++)
                        {
                            oData = new ObstacleVertexData()
                            {
                                infos = i,
                                index = index,
                                pos   = o[v].XZ,
                                prev  = v == 0 ? lastIndex : index - 1,
                                next  = v == vCountMinusOne ? firstIndex : index + 1
                            };
                            m_referenceObstacles[index++] = oData;
                        }
                    }
                    else
                    {
                        //Obstacle is an open path
                        for (int v = 0; v < vCount; v++)
                        {
                            oData = new ObstacleVertexData()
                            {
                                infos = i,
                                index = index,
                                pos   = o[v].XZ,
                                prev  = v == 0 ? index : index - 1,
                                next  = v == vCountMinusOne ? index : index + 1
                            };
                            m_referenceObstacles[index++] = oData;
                        }
                    }

                    gIndex += vCount;
                }
            }

            m_referenceObstacles.CopyTo(m_outputObstacles);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Recursive method for building an agent k-D tree.
        /// </summary>
        /// <param name="begin">The beginning agent k-D tree node node index.</param>
        /// <param name="end">The ending agent k-D tree node index.</param>
        /// <param name="node">The current agent k-D tree node index.</param>
        private void BuildAgentTreeRecursive(int begin, int end, int node)
        {
            ObstacleTreeNode   treeNode = m_outputTree[node];
            ObstacleVertexData obstacle = m_inputObstacles[begin];
            float2             pos;
            float minX, minY, maxX, maxY;

            treeNode.begin = begin;
            treeNode.end   = end;
            minX           = maxX = obstacle.pos.x;
            minY           = maxY = obstacle.pos.y;

            for (int i = begin + 1; i < end; ++i)
            {
                pos  = m_inputObstacles[i].pos;
                maxX = max(maxX, pos.x);
                minX = min(minX, pos.x);
                maxY = max(maxY, pos.y);
                minY = min(minY, pos.y);
            }

            treeNode.minX = minX;
            treeNode.maxX = maxX;
            treeNode.minY = minY;
            treeNode.maxY = maxY;

            m_outputTree[node] = treeNode;

            if (end - begin > ObstacleTreeNode.MAX_LEAF_SIZE)
            {
                // No leaf node.
                bool  isVertical = treeNode.maxX - treeNode.minX > treeNode.maxY - treeNode.minY;
                float splitValue = 0.5f * (isVertical ? treeNode.maxX + treeNode.minX : treeNode.maxY + treeNode.minY);

                int left  = begin;
                int right = end;

                while (left < right)
                {
                    while (left < right && (isVertical ? m_inputObstacles[left].pos.x : m_inputObstacles[left].pos.y) < splitValue)
                    {
                        ++left;
                    }

                    while (right > left && (isVertical ? m_inputObstacles[right - 1].pos.x : m_inputObstacles[right - 1].pos.y) >= splitValue)
                    {
                        --right;
                    }

                    if (left < right)
                    {
                        ObstacleVertexData tempAgent = m_inputObstacles[left];
                        m_inputObstacles[left]      = m_inputObstacles[right - 1];
                        m_inputObstacles[right - 1] = tempAgent;
                        ++left;
                        --right;
                    }
                }

                int leftSize = left - begin;

                if (leftSize == 0)
                {
                    ++leftSize;
                    ++left;
                    ++right;
                }

                treeNode.left      = node + 1;
                treeNode.right     = node + 2 * leftSize;
                m_outputTree[node] = treeNode;

                BuildAgentTreeRecursive(begin, left, treeNode.left);
                BuildAgentTreeRecursive(left, end, treeNode.right);
            }
        }
Exemplo n.º 4
0
        public void Execute(int index)
        {
            RaycastData   raycast = m_inputRaycasts[index];
            RaycastResult result  = new RaycastResult()
            {
                hitAgent        = -1,
                hitObstacle     = -1,
                dynamicObstacle = false
            };

            RaycastFilter filter = raycast.filter;

            if (filter == 0)
            {
                m_results[index] = result;
                return;
            }

            float2
                r_position = raycast.position,
                r_dir      = raycast.direction,
                hitLocation;

            float
                a_bottom  = raycast.baseline,
                a_top     = a_bottom,
                a_sqRange = lengthsq(raycast.distance);

            Segment2D raySegment = new Segment2D(raycast.position, raycast.position + raycast.direction * raycast.distance),
                      segment;

            UIntPair           pair = new UIntPair(0, 0);
            ObstacleVertexData otherVertex;
            bool
                twoSidedCast   = raycast.twoSided,
                alreadyCovered = false,
                hit;

            #region static obstacles

            if ((filter & RaycastFilter.OBSTACLE_STATIC) != 0)
            {
                NativeList <int> staticObstacleNeighbors = new NativeList <int>(10, Allocator.Temp);

                if (m_staticObstacleTree.Length > 0)
                {
                    QueryObstacleTreeRecursive(ref raycast, ref a_sqRange, 0, ref staticObstacleNeighbors,
                                               ref m_staticObstacles, ref m_staticRefObstacles, ref m_staticObstacleInfos, ref m_staticObstacleTree);
                }

                NativeHashMap <UIntPair, bool> coveredStaticEdges = new NativeHashMap <UIntPair, bool>(m_staticObstacleTree.Length * 2, Allocator.Temp);

                for (int i = 0; i < staticObstacleNeighbors.Length; ++i)
                {
                    ObstacleVertexData vertex = m_staticObstacles[staticObstacleNeighbors[i]];
                    ObstacleInfos      infos  = m_staticObstacleInfos[vertex.infos];

                    pair           = new UIntPair(vertex.index, vertex.next);
                    alreadyCovered = coveredStaticEdges.TryGetValue(pair, out hit);

                    if (!alreadyCovered)
                    {
                        otherVertex    = m_staticRefObstacles[vertex.next];
                        segment        = new Segment2D(vertex.pos, otherVertex.pos);
                        alreadyCovered = (!twoSidedCast && dot(r_dir, segment.normal) < 0f);

                        if (!alreadyCovered)
                        {
                            if (raySegment.IsIntersecting(segment, out hitLocation))
                            {
                                //Rays intersecting !
                                if (result.hitObstacle == -1 ||
                                    distancesq(r_position, hitLocation) < distancesq(r_position, result.hitObstacleLocation2D))
                                {
                                    result.hitObstacleLocation2D = hitLocation;
                                    result.hitObstacle           = infos.index;
                                }
                            }
                        }

                        coveredStaticEdges.TryAdd(pair, true);
                    }

                    pair           = new UIntPair(vertex.index, vertex.prev);
                    alreadyCovered = coveredStaticEdges.ContainsKey(pair);

                    if (!alreadyCovered)
                    {
                        otherVertex    = m_staticRefObstacles[vertex.prev];
                        segment        = new Segment2D(vertex.pos, otherVertex.pos);
                        alreadyCovered = (!twoSidedCast && dot(r_dir, segment.normal) < 0f);

                        if (!alreadyCovered)
                        {
                            if (raySegment.IsIntersecting(segment, out hitLocation))
                            {
                                //Rays intersecting !
                                if (result.hitObstacle == -1 ||
                                    distancesq(r_position, hitLocation) < distancesq(r_position, result.hitObstacleLocation2D))
                                {
                                    result.hitObstacleLocation2D = hitLocation;
                                    result.hitObstacle           = infos.index;
                                }
                            }
                        }

                        coveredStaticEdges.TryAdd(pair, true);
                    }
                }

                staticObstacleNeighbors.Dispose();
                coveredStaticEdges.Dispose();
            }

            #endregion

            #region dynamic obstacles

            if ((filter & RaycastFilter.OBSTACLE_DYNAMIC) != 0)
            {
                NativeList <int> dynObstacleNeighbors = new NativeList <int>(10, Allocator.Temp);

                if (m_dynObstacleTree.Length > 0)
                {
                    QueryObstacleTreeRecursive(ref raycast, ref a_sqRange, 0, ref dynObstacleNeighbors,
                                               ref m_dynObstacles, ref m_dynRefObstacles, ref m_dynObstacleInfos, ref m_dynObstacleTree);
                }

                NativeHashMap <UIntPair, bool> coveredDynEdges = new NativeHashMap <UIntPair, bool>(m_dynObstacleTree.Length * 2, Allocator.Temp);

                for (int i = 0; i < dynObstacleNeighbors.Length; ++i)
                {
                    ObstacleVertexData vertex = m_dynObstacles[dynObstacleNeighbors[i]];
                    ObstacleInfos      infos  = m_dynObstacleInfos[vertex.infos];

                    pair           = new UIntPair(vertex.index, vertex.next);
                    alreadyCovered = coveredDynEdges.TryGetValue(pair, out hit);

                    if (!alreadyCovered)
                    {
                        otherVertex    = m_dynRefObstacles[vertex.next];
                        segment        = new Segment2D(vertex.pos, otherVertex.pos);
                        alreadyCovered = (!twoSidedCast && dot(r_dir, segment.normal) < 0f);

                        if (!alreadyCovered)
                        {
                            if (raySegment.IsIntersecting(segment, out hitLocation))
                            {
                                //Rays intersecting !
                                if (result.hitObstacle == -1 ||
                                    distancesq(r_position, hitLocation) < distancesq(r_position, result.hitObstacleLocation2D))
                                {
                                    result.hitObstacleLocation2D = hitLocation;
                                    result.hitObstacle           = infos.index;
                                    result.dynamicObstacle       = true;
                                }
                            }
                        }

                        coveredDynEdges.TryAdd(pair, true);
                    }

                    pair           = new UIntPair(vertex.index, vertex.prev);
                    alreadyCovered = coveredDynEdges.ContainsKey(pair);

                    if (!alreadyCovered)
                    {
                        otherVertex    = m_dynRefObstacles[vertex.prev];
                        segment        = new Segment2D(vertex.pos, otherVertex.pos);
                        alreadyCovered = (!twoSidedCast && dot(r_dir, segment.normal) < 0f);

                        if (!alreadyCovered)
                        {
                            if (raySegment.IsIntersecting(segment, out hitLocation))
                            {
                                //Rays intersecting !
                                if (result.hitObstacle == -1 ||
                                    distancesq(r_position, hitLocation) < distancesq(r_position, result.hitObstacleLocation2D))
                                {
                                    result.hitObstacleLocation2D = hitLocation;
                                    result.hitObstacle           = infos.index;
                                    result.dynamicObstacle       = true;
                                }
                            }
                        }

                        coveredDynEdges.TryAdd(pair, true);
                    }
                }

                dynObstacleNeighbors.Dispose();
                coveredDynEdges.Dispose();
            }

            #endregion

            #region Agents

            if ((filter & RaycastFilter.AGENTS) != 0)
            {
                NativeList <int> agentNeighbors = new NativeList <int>(10, Allocator.Temp);

                float radSq = a_sqRange + lengthsq(m_maxAgentRadius);

                if (m_inputAgents.Length > 0)
                {
                    QueryAgentTreeRecursive(ref raycast, ref radSq, 0, ref agentNeighbors);
                }

                AgentData agent;
                int       iResult, agentIndex;
                float2    center, i1, i2, rayEnd = r_position + normalize(r_dir) * raycast.distance;
                float
                    a_radius, a_sqRadius, cx, cy,
                    Ax   = r_position.x,
                    Ay   = r_position.y,
                    Bx   = rayEnd.x,
                    By   = rayEnd.y,
                    dx   = Bx - Ax,
                    dy   = By - Ay,
                    magA = dx * dx + dy * dy,
                    distSq;

                int TryGetIntersection(out float2 intersection1, out float2 intersection2)
                {
                    float
                        magB = 2f * (dx * (Ax - cx) + dy * (Ay - cy)),
                        magC = (Ax - cx) * (Ax - cx) + (Ay - cy) * (Ay - cy) - a_sqRadius,
                        det = magB * magB - 4f * magA * magC,
                        sqDet, t;

                    if ((magA <= float.Epsilon) || (det < 0f))
                    {
                        // No real solutions.
                        intersection1 = float2(float.NaN, float.NaN);
                        intersection2 = float2(float.NaN, float.NaN);

                        return(0);
                    }

                    if (det == 0)
                    {
                        // One solution.
                        t = -magB / (2f * magA);

                        intersection1 = float2(Ax + t * dx, Ay + t * dy);
                        intersection2 = float2(float.NaN, float.NaN);

                        return(1);
                    }
                    else
                    {
                        // Two solutions.
                        sqDet = sqrt(det);

                        t             = ((-magB + sqDet) / (2f * magA));
                        intersection1 = float2(Ax + t * dx, Ay + t * dy);

                        t             = ((-magB - sqDet) / (2f * magA));
                        intersection2 = float2(Ax + t * dx, Ay + t * dy);

                        return(2);
                    }
                }

                for (int i = 0; i < agentNeighbors.Length; ++i)
                {
                    agentIndex = agentNeighbors[i];
                    agent      = m_inputAgents[agentIndex];

                    center = agent.position;
                    cx     = center.x;
                    cy     = center.y;

                    a_radius   = agent.radius;
                    a_sqRadius = a_radius * a_radius;

                    if (dot(center - r_position, r_dir) < 0f)
                    {
                        continue;
                    }

                    iResult = TryGetIntersection(out i1, out i2);

                    if (iResult == 0)
                    {
                        continue;
                    }

                    distSq = distancesq(r_position, i1);

                    if (distSq < a_sqRange &&
                        (result.hitAgent == -1 || distSq < distancesq(r_position, result.hitAgentLocation2D)) &&
                        IsBetween(r_position, center, i1))
                    {
                        result.hitAgentLocation2D = i1;
                        result.hitAgent           = agentIndex;
                    }

                    if (iResult == 2)
                    {
                        distSq = distancesq(r_position, i2);

                        if (distSq < a_sqRange &&
                            (result.hitAgent == -1 || distSq < distancesq(r_position, result.hitAgentLocation2D)) &&
                            IsBetween(r_position, center, i2))
                        {
                            result.hitAgentLocation2D = i2;
                            result.hitAgent           = agentIndex;
                        }
                    }
                }

                agentNeighbors.Dispose();
            }

            #endregion

            if (m_plane == AxisPair.XY)
            {
                float baseline = raycast.worldPosition.z;

                if (result.hitAgent != -1)
                {
                    result.hitAgentLocation = float3(result.hitAgentLocation2D, baseline);
                }

                if (result.hitObstacle != -1)
                {
                    result.hitObstacleLocation = float3(result.hitObstacleLocation2D, baseline);
                }
            }
            else
            {
                float baseline = raycast.worldPosition.y;

                if (result.hitAgent != -1)
                {
                    result.hitAgentLocation = float3(result.hitAgentLocation2D.x, baseline, result.hitAgentLocation2D.y);
                }

                if (result.hitObstacle != -1)
                {
                    result.hitObstacleLocation = float3(result.hitObstacleLocation2D.x, baseline, result.hitObstacleLocation2D.y);
                }
            }

            m_results[index] = result;
        }