상속: Pathfinding.MeshNode
예제 #1
0
		public override void CreateNodes (int number) {
			TriangleMeshNode[] tmp = new TriangleMeshNode[number];
			for (int i=0;i<number;i++) {
				tmp[i] = new TriangleMeshNode (active);
				tmp[i].Penalty = initialPenalty;
			}
		}
예제 #2
0
        public override IEnumerable <Progress> ScanInternal()
        {
            TriangleMeshNode.SetNavmeshHolder(AstarPath.active.data.GetGraphIndex(this), this);
            if (!Application.isPlaying)
            {
                RelevantGraphSurface.FindAllGraphSurfaces();
            }
            RelevantGraphSurface.UpdateAllPositions();
            foreach (Progress progress in this.ScanAllTiles())
            {
                yield return(progress);
            }
            IEnumerator <Progress> enumerator = null;

            yield break;
            yield break;
            yield break;
        }
예제 #3
0
        public override void ScanInternal(OnScanStatus statusCallback)
        {
            if (sourceMesh == null)
            {
                return;
            }

            GenerateMatrix();

            //float startTime = 0;//Time.realtimeSinceStartup;

            Vector3[] vectorVertices = sourceMesh.vertices;

            triangles = sourceMesh.triangles;

            TriangleMeshNode.SetNavmeshHolder(active.astarData.GetGraphIndex(this), this);
            GenerateNodes(vectorVertices, triangles, out originalVertices, out _vertices);
        }
예제 #4
0
        public bool IsVertex(Int3 p, out int index)
        {
            INavmeshHolder navmeshHolder = TriangleMeshNode.GetNavmeshHolder(base.GraphIndex);

            index = -1;
            if (navmeshHolder.GetVertex(this.v0).IsEqualXZ(ref p))
            {
                index = 0;
            }
            else if (navmeshHolder.GetVertex(this.v1).IsEqualXZ(ref p))
            {
                index = 1;
            }
            else if (navmeshHolder.GetVertex(this.v2).IsEqualXZ(ref p))
            {
                index = 2;
            }
            return(index != -1);
        }
예제 #5
0
 // Token: 0x060025F4 RID: 9716 RVA: 0x001A3488 File Offset: 0x001A1688
 private void SearchBoxClosestXZ(int boxi, Vector3 p, ref float closestSqrDist, NNConstraint constraint, ref NNInfoInternal nnInfo)
 {
     BBTree.BBTreeBox bbtreeBox = this.tree[boxi];
     if (bbtreeBox.IsLeaf)
     {
         TriangleMeshNode[] array = this.nodeLookup;
         for (int i = 0; i < 4; i++)
         {
             if (array[bbtreeBox.nodeOffset + i] == null)
             {
                 return;
             }
             TriangleMeshNode triangleMeshNode = array[bbtreeBox.nodeOffset + i];
             if (constraint == null || constraint.Suitable(triangleMeshNode))
             {
                 Vector3 vector = triangleMeshNode.ClosestPointOnNodeXZ(p);
                 float   num    = (vector.x - p.x) * (vector.x - p.x) + (vector.z - p.z) * (vector.z - p.z);
                 if (nnInfo.constrainedNode == null || num < closestSqrDist - 1E-06f || (num <= closestSqrDist + 1E-06f && Mathf.Abs(vector.y - p.y) < Mathf.Abs(nnInfo.constClampedPosition.y - p.y)))
                 {
                     nnInfo.constrainedNode      = triangleMeshNode;
                     nnInfo.constClampedPosition = vector;
                     closestSqrDist = num;
                 }
             }
         }
     }
     else
     {
         int   left  = bbtreeBox.left;
         int   right = bbtreeBox.right;
         float num2;
         float num3;
         this.GetOrderedChildren(ref left, ref right, out num2, out num3, p);
         if (num2 <= closestSqrDist)
         {
             this.SearchBoxClosestXZ(left, p, ref closestSqrDist, constraint, ref nnInfo);
         }
         if (num3 <= closestSqrDist)
         {
             this.SearchBoxClosestXZ(right, p, ref closestSqrDist, constraint, ref nnInfo);
         }
     }
 }
예제 #6
0
        private TriangleMeshNode checkObjIntersects(ref int edge, Int3 start, Int3 end, int gridX, int gridY)
        {
            List <object> objs = this.rasterizer.GetObjs(gridX, gridY);

            if (objs == null || objs.Count == 0)
            {
                return(null);
            }
            Int3[]           array            = new Int3[3];
            TriangleMeshNode triangleMeshNode = null;
            int  num  = -1;
            long num2 = 9223372036854775807L;

            for (int i = 0; i < objs.Count; i++)
            {
                TriangleMeshNode triangleMeshNode2 = objs[i] as TriangleMeshNode;
                triangleMeshNode2.GetPoints(out array[0], out array[1], out array[2]);
                for (int j = 0; j < 3; j++)
                {
                    int num3 = j;
                    int num4 = (j + 1) % 3;
                    if (Polygon.Intersects(array[num3], array[num4], start, end))
                    {
                        bool flag;
                        Int3 vInt = Polygon.IntersectionPoint(ref array[num3], ref array[num4], ref start, ref end, out flag);

                        long num5 = start.XZSqrMagnitude(ref vInt);
                        if (num5 < num2)
                        {
                            num2             = num5;
                            triangleMeshNode = triangleMeshNode2;
                            num = j;
                        }
                    }
                }
            }
            if (num != -1 && triangleMeshNode != null)
            {
                edge = num;
                return(triangleMeshNode);
            }
            return(null);
        }
예제 #7
0
 public static void BuildFunnelCorridor(INavmesh graph, List <GraphNode> path, int startIndex, int endIndex, List <Vector3> left, List <Vector3> right)
 {
     if (graph == null)
     {
         Debug.LogError("Couldn't cast graph to the appropriate type (graph isn't a Navmesh type graph, it doesn't implement the INavmesh interface)");
         return;
     }
     for (int i = startIndex; i < endIndex; i++)
     {
         TriangleMeshNode triangleMeshNode  = path[i] as TriangleMeshNode;
         TriangleMeshNode triangleMeshNode2 = path[i + 1] as TriangleMeshNode;
         bool             flag = true;
         int j;
         for (j = 0; j < 3; j++)
         {
             for (int k = 0; k < 3; k++)
             {
                 if (triangleMeshNode.GetVertexIndex(j) == triangleMeshNode2.GetVertexIndex((k + 1) % 3) && triangleMeshNode.GetVertexIndex((j + 1) % 3) == triangleMeshNode2.GetVertexIndex(k))
                 {
                     flag = false;
                     break;
                 }
             }
             if (!flag)
             {
                 break;
             }
         }
         if (j == 3)
         {
             left.Add((Vector3)triangleMeshNode.position);
             right.Add((Vector3)triangleMeshNode.position);
             left.Add((Vector3)triangleMeshNode2.position);
             right.Add((Vector3)triangleMeshNode2.position);
         }
         else
         {
             left.Add((Vector3)triangleMeshNode.GetVertex(j));
             right.Add((Vector3)triangleMeshNode.GetVertex((j + 1) % 3));
         }
     }
 }
예제 #8
0
 private TriangleMeshNode SearchBoxInside(int boxi, Vector3 p, NNConstraint constraint)
 {
     BBTree.BBTreeBox bbtreeBox = this.tree[boxi];
     if (bbtreeBox.IsLeaf)
     {
         TriangleMeshNode[] array = this.nodeLookup;
         int num = 0;
         while (num < 4 && array[bbtreeBox.nodeOffset + num] != null)
         {
             TriangleMeshNode triangleMeshNode = array[bbtreeBox.nodeOffset + num];
             if (triangleMeshNode.ContainsPoint((Int3)p))
             {
                 if (constraint == null || constraint.Suitable(triangleMeshNode))
                 {
                     return(triangleMeshNode);
                 }
             }
             num++;
         }
     }
     else
     {
         if (this.tree[bbtreeBox.left].Contains(p))
         {
             TriangleMeshNode triangleMeshNode2 = this.SearchBoxInside(bbtreeBox.left, p, constraint);
             if (triangleMeshNode2 != null)
             {
                 return(triangleMeshNode2);
             }
         }
         if (this.tree[bbtreeBox.right].Contains(p))
         {
             TriangleMeshNode triangleMeshNode3 = this.SearchBoxInside(bbtreeBox.right, p, constraint);
             if (triangleMeshNode3 != null)
             {
                 return(triangleMeshNode3);
             }
         }
     }
     return(null);
 }
예제 #9
0
 private void SearchBoxClosest(int boxi, Vector3 p, ref float closestSqrDist, NNConstraint constraint, ref NNInfoInternal nnInfo)
 {
     BBTree.BBTreeBox bbtreeBox = this.tree[boxi];
     if (bbtreeBox.IsLeaf)
     {
         TriangleMeshNode[] array = this.nodeLookup;
         int num = 0;
         while (num < 4 && array[bbtreeBox.nodeOffset + num] != null)
         {
             TriangleMeshNode triangleMeshNode = array[bbtreeBox.nodeOffset + num];
             Vector3          vector           = triangleMeshNode.ClosestPointOnNode(p);
             float            sqrMagnitude     = (vector - p).sqrMagnitude;
             if (sqrMagnitude < closestSqrDist)
             {
                 if (constraint == null || constraint.Suitable(triangleMeshNode))
                 {
                     nnInfo.constrainedNode      = triangleMeshNode;
                     nnInfo.constClampedPosition = vector;
                     closestSqrDist = sqrMagnitude;
                 }
             }
             num++;
         }
     }
     else
     {
         int   left  = bbtreeBox.left;
         int   right = bbtreeBox.right;
         float num2;
         float num3;
         this.GetOrderedChildren(ref left, ref right, out num2, out num3, p);
         if (num2 < closestSqrDist)
         {
             this.SearchBoxClosest(left, p, ref closestSqrDist, constraint, ref nnInfo);
         }
         if (num3 < closestSqrDist)
         {
             this.SearchBoxClosest(right, p, ref closestSqrDist, constraint, ref nnInfo);
         }
     }
 }
예제 #10
0
 private void SearchBoxClosestXZ(int boxi, Vector3 p, ref float closestSqrDist, NNConstraint constraint, ref NNInfoInternal nnInfo)
 {
     BBTree.BBTreeBox bbtreeBox = this.tree[boxi];
     if (bbtreeBox.IsLeaf)
     {
         TriangleMeshNode[] array = this.nodeLookup;
         int num = 0;
         while (num < 4 && array[bbtreeBox.nodeOffset + num] != null)
         {
             TriangleMeshNode triangleMeshNode = array[bbtreeBox.nodeOffset + num];
             if (constraint == null || constraint.Suitable(triangleMeshNode))
             {
                 Vector3 constClampedPosition = triangleMeshNode.ClosestPointOnNodeXZ(p);
                 float   num2 = (constClampedPosition.x - p.x) * (constClampedPosition.x - p.x) + (constClampedPosition.z - p.z) * (constClampedPosition.z - p.z);
                 if (nnInfo.constrainedNode == null || num2 < closestSqrDist - 1E-06f || (num2 <= closestSqrDist + 1E-06f && Mathf.Abs(constClampedPosition.y - p.y) < Mathf.Abs(nnInfo.constClampedPosition.y - p.y)))
                 {
                     nnInfo.constrainedNode      = triangleMeshNode;
                     nnInfo.constClampedPosition = constClampedPosition;
                     closestSqrDist = num2;
                 }
             }
             num++;
         }
     }
     else
     {
         int   left  = bbtreeBox.left;
         int   right = bbtreeBox.right;
         float num3;
         float num4;
         this.GetOrderedChildren(ref left, ref right, out num3, out num4, p);
         if (num3 <= closestSqrDist)
         {
             this.SearchBoxClosestXZ(left, p, ref closestSqrDist, constraint, ref nnInfo);
         }
         if (num4 <= closestSqrDist)
         {
             this.SearchBoxClosestXZ(right, p, ref closestSqrDist, constraint, ref nnInfo);
         }
     }
 }
예제 #11
0
        private TriangleMeshNode checkObjIntersects(ref int edge, VInt3 start, VInt3 end, int gridX, int gridY)
        {
            List <object> objs = this.rasterizer.GetObjs(gridX, gridY);

            if ((objs != null) && (objs.Count != 0))
            {
                VInt3[]          numArray = new VInt3[3];
                TriangleMeshNode node     = null;
                int  num  = -1;
                long num2 = 0x7fffffffffffffffL;
                for (int i = 0; i < objs.Count; i++)
                {
                    TriangleMeshNode node2 = objs[i] as TriangleMeshNode;
                    node2.GetPoints(out numArray[0], out numArray[1], out numArray[2]);
                    for (int j = 0; j < 3; j++)
                    {
                        int index = j;
                        int num6  = (j + 1) % 3;
                        if (Polygon.Intersects(numArray[index], numArray[num6], start, end))
                        {
                            bool  flag;
                            VInt3 rhs = Polygon.IntersectionPoint(ref numArray[index], ref numArray[num6], ref start, ref end, out flag);
                            DebugHelper.Assert(flag);
                            long num8 = start.XZSqrMagnitude(ref rhs);
                            if (num8 < num2)
                            {
                                num2 = num8;
                                node = node2;
                                num  = j;
                            }
                        }
                    }
                }
                if ((num != -1) && (node != null))
                {
                    edge = num;
                    return(node);
                }
            }
            return(null);
        }
예제 #12
0
        public override IEnumerable <Progress> ScanInternal()
        {
            this.transform  = this.CalculateTransform();
            this.tileZCount = (this.tileXCount = 1);
            this.tiles      = new NavmeshTile[this.tileZCount * this.tileXCount];
            TriangleMeshNode.SetNavmeshHolder(AstarPath.active.data.GetGraphIndex(this), this);
            if (this.sourceMesh == null)
            {
                base.FillWithEmptyTiles();
                yield break;
            }
            yield return(new Progress(0f, "Transforming Vertices"));

            this.forcedBoundsSize = this.sourceMesh.bounds.size * this.scale;
            Vector3[]   vertices    = this.sourceMesh.vertices;
            List <Int3> intVertices = ListPool <Int3> .Claim(vertices.Length);

            Matrix4x4 matrix4x = Matrix4x4.TRS(-this.sourceMesh.bounds.min * this.scale, Quaternion.identity, Vector3.one * this.scale);

            for (int i = 0; i < vertices.Length; i++)
            {
                intVertices.Add((Int3)matrix4x.MultiplyPoint3x4(vertices[i]));
            }
            yield return(new Progress(0.1f, "Compressing Vertices"));

            Int3[] compressedVertices  = null;
            int[]  compressedTriangles = null;
            Polygon.CompressMesh(intVertices, new List <int>(this.sourceMesh.triangles), out compressedVertices, out compressedTriangles);
            ListPool <Int3> .Release(intVertices);

            yield return(new Progress(0.2f, "Building Nodes"));

            base.ReplaceTile(0, 0, compressedVertices, compressedTriangles);
            if (this.OnRecalculatedTiles != null)
            {
                this.OnRecalculatedTiles(this.tiles.Clone() as NavmeshTile[]);
            }
            yield break;
            yield break;
        }
예제 #13
0
 // Token: 0x060025F9 RID: 9721 RVA: 0x001A379C File Offset: 0x001A199C
 private TriangleMeshNode SearchBoxInside(int boxi, Vector3 p, NNConstraint constraint)
 {
     BBTree.BBTreeBox bbtreeBox = this.tree[boxi];
     if (bbtreeBox.IsLeaf)
     {
         TriangleMeshNode[] array = this.nodeLookup;
         for (int i = 0; i < 4; i++)
         {
             if (array[bbtreeBox.nodeOffset + i] == null)
             {
                 break;
             }
             TriangleMeshNode triangleMeshNode = array[bbtreeBox.nodeOffset + i];
             if (triangleMeshNode.ContainsPoint((Int3)p) && (constraint == null || constraint.Suitable(triangleMeshNode)))
             {
                 return(triangleMeshNode);
             }
         }
     }
     else
     {
         if (this.tree[bbtreeBox.left].Contains(p))
         {
             TriangleMeshNode triangleMeshNode2 = this.SearchBoxInside(bbtreeBox.left, p, constraint);
             if (triangleMeshNode2 != null)
             {
                 return(triangleMeshNode2);
             }
         }
         if (this.tree[bbtreeBox.right].Contains(p))
         {
             TriangleMeshNode triangleMeshNode3 = this.SearchBoxInside(bbtreeBox.right, p, constraint);
             if (triangleMeshNode3 != null)
             {
                 return(triangleMeshNode3);
             }
         }
     }
     return(null);
 }
예제 #14
0
        public bool CheckSegmentIntersects(Int3 start, Int3 end, int gridX, int gridY, out Int3 outPoint, out TriangleMeshNode nearestNode)
        {
            List <object> objs = this.rasterizer.GetObjs(gridX, gridY);

            outPoint    = end;
            nearestNode = null;
            if (objs == null || objs.Count == 0)
            {
                return(false);
            }
            Int3[] array  = new Int3[3];
            bool   result = false;
            long   num    = 9223372036854775807L;

            for (int i = 0; i < objs.Count; i++)
            {
                TriangleMeshNode triangleMeshNode = objs[i] as TriangleMeshNode;
                triangleMeshNode.GetPoints(out array[0], out array[1], out array[2]);
                for (int j = 0; j < 3; j++)
                {
                    int  num2 = j;
                    int  num3 = (j + 1) % 3;
                    bool flag = false;
                    Int3 vInt = Polygon.SegmentIntersectionPoint(array[num2], array[num3], start, end, out flag);
                    if (flag)
                    {
                        long num4 = start.XZSqrMagnitude(ref vInt);
                        if (num4 < num)
                        {
                            nearestNode = triangleMeshNode;
                            num         = num4;
                            outPoint    = vInt;
                            result      = true;
                        }
                    }
                }
            }
            return(result);
        }
예제 #15
0
        protected override IEnumerable <Progress> ScanInternal()
        {
            TriangleMeshNode.SetNavmeshHolder(AstarPath.active.data.GetGraphIndex(this), this);

            if (!Application.isPlaying)
            {
                RelevantGraphSurface.FindAllGraphSurfaces();
            }

            RelevantGraphSurface.UpdateAllPositions();


            foreach (var progress in ScanAllTiles())
            {
                yield return(progress);
            }


#if DEBUG_REPLAY
            DebugReplay.WriteToFile();
#endif
        }
예제 #16
0
        public TriangleMeshNode GetNearestByRasterizer(Int3 position, out Int3 clampedPosition)
        {
            clampedPosition = Int3.zero;
            if (this.rasterizer == null)
            {
                return(null);
            }
            TriangleMeshNode triangleMeshNode = this.GetLocatedByRasterizer(position);

            if (triangleMeshNode != null)
            {
                clampedPosition = position;
                return(triangleMeshNode);
            }
            triangleMeshNode = this.FindNearestByRasterizer(position, -1);
            if (triangleMeshNode == null)
            {
                return(null);
            }
            clampedPosition = triangleMeshNode.ClosestPointOnNodeXZ(position);
            return(triangleMeshNode);
        }
예제 #17
0
        public override void DeserializeExtraInfo(GraphSerializationContext ctx)
        {
            uint graphIndex = ctx.graphIndex;

            TriangleMeshNode.SetNavmeshHolder((int)graphIndex, this);

            int nodeCount   = ctx.reader.ReadInt32();
            int vertexCount = ctx.reader.ReadInt32();

            if (nodeCount == -1)
            {
                nodes            = new TriangleMeshNode[0];
                _vertices        = new Int3[0];
                originalVertices = new Vector3[0];
                return;
            }

            nodes            = new TriangleMeshNode[nodeCount];
            _vertices        = new Int3[vertexCount];
            originalVertices = new Vector3[vertexCount];

            for (int i = 0; i < vertexCount; i++)
            {
                _vertices[i]        = ctx.DeserializeInt3();
                originalVertices[i] = ctx.DeserializeVector3();
            }

            bbTree = new BBTree();

            for (int i = 0; i < nodeCount; i++)
            {
                nodes[i] = new TriangleMeshNode(active);
                TriangleMeshNode node = nodes[i];
                node.DeserializeNode(ctx);
                node.UpdatePositionFromVertices();
            }

            bbTree.RebuildFrom(nodes);
        }
        //These functions are for serialization, the static ones are there so other graphs using mesh nodes can serialize them more easily
        public static byte[] SerializeMeshNodes(NavMeshGraph graph, GraphNode[] nodes)
        {
            System.IO.MemoryStream mem    = new System.IO.MemoryStream();
            System.IO.BinaryWriter stream = new System.IO.BinaryWriter(mem);

            for (int i = 0; i < nodes.Length; i++)
            {
                TriangleMeshNode node = nodes[i] as TriangleMeshNode;

                if (node == null)
                {
                    Debug.LogError("Serialization Error : Couldn't cast the node to the appropriate type - NavMeshGenerator. Omitting node data.");
                    return(null);
                }

                stream.Write(node.v0);
                stream.Write(node.v1);
                stream.Write(node.v2);
            }

            Int3[] vertices = graph.vertices;

            if (vertices == null)
            {
                vertices = new Int3[0];
            }

            stream.Write(vertices.Length);

            for (int i = 0; i < vertices.Length; i++)
            {
                stream.Write(vertices[i].x);
                stream.Write(vertices[i].y);
                stream.Write(vertices[i].z);
            }

            stream.Close();
            return(mem.ToArray());
        }
예제 #19
0
 private void UpdateFunnelCorridor(int splitIndex, TriangleMeshNode prefix)
 {
     if (splitIndex > 0)
     {
         this.nodes.RemoveRange(0, splitIndex - 1);
         this.nodes[0] = prefix;
     }
     else
     {
         this.nodes.Insert(0, prefix);
     }
     this.left.Clear();
     this.right.Clear();
     this.left.Add(this.exactStart);
     this.right.Add(this.exactStart);
     for (int i = 0; i < this.nodes.Count - 1; i++)
     {
         this.nodes[i].GetPortal(this.nodes[i + 1], this.left, this.right, false);
     }
     this.left.Add(this.exactEnd);
     this.right.Add(this.exactEnd);
 }
예제 #20
0
        public TriangleMeshNode GetNeighborByEdge(int edge, out int otherEdge)
        {
            otherEdge = -1;
            if (edge < 0 || edge > 2 || this.connections == null)
            {
                return(null);
            }
            int vertexIndex         = this.GetVertexIndex(edge % 3);
            int vertexIndex2        = this.GetVertexIndex((edge + 1) % 3);
            TriangleMeshNode result = null;

            for (int i = 0; i < this.connections.Length; i++)
            {
                TriangleMeshNode triangleMeshNode = this.connections[i] as TriangleMeshNode;
                if (triangleMeshNode != null && triangleMeshNode.GraphIndex == base.GraphIndex)
                {
                    if (triangleMeshNode.v1 == vertexIndex && triangleMeshNode.v0 == vertexIndex2)
                    {
                        otherEdge = 0;
                    }
                    else if (triangleMeshNode.v2 == vertexIndex && triangleMeshNode.v1 == vertexIndex2)
                    {
                        otherEdge = 1;
                    }
                    else if (triangleMeshNode.v0 == vertexIndex && triangleMeshNode.v2 == vertexIndex2)
                    {
                        otherEdge = 2;
                    }
                    if (otherEdge != -1)
                    {
                        result = triangleMeshNode;
                        break;
                    }
                }
            }
            return(result);
        }
예제 #21
0
        public override void DeserializeExtraInfo(GraphSerializationContext ctx)
        {
            uint graphIndex = (uint)ctx.graphIndex;

            TriangleMeshNode.SetNavmeshHolder((int)graphIndex, this);

            int c1 = ctx.reader.ReadInt32();
            int c2 = ctx.reader.ReadInt32();

            if (c1 == -1)
            {
                nodes            = new TriangleMeshNode[0];
                _vertices        = new Int3[0];
                originalVertices = new Vector3[0];
            }

            nodes            = new TriangleMeshNode[c1];
            _vertices        = new Int3[c2];
            originalVertices = new Vector3[c2];

            for (int i = 0; i < c2; i++)
            {
                _vertices[i]        = new Int3(ctx.reader.ReadInt32(), ctx.reader.ReadInt32(), ctx.reader.ReadInt32());
                originalVertices[i] = new Vector3(ctx.reader.ReadSingle(), ctx.reader.ReadSingle(), ctx.reader.ReadSingle());
            }

            bbTree = new BBTree(this);

            for (int i = 0; i < c1; i++)
            {
                nodes[i] = new TriangleMeshNode(active);
                TriangleMeshNode node = nodes[i];
                node.DeserializeNode(ctx);
                node.UpdatePositionFromVertices();
                bbTree.Insert(node);
            }
        }
예제 #22
0
        public override void DeserializeExtraInfo(GraphSerializationContext ctx)
        {
            var graphIndex = (uint)active.astarData.GetGraphIndex(this);

            TriangleMeshNode.SetNavmeshHolder((int)graphIndex, this);

            var c1 = ctx.reader.ReadInt32();
            var c2 = ctx.reader.ReadInt32();

            if (c1 == -1)
            {
                nodes            = new TriangleMeshNode[0];
                _vertices        = new Int3[0];
                originalVertices = new Vector3[0];
            }

            nodes            = new TriangleMeshNode[c1];
            _vertices        = new Int3[c2];
            originalVertices = new Vector3[c2];

            for (var i = 0; i < c2; i++)
            {
                _vertices[i]        = new Int3(ctx.reader.ReadInt32(), ctx.reader.ReadInt32(), ctx.reader.ReadInt32());
                originalVertices[i] = new Vector3(ctx.reader.ReadSingle(), ctx.reader.ReadSingle(), ctx.reader.ReadSingle());
            }


            for (var i = 0; i < c1; i++)
            {
                nodes[i] = new TriangleMeshNode(active);
                var node = nodes[i];
                node.DeserializeNode(ctx);
                node.GraphIndex = graphIndex;
                node.UpdatePositionFromVertices();
            }
        }
예제 #23
0
		/** Generates a navmesh. Based on the supplied vertices and triangles */
		void GenerateNodes (Vector3[] vectorVertices, int[] triangles, out Vector3[] originalVertices, out Int3[] vertices) {

			Profiler.BeginSample ("Init");

			if (vectorVertices.Length == 0 || triangles.Length == 0) {
				originalVertices = vectorVertices;
				vertices = new Int3[0];
				nodes = new TriangleMeshNode[0];
				return;
			}

			vertices = new Int3[vectorVertices.Length];

			int c = 0;

			for (int i=0;i<vertices.Length;i++) {
				vertices[i] = (Int3)matrix.MultiplyPoint3x4 (vectorVertices[i]);
			}

			var hashedVerts = new Dictionary<Int3,int> ();

			var newVertices = new int[vertices.Length];

			Profiler.EndSample ();
			Profiler.BeginSample ("Hashing");

			for (int i=0;i<vertices.Length;i++) {
				if (!hashedVerts.ContainsKey (vertices[i])) {
					newVertices[c] = i;
					hashedVerts.Add (vertices[i], c);
					c++;
				}
			}

			for (int x=0;x<triangles.Length;x++) {
				Int3 vertex = vertices[triangles[x]];

				triangles[x] = hashedVerts[vertex];
			}

			Int3[] totalIntVertices = vertices;
			vertices = new Int3[c];
			originalVertices = new Vector3[c];
			for (int i=0;i<c;i++) {

				vertices[i] = totalIntVertices[newVertices[i]];
				originalVertices[i] = vectorVertices[newVertices[i]];
			}

			Profiler.EndSample ();
			Profiler.BeginSample ("Constructing Nodes");

			nodes = new TriangleMeshNode[triangles.Length/3];

			int graphIndex = active.astarData.GetGraphIndex(this);

			// Does not have to set this, it is set in ScanInternal
			//TriangleMeshNode.SetNavmeshHolder ((int)graphIndex,this);

			for (int i=0;i<nodes.Length;i++) {

				nodes[i] = new TriangleMeshNode(active);
				TriangleMeshNode node = nodes[i];//new MeshNode ();

				node.GraphIndex = (uint)graphIndex;
				node.Penalty = initialPenalty;
				node.Walkable = true;


				node.v0 = triangles[i*3];
				node.v1 = triangles[i*3+1];
				node.v2 = triangles[i*3+2];

				if (!Polygon.IsClockwise (vertices[node.v0],vertices[node.v1],vertices[node.v2])) {
					//Debug.DrawLine (vertices[node.v0],vertices[node.v1],Color.red);
					//Debug.DrawLine (vertices[node.v1],vertices[node.v2],Color.red);
					//Debug.DrawLine (vertices[node.v2],vertices[node.v0],Color.red);

					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}

				if (Polygon.IsColinear (vertices[node.v0],vertices[node.v1],vertices[node.v2])) {
					Debug.DrawLine ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v1],(Vector3)vertices[node.v2],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v2],(Vector3)vertices[node.v0],Color.red);
				}

				// Make sure position is correctly set
				node.UpdatePositionFromVertices();
			}

			Profiler.EndSample ();

			var sides = new Dictionary<Int2, TriangleMeshNode>();

			for (int i=0, j=0;i<triangles.Length; j+=1, i+=3) {
				sides[new Int2(triangles[i+0],triangles[i+1])] = nodes[j];
				sides[new Int2(triangles[i+1],triangles[i+2])] = nodes[j];
				sides[new Int2(triangles[i+2],triangles[i+0])] = nodes[j];
			}

			Profiler.BeginSample ("Connecting Nodes");

			var connections = new List<MeshNode> ();
			var connectionCosts = new List<uint> ();

			for (int i=0, j = 0; i < triangles.Length; j+=1, i+=3) {
				connections.Clear ();
				connectionCosts.Clear ();

				TriangleMeshNode node = nodes[j];

				for ( int q = 0; q < 3; q++ ) {
					TriangleMeshNode other;
					if (sides.TryGetValue ( new Int2 (triangles[i+((q+1)%3)], triangles[i+q]), out other ) ) {
						connections.Add (other);
						connectionCosts.Add ((uint)(node.position-other.position).costMagnitude);
					}
				}

				node.connections = connections.ToArray ();
				node.connectionCosts = connectionCosts.ToArray ();
			}

			Profiler.EndSample ();
			Profiler.BeginSample ("Rebuilding BBTree");

			RebuildBBTree (this);

			Profiler.EndSample ();

#if ASTARDEBUG
			for (int i=0;i<nodes.Length;i++) {
				TriangleMeshNode node = nodes[i] as TriangleMeshNode;

				float a1 = Polygon.TriangleArea2 ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],(Vector3)vertices[node.v2]);

				long a2 = Polygon.TriangleArea2 (vertices[node.v0],vertices[node.v1],vertices[node.v2]);
				if (a1 * a2 < 0) Debug.LogError (a1+ " " + a2);


				if (Polygon.IsClockwise (vertices[node.v0],vertices[node.v1],vertices[node.v2])) {
					Debug.DrawLine ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],Color.green);
					Debug.DrawLine ((Vector3)vertices[node.v1],(Vector3)vertices[node.v2],Color.green);
					Debug.DrawLine ((Vector3)vertices[node.v2],(Vector3)vertices[node.v0],Color.green);
				} else {
					Debug.DrawLine ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v1],(Vector3)vertices[node.v2],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v2],(Vector3)vertices[node.v0],Color.red);
				}
			}
#endif
		}
예제 #24
0
		/** Returns if the point is inside the node in XZ space */
		public static bool ContainsPoint (TriangleMeshNode node, Vector3 pos, Int3[] vertices) {
			if (!Polygon.IsClockwiseMargin ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1], (Vector3)vertices[node.v2])) {
				Debug.LogError ("Noes!");
			}
			
			if ( 	Polygon.IsClockwiseMargin ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1], pos)
			    && 	Polygon.IsClockwiseMargin ((Vector3)vertices[node.v1],(Vector3)vertices[node.v2], pos)
			    && 	Polygon.IsClockwiseMargin ((Vector3)vertices[node.v2],(Vector3)vertices[node.v0], pos)) {
				return true;
			}
			return false;
		}
예제 #25
0
		/** Generates a navmesh. Based on the supplied vertices and triangles. Memory usage is about O(n) */
		public void GenerateNodes (Vector3[] vectorVertices, int[] triangles, out Vector3[] originalVertices, out Int3[] vertices) {
			
			
			if (vectorVertices.Length == 0 || triangles.Length == 0) {
				originalVertices = vectorVertices;
				vertices = new Int3[0];
				//graph.CreateNodes (0);
				nodes = new TriangleMeshNode[0];
				return;
			}
			
			vertices = new Int3[vectorVertices.Length];
			
			//Backup the original vertices
			//for (int i=0;i<vectorVertices.Length;i++) {
			//	vectorVertices[i] = graph.matrix.MultiplyPoint (vectorVertices[i]);
			//}
			
			int c = 0;
			/*int maxX = 0;
			int maxZ = 0;
			
			//Almost infinity
			int minX = 0xFFFFFFF;
			int minZ = 0xFFFFFFF;*/
			
			for (int i=0;i<vertices.Length;i++) {
				vertices[i] = (Int3)matrix.MultiplyPoint3x4 (vectorVertices[i]);
				/*maxX = Mathfx.Max (vertices[i].x, maxX);
				maxZ = Mathfx.Max (vertices[i].z, maxZ);
				minX = Mathfx.Min (vertices[i].x, minX);
				minZ = Mathfx.Min (vertices[i].z, minZ);*/
			}
			
			//maxX = maxX-minX;
			//maxZ = maxZ-minZ;
			
			Dictionary<Int3,int> hashedVerts = new Dictionary<Int3,int> ();
			
			int[] newVertices = new int[vertices.Length];
				
			for (int i=0;i<vertices.Length-1;i++) {
				
				//int hash = Mathfx.ComputeVertexHash (vertices[i].x,vertices[i].y,vertices[i].z);
				
				//(vertices[i].x-minX)+(vertices[i].z-minX)*maxX+vertices[i].y*maxX*maxZ;
				//if (sortedVertices[i] != sortedVertices[i+1]) {
				if (!hashedVerts.ContainsKey (vertices[i])) {
					newVertices[c] = i;
					hashedVerts.Add (vertices[i], c);
					c++;
				}// else {
					//Debug.Log ("Hash Duplicate "+hash+" "+vertices[i].ToString ());
				//}
			}
			
			newVertices[c] = vertices.Length-1;
			
			//int hash2 = (newVertices[c].x-minX)+(newVertices[c].z-minX)*maxX+newVertices[c].y*maxX*maxZ;
			//int hash2 = Mathfx.ComputeVertexHash (newVertices[c].x,newVertices[c].y,newVertices[c].z);
			if (!hashedVerts.ContainsKey (vertices[newVertices[c]])) {
				
				hashedVerts.Add (vertices[newVertices[c]], c);
				c++;
			}
			
			for (int x=0;x<triangles.Length;x++) {
				Int3 vertex = vertices[triangles[x]];
				
				//int hash3 = (vertex.x-minX)+(vertex.z-minX)*maxX+vertex.y*maxX*maxZ;
				//int hash3 = Mathfx.ComputeVertexHash (vertex.x,vertex.y,vertex.z);
				//for (int y=0;y<newVertices.Length;y++) {
				triangles[x] = hashedVerts[vertex];
			}
			
			/*for (int i=0;i<triangles.Length;i += 3) {
				
				Vector3 offset = Vector3.forward*i*0.01F;
				Debug.DrawLine (newVertices[triangles[i]]+offset,newVertices[triangles[i+1]]+offset,Color.blue);
				Debug.DrawLine (newVertices[triangles[i+1]]+offset,newVertices[triangles[i+2]]+offset,Color.blue);
				Debug.DrawLine (newVertices[triangles[i+2]]+offset,newVertices[triangles[i]]+offset,Color.blue);
			}*/
			
			//Debug.Log ("NavMesh - Old vertice count "+vertices.Length+", new vertice count "+c+" "+maxX+" "+maxZ+" "+maxX*maxZ);
			
			Int3[] totalIntVertices = vertices;
			vertices = new Int3[c];
			originalVertices = new Vector3[c];
			for (int i=0;i<c;i++) {
				
				vertices[i] = totalIntVertices[newVertices[i]];//(Int3)graph.matrix.MultiplyPoint (vectorVertices[i]);
				originalVertices[i] = (Vector3)vectorVertices[newVertices[i]];//vectorVertices[newVertices[i]];
			}
			
			//graph.CreateNodes (triangles.Length/3);//new Node[triangles.Length/3];
			nodes = new TriangleMeshNode[triangles.Length/3];
			
			for (int i=0;i<nodes.Length;i++) {
				
				nodes[i] = new TriangleMeshNode(active);
				TriangleMeshNode node = nodes[i];//new MeshNode ();
				
				node.Penalty = initialPenalty;
				node.Walkable = true;
				
				
				node.v0 = triangles[i*3];
				node.v1 = triangles[i*3+1];
				node.v2 = triangles[i*3+2];
				
				if (!Polygon.IsClockwise (vertices[node.v0],vertices[node.v1],vertices[node.v2])) {
					//Debug.DrawLine (vertices[node.v0],vertices[node.v1],Color.red);
					//Debug.DrawLine (vertices[node.v1],vertices[node.v2],Color.red);
					//Debug.DrawLine (vertices[node.v2],vertices[node.v0],Color.red);
					
					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}
				
				if (Polygon.IsColinear (vertices[node.v0],vertices[node.v1],vertices[node.v2])) {
					Debug.DrawLine ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v1],(Vector3)vertices[node.v2],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v2],(Vector3)vertices[node.v0],Color.red);
				}
				
				// Make sure position is correctly set
				node.UpdatePositionFromVertices();
			}
			
			List<MeshNode> connections = new List<MeshNode> ();
			List<uint> connectionCosts = new List<uint> ();
			
			int identicalError = 0;
			
			for (int i=0;i<triangles.Length;i+=3) {
				
				connections.Clear ();
				connectionCosts.Clear ();
				
				//Int3 indices = new Int3(triangles[i],triangles[i+1],triangles[i+2]);
				
				TriangleMeshNode node = nodes[i/3];
				
				for (int x=0;x<triangles.Length;x+=3) {
					
					if (x == i) {
						continue;
					}
					
					int count = 0;
					if (triangles[x] 	== 	triangles[i]) { count++; }
					if (triangles[x+1]	== 	triangles[i]) { count++; }
					if (triangles[x+2] 	== 	triangles[i]) { count++; }
					if (triangles[x] 	== 	triangles[i+1]) { count++; }
					if (triangles[x+1] 	== 	triangles[i+1]) { count++; }
					if (triangles[x+2] 	== 	triangles[i+1]) { count++; }
					if (triangles[x] 	== 	triangles[i+2]) { count++; }
					if (triangles[x+1] 	== 	triangles[i+2]) { count++; }
					if (triangles[x+2] 	== 	triangles[i+2]) { count++; }
					
					if (count >= 3) {
						identicalError++;
						Debug.DrawLine ((Vector3)vertices[triangles[x]],(Vector3)vertices[triangles[x+1]],Color.red);
						Debug.DrawLine ((Vector3)vertices[triangles[x]],(Vector3)vertices[triangles[x+2]],Color.red);
						Debug.DrawLine ((Vector3)vertices[triangles[x+2]],(Vector3)vertices[triangles[x+1]],Color.red);
					}
					
					if (count == 2) {
						GraphNode other = nodes[x/3];
						connections.Add (other as MeshNode);
						connectionCosts.Add ((uint)(node.position-other.position).costMagnitude);
					}
				}
				
				node.connections = connections.ToArray ();
				node.connectionCosts = connectionCosts.ToArray ();
			}
			
			if (identicalError > 0) {
				Debug.LogError ("One or more triangles are identical to other triangles, this is not a good thing to have in a navmesh\nIncreasing the scale of the mesh might help\nNumber of triangles with error: "+identicalError+"\n");
			}
			RebuildBBTree (this);
			
#if ASTARDEBUG
			for (int i=0;i<nodes.Length;i++) {
				TriangleMeshNode node = nodes[i] as TriangleMeshNode;
				
				float a1 = Polygon.TriangleArea2 ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],(Vector3)vertices[node.v2]);
				
				long a2 = Polygon.TriangleArea2 (vertices[node.v0],vertices[node.v1],vertices[node.v2]);
				if (a1 * a2 < 0) Debug.LogError (a1+ " " + a2);
				
				
				if (Polygon.IsClockwise (vertices[node.v0],vertices[node.v1],vertices[node.v2])) {
					Debug.DrawLine ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],Color.green);
					Debug.DrawLine ((Vector3)vertices[node.v1],(Vector3)vertices[node.v2],Color.green);
					Debug.DrawLine ((Vector3)vertices[node.v2],(Vector3)vertices[node.v0],Color.green);
				} else {
					Debug.DrawLine ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v1],(Vector3)vertices[node.v2],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v2],(Vector3)vertices[node.v0],Color.red);
				}
			}
#endif
			//Debug.Log ("Graph Generation - NavMesh - Time to compute graph "+((Time.realtimeSinceStartup-startTime)*1000F).ToString ("0")+"ms");
		}
예제 #26
0
 /** Returns the closest point of the node */
 public static Vector3 ClosestPointOnNode(TriangleMeshNode node, Int3[] vertices, Vector3 pos)
 {
     return(Polygon.ClosestPointOnTriangle((Vector3)vertices[node.v0], (Vector3)vertices[node.v1], (Vector3)vertices[node.v2], pos));
 }
예제 #27
0
		/** Returns if the point is inside the node in XZ space */
		public bool ContainsPoint (TriangleMeshNode node, Vector3 pos) {
			if (	Polygon.IsClockwise ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1], pos)
			    && 	Polygon.IsClockwise ((Vector3)vertices[node.v1],(Vector3)vertices[node.v2], pos)
			    && 	Polygon.IsClockwise ((Vector3)vertices[node.v2],(Vector3)vertices[node.v0], pos)) {
				return true;
			}
			return false;
		}
예제 #28
0
 public bool ContainsPoint(TriangleMeshNode node, Vector3 pos)
 {
     return Polygon.IsClockwise((Vector3)this.GetVertex(node.v0), (Vector3)this.GetVertex(node.v1), pos) && Polygon.IsClockwise((Vector3)this.GetVertex(node.v1), (Vector3)this.GetVertex(node.v2), pos) && Polygon.IsClockwise((Vector3)this.GetVertex(node.v2), (Vector3)this.GetVertex(node.v0), pos);
 }
예제 #29
0
 private RecastGraph.NavmeshTile CreateTile(Voxelize vox, VoxelMesh mesh, int x, int z)
 {
     if (mesh.tris == null)
     {
         throw new ArgumentNullException("mesh.tris");
     }
     if (mesh.verts == null)
     {
         throw new ArgumentNullException("mesh.verts");
     }
     RecastGraph.NavmeshTile navmeshTile = new RecastGraph.NavmeshTile();
     navmeshTile.x = x;
     navmeshTile.z = z;
     navmeshTile.w = 1;
     navmeshTile.d = 1;
     navmeshTile.tris = mesh.tris;
     navmeshTile.verts = mesh.verts;
     navmeshTile.bbTree = new BBTree();
     if (navmeshTile.tris.Length % 3 != 0)
     {
         throw new ArgumentException("Indices array's length must be a multiple of 3 (mesh.tris)");
     }
     if (navmeshTile.verts.Length >= 4095)
     {
         throw new ArgumentException("Too many vertices per tile (more than " + 4095 + ").\nTry enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector");
     }
     Dictionary<Int3, int> dictionary = this.cachedInt3_int_dict;
     dictionary.Clear();
     int[] array = new int[navmeshTile.verts.Length];
     int num = 0;
     for (int i = 0; i < navmeshTile.verts.Length; i++)
     {
         if (!dictionary.ContainsKey(navmeshTile.verts[i]))
         {
             dictionary.Add(navmeshTile.verts[i], num);
             array[i] = num;
             navmeshTile.verts[num] = navmeshTile.verts[i];
             num++;
         }
         else
         {
             array[i] = dictionary[navmeshTile.verts[i]];
         }
     }
     for (int j = 0; j < navmeshTile.tris.Length; j++)
     {
         navmeshTile.tris[j] = array[navmeshTile.tris[j]];
     }
     Int3[] array2 = new Int3[num];
     for (int k = 0; k < num; k++)
     {
         array2[k] = navmeshTile.verts[k];
     }
     navmeshTile.verts = array2;
     TriangleMeshNode[] array3 = new TriangleMeshNode[navmeshTile.tris.Length / 3];
     navmeshTile.nodes = array3;
     int graphIndex = AstarPath.active.astarData.graphs.Length;
     TriangleMeshNode.SetNavmeshHolder(graphIndex, navmeshTile);
     int num2 = x + z * this.tileXCount;
     num2 <<= 12;
     for (int l = 0; l < array3.Length; l++)
     {
         TriangleMeshNode triangleMeshNode = new TriangleMeshNode(this.active);
         array3[l] = triangleMeshNode;
         triangleMeshNode.GraphIndex = (uint)graphIndex;
         triangleMeshNode.v0 = (navmeshTile.tris[l * 3] | num2);
         triangleMeshNode.v1 = (navmeshTile.tris[l * 3 + 1] | num2);
         triangleMeshNode.v2 = (navmeshTile.tris[l * 3 + 2] | num2);
         if (!Polygon.IsClockwise(triangleMeshNode.GetVertex(0), triangleMeshNode.GetVertex(1), triangleMeshNode.GetVertex(2)))
         {
             int v = triangleMeshNode.v0;
             triangleMeshNode.v0 = triangleMeshNode.v2;
             triangleMeshNode.v2 = v;
         }
         triangleMeshNode.Walkable = true;
         triangleMeshNode.Penalty = this.initialPenalty;
         triangleMeshNode.UpdatePositionFromVertices();
     }
     navmeshTile.bbTree.RebuildFrom(array3);
     this.CreateNodeConnections(navmeshTile.nodes);
     TriangleMeshNode.SetNavmeshHolder(graphIndex, null);
     return navmeshTile;
 }
예제 #30
0
		/** Split funnel at node index \a splitIndex and throw the nodes up to that point away and replace with \a prefix.
		  * Used when the AI has happened to get sidetracked and entered a node outside the funnel.
		  */
		public void UpdateFunnelCorridor (int splitIndex, TriangleMeshNode prefix) {

			if (splitIndex > 0) {
				nodes.RemoveRange(0,splitIndex-1);
				//This is a node which should be removed, we replace it with the prefix
				nodes[0] = prefix;
			} else {
				nodes.Insert(0,prefix);
			}

			left.Clear();
			right.Clear();
			left.Add(exactStart);
			right.Add(exactStart);

			for (int i=0;i<nodes.Count-1;i++) {
				//NOTE should use return value in future versions
				nodes[i].GetPortal (nodes[i+1],left,right,false);
			}

			left.Add(exactEnd);
			right.Add(exactEnd);
		}
예제 #31
0
		/** Generates a navmesh. Based on the supplied vertices and triangles. Memory usage is about O(n) */
		public void GenerateNodes (Vector3[] vectorVertices, int[] triangles, out Vector3[] originalVertices, out Int3[] vertices) {
			
			Profiler.BeginSample ("Init");

			if (vectorVertices.Length == 0 || triangles.Length == 0) {
				originalVertices = vectorVertices;
				vertices = new Int3[0];
				//graph.CreateNodes (0);
				nodes = new TriangleMeshNode[0];
				return;
			}
			
			vertices = new Int3[vectorVertices.Length];
			
			//Backup the original vertices
			//for (int i=0;i<vectorVertices.Length;i++) {
			//	vectorVertices[i] = graph.matrix.MultiplyPoint (vectorVertices[i]);
			//}
			
			int c = 0;
			
			for (int i=0;i<vertices.Length;i++) {
				vertices[i] = (Int3)matrix.MultiplyPoint3x4 (vectorVertices[i]);
			}
			
			Dictionary<Int3,int> hashedVerts = new Dictionary<Int3,int> ();
			
			int[] newVertices = new int[vertices.Length];
				
			Profiler.EndSample ();
			Profiler.BeginSample ("Hashing");

			for (int i=0;i<vertices.Length;i++) {
				if (!hashedVerts.ContainsKey (vertices[i])) {
					newVertices[c] = i;
					hashedVerts.Add (vertices[i], c);
					c++;
				}// else {
					//Debug.Log ("Hash Duplicate "+hash+" "+vertices[i].ToString ());
				//}
			}
			
			/*newVertices[c] = vertices.Length-1;

			if (!hashedVerts.ContainsKey (vertices[newVertices[c]])) {
				
				hashedVerts.Add (vertices[newVertices[c]], c);
				c++;
			}*/
			
			for (int x=0;x<triangles.Length;x++) {
				Int3 vertex = vertices[triangles[x]];

				triangles[x] = hashedVerts[vertex];
			}
			
			/*for (int i=0;i<triangles.Length;i += 3) {
				
				Vector3 offset = Vector3.forward*i*0.01F;
				Debug.DrawLine (newVertices[triangles[i]]+offset,newVertices[triangles[i+1]]+offset,Color.blue);
				Debug.DrawLine (newVertices[triangles[i+1]]+offset,newVertices[triangles[i+2]]+offset,Color.blue);
				Debug.DrawLine (newVertices[triangles[i+2]]+offset,newVertices[triangles[i]]+offset,Color.blue);
			}*/
			
			Int3[] totalIntVertices = vertices;
			vertices = new Int3[c];
			originalVertices = new Vector3[c];
			for (int i=0;i<c;i++) {
				
				vertices[i] = totalIntVertices[newVertices[i]];//(Int3)graph.matrix.MultiplyPoint (vectorVertices[i]);
				originalVertices[i] = (Vector3)vectorVertices[newVertices[i]];//vectorVertices[newVertices[i]];
			}

			Profiler.EndSample ();
			Profiler.BeginSample ("Constructing Nodes");

			//graph.CreateNodes (triangles.Length/3);//new Node[triangles.Length/3];
			nodes = new TriangleMeshNode[triangles.Length/3];
			
			for (int i=0;i<nodes.Length;i++) {
				
				nodes[i] = new TriangleMeshNode(active);
				TriangleMeshNode node = nodes[i];//new MeshNode ();
				
				node.Penalty = initialPenalty;
				node.Walkable = true;
				
				
				node.v0 = triangles[i*3];
				node.v1 = triangles[i*3+1];
				node.v2 = triangles[i*3+2];
				
				if (!Polygon.IsClockwise (vertices[node.v0],vertices[node.v1],vertices[node.v2])) {
					//Debug.DrawLine (vertices[node.v0],vertices[node.v1],Color.red);
					//Debug.DrawLine (vertices[node.v1],vertices[node.v2],Color.red);
					//Debug.DrawLine (vertices[node.v2],vertices[node.v0],Color.red);
					
					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}
				
				if (Polygon.IsColinear (vertices[node.v0],vertices[node.v1],vertices[node.v2])) {
					Debug.DrawLine ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v1],(Vector3)vertices[node.v2],Color.red);
					Debug.DrawLine ((Vector3)vertices[node.v2],(Vector3)vertices[node.v0],Color.red);
				}
				
				// Make sure position is correctly set
				node.UpdatePositionFromVertices();
			}

			Profiler.EndSample ();

			Dictionary<Int2,TriangleMeshNode> sides = new Dictionary<Int2, TriangleMeshNode>();
			
			for (int i=0, j=0;i<triangles.Length; j+=1, i+=3) {
				sides[new Int2(triangles[i+0],triangles[i+1])] = nodes[j];
				sides[new Int2(triangles[i+1],triangles[i+2])] = nodes[j];
				sides[new Int2(triangles[i+2],triangles[i+0])] = nodes[j];
			}

			Profiler.BeginSample ("Connecting Nodes");

			List<MeshNode> connections = new List<MeshNode> ();
			List<uint> connectionCosts = new List<uint> ();
			
			int identicalError = 0;

			for (int i=0, j=0;i<triangles.Length; j+=1, i+=3) {
				connections.Clear ();
				connectionCosts.Clear ();
				
				//Int3 indices = new Int3(triangles[i],triangles[i+1],triangles[i+2]);
				
				TriangleMeshNode node = nodes[j];

				for ( int q = 0; q < 3; q++ ) {
					TriangleMeshNode other;
					if (sides.TryGetValue ( new Int2 (triangles[i+((q+1)%3)], triangles[i+q]), out other ) ) {
						connections.Add (other);
						connectionCosts.Add ((uint)(node.position-other.position).costMagnitude);
					}
				}

				node.connections = connections.ToArray ();
				node.connectionCosts = connectionCosts.ToArray ();
			}
			
			if (identicalError > 0) {
				Debug.LogError ("One or more triangles are identical to other triangles, this is not a good thing to have in a navmesh\nIncreasing the scale of the mesh might help\nNumber of triangles with error: "+identicalError+"\n");
			}

			Profiler.EndSample ();
			Profiler.BeginSample ("Rebuilding BBTree");

			RebuildBBTree (this);

			Profiler.EndSample ();

			//Debug.Log ("Graph Generation - NavMesh - Time to compute graph "+((Time.realtimeSinceStartup-startTime)*1000F).ToString ("0")+"ms");
		}
예제 #32
0
		/** Returns the closest point of the node */
		public Vector3 ClosestPointOnNode (TriangleMeshNode node, Vector3 pos) {
			return Polygon.ClosestPointOnTriangle ((Vector3)GetVertex(node.v0),(Vector3)GetVertex(node.v1),(Vector3)GetVertex(node.v2),pos);
		}
예제 #33
0
		/** Returns if the point is inside the node in XZ space */
		public bool ContainsPoint (TriangleMeshNode node, Vector3 pos) {
			if (	Polygon.IsClockwise ((Vector3)GetVertex(node.v0),(Vector3)GetVertex(node.v1), pos)
			    && 	Polygon.IsClockwise ((Vector3)GetVertex(node.v1),(Vector3)GetVertex(node.v2), pos)
			    && 	Polygon.IsClockwise ((Vector3)GetVertex(node.v2),(Vector3)GetVertex(node.v0), pos)) {
				return true;
			}
			return false;
		}
예제 #34
0
 private void CreateNodeConnections(TriangleMeshNode[] nodes)
 {
     List<MeshNode> list = ListPool<MeshNode>.Claim();
     List<uint> list2 = ListPool<uint>.Claim();
     Dictionary<Int2, int> dictionary = this.cachedInt2_int_dict;
     dictionary.Clear();
     for (int i = 0; i < nodes.Length; i++)
     {
         TriangleMeshNode triangleMeshNode = nodes[i];
         int vertexCount = triangleMeshNode.GetVertexCount();
         for (int j = 0; j < vertexCount; j++)
         {
             Int2 key = new Int2(triangleMeshNode.GetVertexIndex(j), triangleMeshNode.GetVertexIndex((j + 1) % vertexCount));
             if (!dictionary.ContainsKey(key))
             {
                 dictionary.Add(key, i);
             }
         }
     }
     for (int k = 0; k < nodes.Length; k++)
     {
         TriangleMeshNode triangleMeshNode2 = nodes[k];
         list.Clear();
         list2.Clear();
         int vertexCount2 = triangleMeshNode2.GetVertexCount();
         for (int l = 0; l < vertexCount2; l++)
         {
             int vertexIndex = triangleMeshNode2.GetVertexIndex(l);
             int vertexIndex2 = triangleMeshNode2.GetVertexIndex((l + 1) % vertexCount2);
             int num;
             if (dictionary.TryGetValue(new Int2(vertexIndex2, vertexIndex), out num))
             {
                 TriangleMeshNode triangleMeshNode3 = nodes[num];
                 int vertexCount3 = triangleMeshNode3.GetVertexCount();
                 for (int m = 0; m < vertexCount3; m++)
                 {
                     if (triangleMeshNode3.GetVertexIndex(m) == vertexIndex2 && triangleMeshNode3.GetVertexIndex((m + 1) % vertexCount3) == vertexIndex)
                     {
                         uint costMagnitude = (uint)(triangleMeshNode2.position - triangleMeshNode3.position).costMagnitude;
                         list.Add(triangleMeshNode3);
                         list2.Add(costMagnitude);
                         break;
                     }
                 }
             }
         }
         triangleMeshNode2.connections = list.ToArray();
         triangleMeshNode2.connectionCosts = list2.ToArray();
     }
     ListPool<MeshNode>.Release(list);
     ListPool<uint>.Release(list2);
 }
예제 #35
0
        public Vector3 Update(Vector3 position, List <Vector3> buffer, int numCorners, out bool lastCorner, out bool requiresRepath)
        {
            lastCorner     = false;
            requiresRepath = false;
            var i3Pos = (Int3)position;

            if (nodes[currentNode].Destroyed)
            {
                requiresRepath = true;
                lastCorner     = false;
                buffer.Add(position);
                return(position);
            }

            // Check if we are in the same node as we were in during the last frame
            if (nodes[currentNode].ContainsPoint(i3Pos))
            {
                // Only check for destroyed nodes every 10 frames
                if (checkForDestroyedNodesCounter >= 10)
                {
                    checkForDestroyedNodesCounter = 0;

                    // Loop through all nodes and check if they are destroyed
                    // If so, we really need a recalculation of our path quickly
                    // since there might be an obstacle blocking our path after
                    // a graph update or something similar
                    for (int i = 0, t = nodes.Count; i < t; i++)
                    {
                        if (nodes[i].Destroyed)
                        {
                            requiresRepath = true;
                            break;
                        }
                    }
                }
                else
                {
                    checkForDestroyedNodesCounter++;
                }
            }
            else
            {
                // This part of the code is relatively seldom called
                // Most of the time we are still on the same node as during the previous frame

                // Otherwise check the 2 nodes ahead and 2 nodes back
                // If they contain the node in XZ space, then we probably moved into those nodes
                bool found = false;

                // 2 nodes ahead
                for (int i = currentNode + 1, t = System.Math.Min(currentNode + 3, nodes.Count); i < t && !found; i++)
                {
                    // If the node is destroyed, make sure we recalculate a new path quickly
                    if (nodes[i].Destroyed)
                    {
                        requiresRepath = true;
                        lastCorner     = false;
                        buffer.Add(position);
                        return(position);
                    }

                    // We found a node which contains our current position in XZ space
                    if (nodes[i].ContainsPoint(i3Pos))
                    {
                        currentNode = i;
                        found       = true;
                    }
                }

                // 2 nodes behind
                for (int i = currentNode - 1, t = System.Math.Max(currentNode - 3, 0); i > t && !found; i--)
                {
                    if (nodes[i].Destroyed)
                    {
                        requiresRepath = true;
                        lastCorner     = false;
                        buffer.Add(position);
                        return(position);
                    }

                    if (nodes[i].ContainsPoint(i3Pos))
                    {
                        currentNode = i;
                        found       = true;
                    }
                }

                if (!found)
                {
                    int              closestNodeInPath    = 0;
                    int              closestIsNeighbourOf = 0;
                    float            closestDist          = float.PositiveInfinity;
                    bool             closestIsInPath      = false;
                    TriangleMeshNode closestNode          = null;

                    int containingIndex = nodes.Count - 1;

                    // If we still couldn't find a good node
                    // Check all nodes in the whole path

                    // We are checking for if any node is destroyed in the loop
                    // So we can reset this counter
                    checkForDestroyedNodesCounter = 0;

                    for (int i = 0, t = nodes.Count; i < t; i++)
                    {
                        if (nodes[i].Destroyed)
                        {
                            requiresRepath = true;
                            lastCorner     = false;
                            buffer.Add(position);
                            return(position);
                        }

                        Vector3 close = nodes[i].ClosestPointOnNode(position);
                        float   d     = (close - position).sqrMagnitude;
                        if (d < closestDist)
                        {
                            closestDist       = d;
                            closestNodeInPath = i;
                            closestNode       = nodes[i];
                            closestIsInPath   = true;
                        }
                    }

                    // Loop through all neighbours of all nodes in the path
                    // and find the closet point on them
                    // We cannot just look on the ones in the path since it is impossible
                    // to know if we are outside the navmesh completely or if we have just
                    // stepped in to an adjacent node

                    // Need to make a copy here, the JIT will move this variable to the heap
                    // because it is used inside a delegate, if we didn't make a copy here
                    // we would *always* allocate 24 bytes (sizeof(position)) on the heap every time
                    // this method was called
                    // now we only do it when this IF statement is executed
                    var posCopy = position;

                    GraphNodeDelegate del = node => {
                        // Check so that this neighbour we are processing is neither the node after the current node or the node before the current node in the path
                        // This is done for optimization, we have already checked those nodes earlier
                        if (!(containingIndex > 0 && node == nodes[containingIndex - 1]) && !(containingIndex < nodes.Count - 1 && node == nodes[containingIndex + 1]))
                        {
                            // Check if the neighbour was a mesh node
                            var mn = node as TriangleMeshNode;
                            if (mn != null)
                            {
                                // Find the distance to the closest point on it from our current position
                                var   close = mn.ClosestPointOnNode(posCopy);
                                float d     = (close - posCopy).sqrMagnitude;

                                // Is that distance better than the best distance seen so far
                                if (d < closestDist)
                                {
                                    closestDist          = d;
                                    closestIsNeighbourOf = containingIndex;
                                    closestNode          = mn;
                                    closestIsInPath      = false;
                                }
                            }
                        }
                    };

                    // Loop through all the nodes in the path in reverse order
                    // The callback needs to know about the index, so we store it
                    // in a local variable which it can read
                    for (; containingIndex >= 0; containingIndex--)
                    {
                        // Loop through all neighbours of the node
                        nodes[containingIndex].GetConnections(del);
                    }

                    // Check if the closest node
                    // was on the path already or if we need to adjust it
                    if (closestIsInPath)
                    {
                        // If we have found a node
                        // Snap to the closest point in XZ space (keep the Y coordinate)
                        // If we would have snapped to the closest point in 3D space, the agent
                        // might slow down when traversing slopes
                        currentNode = closestNodeInPath;
                        position    = nodes[closestNodeInPath].ClosestPointOnNodeXZ(position);
                    }
                    else
                    {
                        // Snap to the closest point in XZ space on the node
                        position = closestNode.ClosestPointOnNodeXZ(position);

                        // We have found a node containing the position, but it is outside the funnel
                        // Recalculate the funnel to include this node
                        exactStart = position;
                        UpdateFunnelCorridor(closestIsNeighbourOf, closestNode);

                        // Restart from the first node in the updated path
                        currentNode = 0;
                    }
                }
            }

            currentPosition = position;


            if (!FindNextCorners(position, currentNode, buffer, numCorners, out lastCorner))
            {
                Debug.LogError("Oh oh");
                buffer.Add(position);
                return(position);
            }

            return(position);
        }
예제 #36
0
        /** Generates a navmesh. Based on the supplied vertices and triangles. Memory usage is about O(n) */
        void GenerateNodes(Vector3[] vectorVertices, int[] triangles, out Vector3[] originalVertices, out Int3[] vertices)
        {
            Profiler.BeginSample("Init");

            if (vectorVertices.Length == 0 || triangles.Length == 0)
            {
                originalVertices = vectorVertices;
                vertices         = new Int3[0];
                //graph.CreateNodes (0);
                nodes = new TriangleMeshNode[0];
                return;
            }

            vertices = new Int3[vectorVertices.Length];

            //Backup the original vertices
            //for (int i=0;i<vectorVertices.Length;i++) {
            //	vectorVertices[i] = graph.matrix.MultiplyPoint (vectorVertices[i]);
            //}

            int c = 0;

            for (int i = 0; i < vertices.Length; i++)
            {
                vertices[i] = (Int3)matrix.MultiplyPoint3x4(vectorVertices[i]);
            }

            Dictionary <Int3, int> hashedVerts = new Dictionary <Int3, int> ();

            int[] newVertices = new int[vertices.Length];

            Profiler.EndSample();
            Profiler.BeginSample("Hashing");

            for (int i = 0; i < vertices.Length; i++)
            {
                if (!hashedVerts.ContainsKey(vertices[i]))
                {
                    newVertices[c] = i;
                    hashedVerts.Add(vertices[i], c);
                    c++;
                }                // else {
                //Debug.Log ("Hash Duplicate "+hash+" "+vertices[i].ToString ());
                //}
            }

            /*newVertices[c] = vertices.Length-1;
             *
             * if (!hashedVerts.ContainsKey (vertices[newVertices[c]])) {
             *
             *      hashedVerts.Add (vertices[newVertices[c]], c);
             *      c++;
             * }*/

            for (int x = 0; x < triangles.Length; x++)
            {
                Int3 vertex = vertices[triangles[x]];

                triangles[x] = hashedVerts[vertex];
            }

            /*for (int i=0;i<triangles.Length;i += 3) {
             *
             *      Vector3 offset = Vector3.forward*i*0.01F;
             *      Debug.DrawLine (newVertices[triangles[i]]+offset,newVertices[triangles[i+1]]+offset,Color.blue);
             *      Debug.DrawLine (newVertices[triangles[i+1]]+offset,newVertices[triangles[i+2]]+offset,Color.blue);
             *      Debug.DrawLine (newVertices[triangles[i+2]]+offset,newVertices[triangles[i]]+offset,Color.blue);
             * }*/

            Int3[] totalIntVertices = vertices;
            vertices         = new Int3[c];
            originalVertices = new Vector3[c];
            for (int i = 0; i < c; i++)
            {
                vertices[i]         = totalIntVertices[newVertices[i]];        //(Int3)graph.matrix.MultiplyPoint (vectorVertices[i]);
                originalVertices[i] = (Vector3)vectorVertices[newVertices[i]]; //vectorVertices[newVertices[i]];
            }

            Profiler.EndSample();
            Profiler.BeginSample("Constructing Nodes");

            //graph.CreateNodes (triangles.Length/3);//new Node[triangles.Length/3];
            nodes = new TriangleMeshNode[triangles.Length / 3];

            int graphIndex = active.astarData.GetGraphIndex(this);

            // Does not have to set this, it is set in ScanInternal
            //TriangleMeshNode.SetNavmeshHolder ((int)graphIndex,this);

            for (int i = 0; i < nodes.Length; i++)
            {
                nodes[i] = new TriangleMeshNode(active);
                TriangleMeshNode node = nodes[i];                //new MeshNode ();

                node.GraphIndex = (uint)graphIndex;
                node.Penalty    = initialPenalty;
                node.Walkable   = true;


                node.v0 = triangles[i * 3];
                node.v1 = triangles[i * 3 + 1];
                node.v2 = triangles[i * 3 + 2];

                if (!Polygon.IsClockwise(vertices[node.v0], vertices[node.v1], vertices[node.v2]))
                {
                    //Debug.DrawLine (vertices[node.v0],vertices[node.v1],Color.red);
                    //Debug.DrawLine (vertices[node.v1],vertices[node.v2],Color.red);
                    //Debug.DrawLine (vertices[node.v2],vertices[node.v0],Color.red);

                    int tmp = node.v0;
                    node.v0 = node.v2;
                    node.v2 = tmp;
                }

                if (Polygon.IsColinear(vertices[node.v0], vertices[node.v1], vertices[node.v2]))
                {
                    Debug.DrawLine((Vector3)vertices[node.v0], (Vector3)vertices[node.v1], Color.red);
                    Debug.DrawLine((Vector3)vertices[node.v1], (Vector3)vertices[node.v2], Color.red);
                    Debug.DrawLine((Vector3)vertices[node.v2], (Vector3)vertices[node.v0], Color.red);
                }

                // Make sure position is correctly set
                node.UpdatePositionFromVertices();
            }

            Profiler.EndSample();

            Dictionary <Int2, TriangleMeshNode> sides = new Dictionary <Int2, TriangleMeshNode>();

            for (int i = 0, j = 0; i < triangles.Length; j += 1, i += 3)
            {
                sides[new Int2(triangles[i + 0], triangles[i + 1])] = nodes[j];
                sides[new Int2(triangles[i + 1], triangles[i + 2])] = nodes[j];
                sides[new Int2(triangles[i + 2], triangles[i + 0])] = nodes[j];
            }

            Profiler.BeginSample("Connecting Nodes");

            List <MeshNode> connections     = new List <MeshNode> ();
            List <uint>     connectionCosts = new List <uint> ();

            int identicalError = 0;

            for (int i = 0, j = 0; i < triangles.Length; j += 1, i += 3)
            {
                connections.Clear();
                connectionCosts.Clear();

                //Int3 indices = new Int3(triangles[i],triangles[i+1],triangles[i+2]);

                TriangleMeshNode node = nodes[j];

                for (int q = 0; q < 3; q++)
                {
                    TriangleMeshNode other;
                    if (sides.TryGetValue(new Int2(triangles[i + ((q + 1) % 3)], triangles[i + q]), out other))
                    {
                        connections.Add(other);
                        connectionCosts.Add((uint)(node.position - other.position).costMagnitude);
                    }
                }

                node.connections     = connections.ToArray();
                node.connectionCosts = connectionCosts.ToArray();
            }

            if (identicalError > 0)
            {
                Debug.LogError("One or more triangles are identical to other triangles, this is not a good thing to have in a navmesh\nIncreasing the scale of the mesh might help\nNumber of triangles with error: " + identicalError + "\n");
            }

            Profiler.EndSample();
            Profiler.BeginSample("Rebuilding BBTree");

            RebuildBBTree(this);

            Profiler.EndSample();

            //Debug.Log ("Graph Generation - NavMesh - Time to compute graph "+((Time.realtimeSinceStartup-startTime)*1000F).ToString ("0")+"ms");
        }
예제 #37
0
 public void ReplaceTile(int x, int z, int w, int d, Int3[] verts, int[] tris, bool worldSpace)
 {
     if (x + w > this.tileXCount || z + d > this.tileZCount || x < 0 || z < 0)
     {
         throw new ArgumentException(string.Concat(new object[]
         {
             "Tile is placed at an out of bounds position or extends out of the graph bounds (",
             x,
             ", ",
             z,
             " [",
             w,
             ", ",
             d,
             "] ",
             this.tileXCount,
             " ",
             this.tileZCount,
             ")"
         }));
     }
     if (w < 1 || d < 1)
     {
         throw new ArgumentException(string.Concat(new object[]
         {
             "width and depth must be greater or equal to 1. Was ",
             w,
             ", ",
             d
         }));
     }
     for (int i = z; i < z + d; i++)
     {
         for (int j = x; j < x + w; j++)
         {
             RecastGraph.NavmeshTile navmeshTile = this.tiles[j + i * this.tileXCount];
             if (navmeshTile != null)
             {
                 this.RemoveConnectionsFromTile(navmeshTile);
                 for (int k = 0; k < navmeshTile.nodes.Length; k++)
                 {
                     navmeshTile.nodes[k].Destroy();
                 }
                 for (int l = navmeshTile.z; l < navmeshTile.z + navmeshTile.d; l++)
                 {
                     for (int m = navmeshTile.x; m < navmeshTile.x + navmeshTile.w; m++)
                     {
                         RecastGraph.NavmeshTile navmeshTile2 = this.tiles[m + l * this.tileXCount];
                         if (navmeshTile2 == null || navmeshTile2 != navmeshTile)
                         {
                             throw new Exception("This should not happen");
                         }
                         if (l < z || l >= z + d || m < x || m >= x + w)
                         {
                             this.tiles[m + l * this.tileXCount] = RecastGraph.NewEmptyTile(m, l);
                             if (this.batchTileUpdate)
                             {
                                 this.batchUpdatedTiles.Add(m + l * this.tileXCount);
                             }
                         }
                         else
                         {
                             this.tiles[m + l * this.tileXCount] = null;
                         }
                     }
                 }
             }
         }
     }
     RecastGraph.NavmeshTile navmeshTile3 = new RecastGraph.NavmeshTile();
     navmeshTile3.x = x;
     navmeshTile3.z = z;
     navmeshTile3.w = w;
     navmeshTile3.d = d;
     navmeshTile3.tris = tris;
     navmeshTile3.verts = verts;
     navmeshTile3.bbTree = new BBTree();
     if (navmeshTile3.tris.Length % 3 != 0)
     {
         throw new ArgumentException("Triangle array's length must be a multiple of 3 (tris)");
     }
     if (navmeshTile3.verts.Length > 65535)
     {
         throw new ArgumentException("Too many vertices per tile (more than 65535)");
     }
     if (!worldSpace)
     {
         if (!Mathf.Approximately((float)(x * this.tileSizeX) * this.cellSize * 1000f, (float)Math.Round((double)((float)(x * this.tileSizeX) * this.cellSize * 1000f))))
         {
             UnityEngine.Debug.LogWarning("Possible numerical imprecision. Consider adjusting tileSize and/or cellSize");
         }
         if (!Mathf.Approximately((float)(z * this.tileSizeZ) * this.cellSize * 1000f, (float)Math.Round((double)((float)(z * this.tileSizeZ) * this.cellSize * 1000f))))
         {
             UnityEngine.Debug.LogWarning("Possible numerical imprecision. Consider adjusting tileSize and/or cellSize");
         }
         Int3 rhs = (Int3)(new Vector3((float)(x * this.tileSizeX) * this.cellSize, 0f, (float)(z * this.tileSizeZ) * this.cellSize) + this.forcedBounds.min);
         for (int n = 0; n < verts.Length; n++)
         {
             verts[n] += rhs;
         }
     }
     TriangleMeshNode[] array = new TriangleMeshNode[navmeshTile3.tris.Length / 3];
     navmeshTile3.nodes = array;
     int graphIndex = AstarPath.active.astarData.graphs.Length;
     TriangleMeshNode.SetNavmeshHolder(graphIndex, navmeshTile3);
     int num = x + z * this.tileXCount;
     num <<= 12;
     for (int num2 = 0; num2 < array.Length; num2++)
     {
         TriangleMeshNode triangleMeshNode = new TriangleMeshNode(this.active);
         array[num2] = triangleMeshNode;
         triangleMeshNode.GraphIndex = (uint)graphIndex;
         triangleMeshNode.v0 = (navmeshTile3.tris[num2 * 3] | num);
         triangleMeshNode.v1 = (navmeshTile3.tris[num2 * 3 + 1] | num);
         triangleMeshNode.v2 = (navmeshTile3.tris[num2 * 3 + 2] | num);
         if (!Polygon.IsClockwise(triangleMeshNode.GetVertex(0), triangleMeshNode.GetVertex(1), triangleMeshNode.GetVertex(2)))
         {
             int v = triangleMeshNode.v0;
             triangleMeshNode.v0 = triangleMeshNode.v2;
             triangleMeshNode.v2 = v;
         }
         triangleMeshNode.Walkable = true;
         triangleMeshNode.Penalty = this.initialPenalty;
         triangleMeshNode.UpdatePositionFromVertices();
     }
     navmeshTile3.bbTree.RebuildFrom(array);
     this.CreateNodeConnections(navmeshTile3.nodes);
     for (int num3 = z; num3 < z + d; num3++)
     {
         for (int num4 = x; num4 < x + w; num4++)
         {
             this.tiles[num4 + num3 * this.tileXCount] = navmeshTile3;
         }
     }
     if (this.batchTileUpdate)
     {
         this.batchUpdatedTiles.Add(x + z * this.tileXCount);
     }
     else
     {
         this.ConnectTileWithNeighbours(navmeshTile3);
     }
     TriangleMeshNode.SetNavmeshHolder(graphIndex, null);
     graphIndex = AstarPath.active.astarData.GetGraphIndex(this);
     for (int num5 = 0; num5 < array.Length; num5++)
     {
         array[num5].GraphIndex = (uint)graphIndex;
     }
 }
예제 #38
0
		public override void DeserializeExtraInfo (GraphSerializationContext ctx)
		{
			
			uint graphIndex = (uint)active.astarData.GetGraphIndex(this);
			TriangleMeshNode.SetNavmeshHolder ((int)graphIndex,this);
			
			int c1 = ctx.reader.ReadInt32();
			int c2 = ctx.reader.ReadInt32();
			
			if (c1 == -1) {
				nodes = new TriangleMeshNode[0];
				_vertices = new Int3[0];
				originalVertices = new Vector3[0];
			}
			
			nodes = new TriangleMeshNode[c1];
			_vertices = new Int3[c2];
			originalVertices = new Vector3[c2];
			
			for (int i=0;i<c2;i++) {
				_vertices[i] = new Int3(ctx.reader.ReadInt32(), ctx.reader.ReadInt32(), ctx.reader.ReadInt32());
				originalVertices[i] = new Vector3(ctx.reader.ReadSingle(), ctx.reader.ReadSingle(), ctx.reader.ReadSingle());
			}
			
			bbTree = new BBTree(this);
			
			for (int i=0;i<c1;i++) {
				nodes[i] = new TriangleMeshNode(active);
				TriangleMeshNode node = nodes[i];
				node.DeserializeNode(ctx);
				node.GraphIndex = graphIndex;
				node.UpdatePositionFromVertices();
				bbTree.Insert (node);
			}
		}
예제 #39
0
 public override void DeserializeExtraInfo(GraphSerializationContext ctx)
 {
     BinaryReader reader = ctx.reader;
     this.tileXCount = reader.ReadInt32();
     if (this.tileXCount < 0)
     {
         return;
     }
     this.tileZCount = reader.ReadInt32();
     this.tiles = new RecastGraph.NavmeshTile[this.tileXCount * this.tileZCount];
     TriangleMeshNode.SetNavmeshHolder(ctx.graphIndex, this);
     for (int i = 0; i < this.tileZCount; i++)
     {
         for (int j = 0; j < this.tileXCount; j++)
         {
             int num = j + i * this.tileXCount;
             int num2 = reader.ReadInt32();
             if (num2 < 0)
             {
                 throw new Exception("Invalid tile coordinates (x < 0)");
             }
             int num3 = reader.ReadInt32();
             if (num3 < 0)
             {
                 throw new Exception("Invalid tile coordinates (z < 0)");
             }
             if (num2 != j || num3 != i)
             {
                 this.tiles[num] = this.tiles[num3 * this.tileXCount + num2];
             }
             else
             {
                 RecastGraph.NavmeshTile navmeshTile = new RecastGraph.NavmeshTile();
                 navmeshTile.x = num2;
                 navmeshTile.z = num3;
                 navmeshTile.w = reader.ReadInt32();
                 navmeshTile.d = reader.ReadInt32();
                 navmeshTile.bbTree = new BBTree();
                 this.tiles[num] = navmeshTile;
                 int num4 = reader.ReadInt32();
                 if (num4 % 3 != 0)
                 {
                     throw new Exception("Corrupt data. Triangle indices count must be divisable by 3. Got " + num4);
                 }
                 navmeshTile.tris = new int[num4];
                 for (int k = 0; k < navmeshTile.tris.Length; k++)
                 {
                     navmeshTile.tris[k] = reader.ReadInt32();
                 }
                 navmeshTile.verts = new Int3[reader.ReadInt32()];
                 for (int l = 0; l < navmeshTile.verts.Length; l++)
                 {
                     navmeshTile.verts[l] = new Int3(reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32());
                 }
                 int num5 = reader.ReadInt32();
                 navmeshTile.nodes = new TriangleMeshNode[num5];
                 num <<= 12;
                 for (int m = 0; m < navmeshTile.nodes.Length; m++)
                 {
                     TriangleMeshNode triangleMeshNode = new TriangleMeshNode(this.active);
                     navmeshTile.nodes[m] = triangleMeshNode;
                     triangleMeshNode.DeserializeNode(ctx);
                     triangleMeshNode.v0 = (navmeshTile.tris[m * 3] | num);
                     triangleMeshNode.v1 = (navmeshTile.tris[m * 3 + 1] | num);
                     triangleMeshNode.v2 = (navmeshTile.tris[m * 3 + 2] | num);
                     triangleMeshNode.UpdatePositionFromVertices();
                 }
                 navmeshTile.bbTree.RebuildFrom(navmeshTile.nodes);
             }
         }
     }
 }
예제 #40
0
		public override void DeserializeExtraInfo (GraphSerializationContext ctx) {

			uint graphIndex = (uint)ctx.graphIndex;
			TriangleMeshNode.SetNavmeshHolder ((int)graphIndex,this);

			int nodeCount = ctx.reader.ReadInt32();
			int vertexCount = ctx.reader.ReadInt32();

			if (nodeCount == -1) {
				nodes = new TriangleMeshNode[0];
				_vertices = new Int3[0];
				originalVertices = new Vector3[0];
			}

			nodes = new TriangleMeshNode[nodeCount];
			_vertices = new Int3[vertexCount];
			originalVertices = new Vector3[vertexCount];

			for (int i=0;i<vertexCount;i++) {
				_vertices[i] = new Int3(ctx.reader.ReadInt32(), ctx.reader.ReadInt32(), ctx.reader.ReadInt32());
				originalVertices[i] = new Vector3(ctx.reader.ReadSingle(), ctx.reader.ReadSingle(), ctx.reader.ReadSingle());
			}

			bbTree = new BBTree();

			for (int i = 0; i < nodeCount;i++) {
				nodes[i] = new TriangleMeshNode(active);
				TriangleMeshNode node = nodes[i];
				node.DeserializeNode(ctx);
				node.UpdatePositionFromVertices();
			}

			bbTree.RebuildFrom (nodes);
		}
예제 #41
0
 public bool ContainsPoint(TriangleMeshNode node, Vector3 pos)
 {
     return(node.ContainsPoint((Int3)pos));
 }
예제 #42
0
		/** Returns the closest point of the node */
		public static Vector3 ClosestPointOnNode (TriangleMeshNode node, Int3[] vertices, Vector3 pos) {
			return Polygon.ClosestPointOnTriangle ((Vector3)vertices[node.v0],(Vector3)vertices[node.v1],(Vector3)vertices[node.v2],pos);
		}
예제 #43
0
        /** Create a tile at tile index \a x, \a z from the mesh.
         * \version Since version 3.7.6 the implementation is thread safe
         */
        NavmeshTile CreateTile(Voxelize vox, VoxelMesh mesh, int x, int z, int threadIndex)
        {
            if (mesh.tris == null)
            {
                throw new System.ArgumentNullException("mesh.tris");
            }
            if (mesh.verts == null)
            {
                throw new System.ArgumentNullException("mesh.verts");
            }
            if (mesh.tris.Length % 3 != 0)
            {
                throw new System.ArgumentException("Indices array's length must be a multiple of 3 (mesh.tris)");
            }
            if (mesh.verts.Length >= VertexIndexMask)
            {
                if (tileXCount * tileZCount == 1)
                {
                    throw new System.ArgumentException("Too many vertices per tile (more than " + VertexIndexMask + ")." +
                                                       "\n<b>Try enabling tiling in the recast graph settings.</b>\n");
                }
                else
                {
                    throw new System.ArgumentException("Too many vertices per tile (more than " + VertexIndexMask + ")." +
                                                       "\n<b>Try reducing tile size or enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector</b>");
                }
            }

            // Create a new navmesh tile and assign its settings
            var tile = new NavmeshTile {
                x      = x,
                z      = z,
                w      = 1,
                d      = 1,
                tris   = mesh.tris,
                bbTree = new BBTree(),
                graph  = this,
            };

            tile.vertsInGraphSpace = Utility.RemoveDuplicateVertices(mesh.verts, tile.tris);
            tile.verts             = (Int3[])tile.vertsInGraphSpace.Clone();
            transform.Transform(tile.verts);

            // Here we are faking a new graph
            // The tile is not added to any graphs yet, but to get the position queries from the nodes
            // to work correctly (not throw exceptions because the tile is not calculated) we fake a new graph
            // and direct the position queries directly to the tile
            // The thread index is added to make sure that if multiple threads are calculating tiles at the same time
            // they will not use the same temporary graph index
            uint temporaryGraphIndex = (uint)(active.data.graphs.Length + threadIndex);

            if (temporaryGraphIndex > GraphNode.MaxGraphIndex)
            {
                // Multithreaded tile calculations use fake graph indices, see above.
                throw new System.Exception("Graph limit reached. Multithreaded recast calculations cannot be done because a few scratch graph indices are required.");
            }

            TriangleMeshNode.SetNavmeshHolder((int)temporaryGraphIndex, tile);
            // We need to lock here because creating nodes is not thread safe
            // and we may be doing this from multiple threads at the same time
            tile.nodes = new TriangleMeshNode[tile.tris.Length / 3];
            lock (active) {
                CreateNodes(tile.nodes, tile.tris, x + z * tileXCount, temporaryGraphIndex);
            }

            tile.bbTree.RebuildFrom(tile.nodes);
            CreateNodeConnections(tile.nodes);
            // Remove the fake graph
            TriangleMeshNode.SetNavmeshHolder((int)temporaryGraphIndex, null);

            return(tile);
        }
예제 #44
0
        /** This performs a linear search through all polygons returning the closest one.
         * This will fill the NNInfo with .node for the closest node not necessarily complying with the NNConstraint, and .constrainedNode with the closest node
         * complying with the NNConstraint.
         * \see GetNearestForce(Node[],Int3[],Vector3,NNConstraint,bool)
         */
        public static NNInfo GetNearestForceBoth(NavGraph graph, INavmeshHolder navmesh, Vector3 position, NNConstraint constraint, bool accurateNearestNode)
        {
            Int3 pos = (Int3)position;

            float     minDist = -1;
            GraphNode minNode = null;

            float     minConstDist = -1;
            GraphNode minConstNode = null;

            float maxDistSqr = constraint.constrainDistance ? AstarPath.active.maxNearestNodeDistanceSqr : float.PositiveInfinity;

            GraphNodeDelegateCancelable del = delegate(GraphNode _node) {
                TriangleMeshNode node = _node as TriangleMeshNode;

                if (accurateNearestNode)
                {
                    Vector3 closest = node.ClosestPointOnNode(position);
                    float   dist    = ((Vector3)pos - closest).sqrMagnitude;

                    if (minNode == null || dist < minDist)
                    {
                        minDist = dist;
                        minNode = node;
                    }

                    if (dist < maxDistSqr && constraint.Suitable(node))
                    {
                        if (minConstNode == null || dist < minConstDist)
                        {
                            minConstDist = dist;
                            minConstNode = node;
                        }
                    }
                }
                else
                {
                    if (!node.ContainsPoint((Int3)position))
                    {
                        float dist = (node.position - pos).sqrMagnitude;
                        if (minNode == null || dist < minDist)
                        {
                            minDist = dist;
                            minNode = node;
                        }

                        if (dist < maxDistSqr && constraint.Suitable(node))
                        {
                            if (minConstNode == null || dist < minConstDist)
                            {
                                minConstDist = dist;
                                minConstNode = node;
                            }
                        }
                    }
                    else
                    {
                        int dist = AstarMath.Abs(node.position.y - pos.y);

                        if (minNode == null || dist < minDist)
                        {
                            minDist = dist;
                            minNode = node;
                        }

                        if (dist < maxDistSqr && constraint.Suitable(node))
                        {
                            if (minConstNode == null || dist < minConstDist)
                            {
                                minConstDist = dist;
                                minConstNode = node;
                            }
                        }
                    }
                }
                return(true);
            };

            graph.GetNodes(del);

            NNInfo nninfo = new NNInfo(minNode);

            //Find the point closest to the nearest triangle

            if (nninfo.node != null)
            {
                TriangleMeshNode node = nninfo.node as TriangleMeshNode;                //minNode2 as MeshNode;

                Vector3 clP = node.ClosestPointOnNode(position);

                nninfo.clampedPosition = clP;
            }

            nninfo.constrainedNode = minConstNode;
            if (nninfo.constrainedNode != null)
            {
                TriangleMeshNode node = nninfo.constrainedNode as TriangleMeshNode;                //minNode2 as MeshNode;

                Vector3 clP = node.ClosestPointOnNode(position);

                nninfo.constClampedPosition = clP;
            }

            return(nninfo);
        }
예제 #45
0
        public static void UpdateArea(GraphUpdateObject o, INavmesh graph)
        {
            //System.DateTime startTime = System.DateTime.UtcNow;

            Bounds bounds = o.bounds;

            Rect r = Rect.MinMaxRect(bounds.min.x, bounds.min.z, bounds.max.x, bounds.max.z);

            IntRect r2 = new IntRect(
                Mathf.FloorToInt(bounds.min.x * Int3.Precision),
                Mathf.FloorToInt(bounds.min.z * Int3.Precision),
                Mathf.FloorToInt(bounds.max.x * Int3.Precision),
                Mathf.FloorToInt(bounds.max.z * Int3.Precision)
                );

            Int3 a = new Int3(r2.xmin, 0, r2.ymin);
            Int3 b = new Int3(r2.xmin, 0, r2.ymax);
            Int3 c = new Int3(r2.xmax, 0, r2.ymin);
            Int3 d = new Int3(r2.xmax, 0, r2.ymax);

            Int3 ia = (Int3)a;
            Int3 ib = (Int3)b;
            Int3 ic = (Int3)c;
            Int3 id = (Int3)d;


            //for (int i=0;i<nodes.Length;i++) {
            graph.GetNodes(delegate(GraphNode _node) {
                TriangleMeshNode node = _node as TriangleMeshNode;

                bool inside = false;

                int allLeft   = 0;
                int allRight  = 0;
                int allTop    = 0;
                int allBottom = 0;

                for (int v = 0; v < 3; v++)
                {
                    Int3 p       = node.GetVertex(v);
                    Vector3 vert = (Vector3)p;
                    //Vector2 vert2D = new Vector2 (vert.x,vert.z);

                    if (r2.Contains(p.x, p.z))
                    {
                        //Debug.DrawRay (vert,Vector3.up*10,Color.yellow);
                        inside = true;
                        break;
                    }

                    if (vert.x < r.xMin)
                    {
                        allLeft++;
                    }
                    if (vert.x > r.xMax)
                    {
                        allRight++;
                    }
                    if (vert.z < r.yMin)
                    {
                        allTop++;
                    }
                    if (vert.z > r.yMax)
                    {
                        allBottom++;
                    }
                }
                if (!inside)
                {
                    if (allLeft == 3 || allRight == 3 || allTop == 3 || allBottom == 3)
                    {
                        return(true);
                    }
                }

                //Debug.DrawLine ((Vector3)node.GetVertex(0),(Vector3)node.GetVertex(1),Color.yellow);
                //Debug.DrawLine ((Vector3)node.GetVertex(1),(Vector3)node.GetVertex(2),Color.yellow);
                //Debug.DrawLine ((Vector3)node.GetVertex(2),(Vector3)node.GetVertex(0),Color.yellow);

                for (int v = 0; v < 3; v++)
                {
                    int v2 = v > 1 ? 0 : v + 1;

                    Int3 vert1 = node.GetVertex(v);
                    Int3 vert2 = node.GetVertex(v2);

                    if (Polygon.Intersects(a, b, vert1, vert2))
                    {
                        inside = true; break;
                    }
                    if (Polygon.Intersects(a, c, vert1, vert2))
                    {
                        inside = true; break;
                    }
                    if (Polygon.Intersects(c, d, vert1, vert2))
                    {
                        inside = true; break;
                    }
                    if (Polygon.Intersects(d, b, vert1, vert2))
                    {
                        inside = true; break;
                    }
                }



                if (node.ContainsPoint(ia) || node.ContainsPoint(ib) || node.ContainsPoint(ic) || node.ContainsPoint(id))
                {
                    inside = true;
                }

                if (!inside)
                {
                    return(true);
                }

                o.WillUpdateNode(node);
                o.Apply(node);

                /*Debug.DrawLine ((Vector3)node.GetVertex(0),(Vector3)node.GetVertex(1),Color.blue);
                 * Debug.DrawLine ((Vector3)node.GetVertex(1),(Vector3)node.GetVertex(2),Color.blue);
                 * Debug.DrawLine ((Vector3)node.GetVertex(2),(Vector3)node.GetVertex(0),Color.blue);
                 * Debug.Break ();*/
                return(true);
            });

            //System.DateTime endTime = System.DateTime.UtcNow;
            //float theTime = (endTime-startTime).Ticks*0.0001F;
            //Debug.Log ("Intersecting bounds with navmesh took "+theTime.ToString ("0.000")+" ms");
        }
예제 #46
0
		/** Create a tile at tile index \a x , \a z from the mesh.
		 * \warning This implementation is not thread safe. It uses cached variables to improve performance
		 */
		NavmeshTile CreateTile (Voxelize vox, VoxelMesh mesh, int x, int z) {
			
			if (mesh.tris == null) throw new System.ArgumentNullException ("The mesh must be valid. tris is null.");
			if (mesh.verts == null) throw new System.ArgumentNullException ("The mesh must be valid. verts is null.");
			
			//Create a new navmesh tile and assign its settings
			NavmeshTile tile = new NavmeshTile();
			
			tile.x = x;
			tile.z = z;
			tile.w = 1;
			tile.d = 1;
			tile.tris = mesh.tris;
			tile.verts = mesh.verts;
			tile.bbTree = new BBTree(tile);
			
			if (tile.tris.Length % 3 != 0) throw new System.ArgumentException ("Indices array's length must be a multiple of 3 (mesh.tris)");
			
			if (tile.verts.Length >= VertexIndexMask) throw new System.ArgumentException ("Too many vertices per tile (more than "+VertexIndexMask+")." +
				"\nTry enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector");
			
			//Dictionary<Int3, int> firstVerts = new Dictionary<Int3, int> ();
			Dictionary<Int3, int> firstVerts = cachedInt3_int_dict;
			firstVerts.Clear();
			
			int[] compressedPointers = new int[tile.verts.Length];
			
			int count = 0;
			for (int i=0;i<tile.verts.Length;i++) {
				try {
					firstVerts.Add (tile.verts[i], count);
					compressedPointers[i] = count;
					tile.verts[count] = tile.verts[i];
					count++;
				} catch {
					//There are some cases, rare but still there, that vertices are identical
					compressedPointers[i] = firstVerts[tile.verts[i]];
				}
			}
			
			for (int i=0;i<tile.tris.Length;i++) {
				tile.tris[i] = compressedPointers[tile.tris[i]];
			}
			
			Int3[] compressed = new Int3[count];
			for (int i=0;i<count;i++) compressed[i] = tile.verts[i];
			
			tile.verts = compressed;
			
			TriangleMeshNode[] nodes = new TriangleMeshNode[tile.tris.Length/3];
			tile.nodes = nodes;
			
			//Here we are faking a new graph
			//The tile is not added to any graphs yet, but to get the position querys from the nodes
			//to work correctly (not throw exceptions because the tile is not calculated) we fake a new graph
			//and direct the position queries directly to the tile
			int graphIndex = AstarPath.active.astarData.graphs.Length;
			
			TriangleMeshNode.SetNavmeshHolder (graphIndex, tile);
			
			//This index will be ORed to the triangle indices
			int tileIndex = x + z*tileXCount;
			tileIndex <<= TileIndexOffset;
			
			//Create nodes and assign triangle indices
			for (int i=0;i<nodes.Length;i++) {
				TriangleMeshNode node = new TriangleMeshNode(active);
				nodes[i] = node;
				node.GraphIndex = (uint)graphIndex;
				node.v0 = tile.tris[i*3+0] | tileIndex;
				node.v1 = tile.tris[i*3+1] | tileIndex;
				node.v2 = tile.tris[i*3+2] | tileIndex;
				
				//Degenerate triangles might ocurr, but they will not cause any large troubles anymore
				//if (Polygon.IsColinear (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
				//	Debug.Log ("COLINEAR!!!!!!");
				//}
				
				//Make sure the triangle is clockwise
				if (!Polygon.IsClockwise (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}
				
				node.Walkable = true;
				node.Penalty = initialPenalty;
				node.UpdatePositionFromVertices();
				tile.bbTree.Insert (node);
			}
			
			CreateNodeConnections (tile.nodes);
			
			//Remove the fake graph
			TriangleMeshNode.SetNavmeshHolder (graphIndex, null);
			
			return tile;
		}
예제 #47
0
		/** Create connections between all nodes.
		 * \warning This implementation is not thread safe. It uses cached variables to improve performance
		 */
		void CreateNodeConnections (TriangleMeshNode[] nodes) {
			
			List<MeshNode> connections = Pathfinding.Util.ListPool<MeshNode>.Claim (); //new List<MeshNode>();
			List<uint> connectionCosts = Pathfinding.Util.ListPool<uint>.Claim (); //new List<uint>();
			
			Dictionary<Int2,int> nodeRefs = cachedInt2_int_dict;
			nodeRefs.Clear();
			
			//Build node neighbours
			for (int i=0;i<nodes.Length;i++) {
				
				TriangleMeshNode node = nodes[i];
				
				int av = node.GetVertexCount ();
				
				for (int a=0;a<av;a++) {
					
					//Recast can in some very special cases generate degenerate triangles which are simply lines
					//In that case, duplicate keys might be added and thus an exception will be thrown
					//It is safe to ignore the second edge though... I think (only found one case where this happens)
					try {
						nodeRefs.Add (new Int2 (node.GetVertexIndex(a), node.GetVertexIndex ((a+1) % av)), i);
					} catch (System.Exception) {
					}
				}
			}
			
			
			for (int i=0;i<nodes.Length;i++) {
				
				TriangleMeshNode node = nodes[i];
				
				connections.Clear ();
				connectionCosts.Clear ();
				
				int av = node.GetVertexCount ();
				
				for (int a=0;a<av;a++) {
					int first = node.GetVertexIndex(a);
					int second = node.GetVertexIndex((a+1) % av);
					int connNode;
					
					if (nodeRefs.TryGetValue (new Int2 (second, first), out connNode)) {
						TriangleMeshNode other = nodes[connNode];
						
						int bv = other.GetVertexCount ();
						
						for (int b=0;b<bv;b++) {
							/** \todo This will fail on edges which are only partially shared */
							if (other.GetVertexIndex (b) == second && other.GetVertexIndex ((b+1) % bv) == first) {
								uint cost = (uint)(node.position - other.position).costMagnitude;									
								connections.Add (other);
								connectionCosts.Add (cost);
								break;
							}
						}
					}
				}
				
				node.connections = connections.ToArray ();
				node.connectionCosts = connectionCosts.ToArray ();
			}
			
			Pathfinding.Util.ListPool<MeshNode>.Release (connections);
			Pathfinding.Util.ListPool<uint>.Release (connectionCosts);
		}
예제 #48
0
		public void ReplaceTile (int x, int z, int w, int d, Int3[] verts, int[] tris, bool worldSpace) {
			
			if(x + w > tileXCount || z+d > tileZCount || x < 0 || z < 0) {
				throw new System.ArgumentException ("Tile is placed at an out of bounds position or extends out of the graph bounds ("+x+", " + z + " [" + w + ", " + d+ "] " + tileXCount + " " + tileZCount + ")");
			}
			
			if (w < 1 || d < 1) throw new System.ArgumentException ("width and depth must be greater or equal to 1");
			
			//Remove previous tiles
			for (int cz=z; cz < z+d;cz++) {
				for (int cx=x; cx < x+w;cx++) {
					
					NavmeshTile otile = tiles[cx + cz*tileXCount];
					if (otile == null) continue;
					
					//Remove old tile connections
					RemoveConnectionsFromTile (otile);
					
					for (int i=0;i<otile.nodes.Length;i++) {
						otile.nodes[i].Destroy();
					}
					
					for (int qz=otile.z; qz < otile.z+otile.d;qz++) {
						for (int qx=otile.x; qx < otile.x+otile.w;qx++) {
							NavmeshTile qtile = tiles[qx + qz*tileXCount];
							if (qtile == null || qtile != otile) throw new System.Exception("This should not happen");
							
							if (qz < z || qz >= z+d || qx < x || qx >= x+w) {
								//if out of this tile's bounds, replace with empty tile
								tiles[qx + qz*tileXCount] = NewEmptyTile(qx,qz);
								
								if (batchTileUpdate) {
									batchUpdatedTiles.Add (qx + qz*tileXCount);
								}
							} else {
								//Will be replaced by the new tile
								tiles[qx + qz*tileXCount] = null;
							}
						}
					}
				}
			}
			
			//Create a new navmesh tile and assign its settings
			NavmeshTile tile = new NavmeshTile();
			
			tile.x = x;
			tile.z = z;
			tile.w = w;
			tile.d = d;
			tile.tris = tris;
			tile.verts = verts;
			tile.bbTree = new BBTree(tile);
			
			if (tile.tris.Length % 3 != 0) throw new System.ArgumentException ("Triangle array's length must be a multiple of 3 (tris)");
			
			if (tile.verts.Length > 0xFFFF) throw new System.ArgumentException ("Too many vertices per tile (more than 65535)");
			
			if (!worldSpace) {
				if (!Mathf.Approximately (x*tileSizeX*cellSize*Int3.FloatPrecision, (float)System.Math.Round(x*tileSizeX*cellSize*Int3.FloatPrecision))) Debug.LogWarning ("Possible numerical imprecision. Consider adjusting tileSize and/or cellSize");
				if (!Mathf.Approximately (z*tileSizeZ*cellSize*Int3.FloatPrecision, (float)System.Math.Round(z*tileSizeZ*cellSize*Int3.FloatPrecision))) Debug.LogWarning ("Possible numerical imprecision. Consider adjusting tileSize and/or cellSize");
			
				Int3 offset = (Int3)(new Vector3((x * tileSizeX * cellSize),0,(z * tileSizeZ * cellSize)) + forcedBounds.min);
				
				for (int i=0;i<verts.Length;i++) {
					verts[i] += offset;
				}
				
			}
			
			TriangleMeshNode[] nodes = new TriangleMeshNode[tile.tris.Length/3];
			tile.nodes = nodes;
			
			//Here we are faking a new graph
			//The tile is not added to any graphs yet, but to get the position querys from the nodes
			//to work correctly (not throw exceptions because the tile is not calculated) we fake a new graph
			//and direct the position queries directly to the tile
			int graphIndex = AstarPath.active.astarData.graphs.Length;
			
			TriangleMeshNode.SetNavmeshHolder (graphIndex, tile);
			
			//This index will be ORed to the triangle indices
			int tileIndex = x + z*tileXCount;
			tileIndex <<= TileIndexOffset;
			
			//Create nodes and assign triangle indices
			for (int i=0;i<nodes.Length;i++) {
				TriangleMeshNode node = new TriangleMeshNode(active);
				nodes[i] = node;
				node.GraphIndex = (uint)graphIndex;
				node.v0 = tile.tris[i*3+0] | tileIndex;
				node.v1 = tile.tris[i*3+1] | tileIndex;
				node.v2 = tile.tris[i*3+2] | tileIndex;
				
				//Degenerate triangles might ocurr, but they will not cause any large troubles anymore
				//if (Polygon.IsColinear (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
				//	Debug.Log ("COLINEAR!!!!!!");
				//}
				
				//Make sure the triangle is clockwise
				if (!Polygon.IsClockwise (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}
				
				node.Walkable = true;
				node.Penalty = initialPenalty;
				node.UpdatePositionFromVertices();
				
				tile.bbTree.Insert (node);
			}
			
			CreateNodeConnections (tile.nodes);
			
			//Set tile
			for (int cz=z; cz < z+d;cz++) {
				for (int cx=x; cx < x+w;cx++) {
					tiles[cx + cz*tileXCount] = tile;
				}
			}
			
			if (batchTileUpdate) {
				batchUpdatedTiles.Add (x + z*tileXCount);
			} else {
				ConnectTileWithNeighbours(tile);
				/*if (x > 0) ConnectTiles (tiles[(x-1) + z*tileXCount], tile);
				if (z > 0) ConnectTiles (tiles[x + (z-1)*tileXCount], tile);
				if (x < tileXCount-1) ConnectTiles (tiles[(x+1) + z*tileXCount], tile);
				if (z < tileZCount-1) ConnectTiles (tiles[x + (z+1)*tileXCount], tile);*/
			}
			
			//Remove the fake graph
			TriangleMeshNode.SetNavmeshHolder (graphIndex, null);
			
			//Real graph index
			//TODO, could this step be changed for this function, is a fake index required?
			graphIndex = AstarPath.active.astarData.GetGraphIndex (this);
			
			for (int i=0;i<nodes.Length;i++) nodes[i].GraphIndex = (uint)graphIndex;			
			
		}
예제 #49
0
        public override void OnDrawGizmos(bool drawNodes)
        {
            if (!drawNodes)
            {
                return;
            }

            Matrix4x4 preMatrix = matrix;

            GenerateMatrix();

            if (nodes == null)
            {
                //Scan ();
            }

            if (nodes == null)
            {
                return;
            }

            if (bbTree != null)
            {
                bbTree.OnDrawGizmos();
            }

            if (preMatrix != matrix)
            {
                //Debug.Log ("Relocating Nodes");
                RelocateNodes(preMatrix, matrix);
            }

            PathHandler debugData = AstarPath.active.debugPathData;

            for (int i = 0; i < nodes.Length; i++)
            {
                TriangleMeshNode node = (TriangleMeshNode)nodes[i];

                Gizmos.color = NodeColor(node, AstarPath.active.debugPathData);

                if (node.Walkable)
                {
                    if (AstarPath.active.showSearchTree && debugData != null && debugData.GetPathNode(node).parent != null)
                    {
                        Gizmos.DrawLine((Vector3)node.position, (Vector3)debugData.GetPathNode(node).parent.node.position);
                    }
                    else
                    {
                        for (int q = 0; q < node.connections.Length; q++)
                        {
                            Gizmos.DrawLine((Vector3)node.position, Vector3.Lerp((Vector3)node.position, (Vector3)node.connections[q].position, 0.45f));
                        }
                    }

                    Gizmos.color = AstarColor.MeshEdgeColor;
                }
                else
                {
                    Gizmos.color = Color.red;
                }
                Gizmos.DrawLine((Vector3)vertices[node.v0], (Vector3)vertices[node.v1]);
                Gizmos.DrawLine((Vector3)vertices[node.v1], (Vector3)vertices[node.v2]);
                Gizmos.DrawLine((Vector3)vertices[node.v2], (Vector3)vertices[node.v0]);
            }
        }
예제 #50
0
		public override void DeserializeExtraInfo (GraphSerializationContext ctx) {
			//NavMeshGraph.DeserializeMeshNodes (this,nodes,bytes);
			
			System.IO.BinaryReader reader = ctx.reader;
			
			tileXCount = reader.ReadInt32();
			
			if (tileXCount < 0) return;
				
			tileZCount = reader.ReadInt32();
			
			tiles = new NavmeshTile[tileXCount * tileZCount];
			
			//Make sure mesh nodes can reference this graph
			TriangleMeshNode.SetNavmeshHolder (ctx.graphIndex, this);
			
			for (int z=0;z<tileZCount;z++) {
				for (int x=0;x<tileXCount;x++) {
					
					int tileIndex = x + z*tileXCount;
					int tx = reader.ReadInt32();
					if (tx < 0) throw new System.Exception ("Invalid tile coordinates (x < 0)");
					
					int tz = reader.ReadInt32();
					if (tz < 0) throw new System.Exception ("Invalid tile coordinates (z < 0)");
					
					// This is not the origin of a large tile. Refer back to that tile.
					if (tx != x || tz != z) {
						tiles[tileIndex] = tiles[tz*tileXCount + tx];
						continue;
					}
					
					NavmeshTile tile = new NavmeshTile ();
					
					tile.x = tx;
					tile.z = tz;
					tile.w = reader.ReadInt32();
					tile.d = reader.ReadInt32();
					tile.bbTree = new BBTree (tile);
					
					tiles[tileIndex] = tile;
					
					int trisCount = reader.ReadInt32 ();
					
					if (trisCount % 3 != 0) throw new System.Exception ("Corrupt data. Triangle indices count must be divisable by 3. Got " + trisCount);
					
					tile.tris = new int[trisCount];
					for (int i=0;i<tile.tris.Length;i++) tile.tris[i] = reader.ReadInt32();
					
					tile.verts = new Int3[reader.ReadInt32()];
					for (int i=0;i<tile.verts.Length;i++) {
						tile.verts[i] = new Int3 (reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32());
					}
					
					int nodeCount = reader.ReadInt32();
					tile.nodes = new TriangleMeshNode[nodeCount];
					
					//Prepare for storing in vertex indices
					tileIndex <<= TileIndexOffset;
					
					for (int i=0;i<tile.nodes.Length;i++) {
						TriangleMeshNode node = new TriangleMeshNode (active);
						tile.nodes[i] = node;
						node.GraphIndex = (uint)ctx.graphIndex;
						
						node.DeserializeNode (ctx);
						node.v0 = tile.tris[i*3+0] | tileIndex;
						node.v1 = tile.tris[i*3+1] | tileIndex;
						node.v2 = tile.tris[i*3+2] | tileIndex;
						node.UpdatePositionFromVertices();
						
						tile.bbTree.Insert (node);
					}
				}
			}
		}
예제 #51
0
        void FindWalls(int nodeIndex, List <Vector3> wallBuffer, Vector3 position, float range)
        {
            if (range <= 0)
            {
                return;
            }

            bool negAbort = false;
            bool posAbort = false;

            range *= range;

            position.y = 0;
            //Looping as 0,-1,1,-2,2,-3,3,-4,4 etc. Avoids code duplication by keeping it to one loop instead of two
            for (int i = 0; !negAbort || !posAbort; i = i < 0 ? -i : -i - 1)
            {
                if (i < 0 && negAbort)
                {
                    continue;
                }
                if (i > 0 && posAbort)
                {
                    continue;
                }

                if (i < 0 && nodeIndex + i < 0)
                {
                    negAbort = true;
                    continue;
                }

                if (i > 0 && nodeIndex + i >= nodes.Count)
                {
                    posAbort = true;
                    continue;
                }

                TriangleMeshNode prev = nodeIndex + i - 1 < 0 ? null : nodes[nodeIndex + i - 1];
                TriangleMeshNode node = nodes[nodeIndex + i];
                TriangleMeshNode next = nodeIndex + i + 1 >= nodes.Count ? null : nodes[nodeIndex + i + 1];

                if (node.Destroyed)
                {
                    break;
                }

                if ((node.ClosestPointOnNodeXZ(position) - position).sqrMagnitude > range)
                {
                    if (i < 0)
                    {
                        negAbort = true;
                    }
                    else
                    {
                        posAbort = true;
                    }
                    continue;
                }

                for (int j = 0; j < 3; j++)
                {
                    triBuffer[j] = 0;
                }

                for (int j = 0; j < node.connections.Length; j++)
                {
                    var other = node.connections[j] as TriangleMeshNode;
                    if (other == null)
                    {
                        continue;
                    }

                    int va = -1;
                    for (int a = 0; a < 3; a++)
                    {
                        for (int b = 0; b < 3; b++)
                        {
                            if (node.GetVertex(a) == other.GetVertex((b + 1) % 3) && node.GetVertex((a + 1) % 3) == other.GetVertex(b))
                            {
                                va = a;
                                a  = 3;
                                break;
                            }
                        }
                    }
                    if (va == -1)
                    {
                        //No direct connection
                    }
                    else
                    {
                        triBuffer[va] = other == prev || other == next ? 2 : 1;
                    }
                }

                for (int j = 0; j < 3; j++)
                {
                    //Tribuffer values
                    // 0 : Navmesh border, outer edge
                    // 1 : Inner edge, to node inside funnel
                    // 2 : Inner edge, to node outside funnel
                    if (triBuffer[j] == 0)
                    {
                        //Add edge to list of walls
                        wallBuffer.Add((Vector3)node.GetVertex(j));
                        wallBuffer.Add((Vector3)node.GetVertex((j + 1) % 3));
                    }
                }
            }
        }
예제 #52
0
 public void UpdateFunnelCorridor(int splitIndex, TriangleMeshNode prefix)
 {
     if (splitIndex > 0)
     {
         this.nodes.RemoveRange(0, splitIndex - 1);
         this.nodes[0] = prefix;
     }
     else
     {
         this.nodes.Insert(0, prefix);
     }
     this.left.Clear();
     this.right.Clear();
     this.left.Add(this.exactStart);
     this.right.Add(this.exactStart);
     for (int i = 0; i < this.nodes.Count - 1; i++)
     {
         this.nodes[i].GetPortal(this.nodes[i + 1], this.left, this.right, false);
     }
     this.left.Add(this.exactEnd);
     this.right.Add(this.exactEnd);
 }