public override void RelocateNodes(Matrix4x4 oldMatrix, Matrix4x4 newMatrix) { if (this.vertices == null || this.vertices.Length == 0 || this.originalVertices == null || this.originalVertices.Length != this.vertices.Length) { return; } for (int i = 0; i < this._vertices.Length; i++) { this._vertices[i] = (Int3)newMatrix.MultiplyPoint3x4(this.originalVertices[i]); } for (int j = 0; j < this.nodes.Length; j++) { TriangleMeshNode triangleMeshNode = this.nodes[j]; triangleMeshNode.UpdatePositionFromVertices(); if (triangleMeshNode.connections != null) { for (int k = 0; k < triangleMeshNode.connections.Length; k++) { triangleMeshNode.connectionCosts[k] = (uint)(triangleMeshNode.position - triangleMeshNode.connections[k].position).costMagnitude; } } } base.SetMatrix(newMatrix); NavMeshGraph.RebuildBBTree(this); }
public override void DeserializeExtraInfo(GraphSerializationContext ctx) { uint graphIndex = (uint)ctx.graphIndex; TriangleMeshNode.SetNavmeshHolder((int)graphIndex, this); int num = ctx.reader.ReadInt32(); int num2 = ctx.reader.ReadInt32(); if (num == -1) { this.nodes = new TriangleMeshNode[0]; this._vertices = new Int3[0]; this.originalVertices = new Vector3[0]; } this.nodes = new TriangleMeshNode[num]; this._vertices = new Int3[num2]; this.originalVertices = new Vector3[num2]; for (int i = 0; i < num2; i++) { this._vertices[i] = new Int3(ctx.reader.ReadInt32(), ctx.reader.ReadInt32(), ctx.reader.ReadInt32()); this.originalVertices[i] = new Vector3(ctx.reader.ReadSingle(), ctx.reader.ReadSingle(), ctx.reader.ReadSingle()); } this.bbTree = new BBTree(); for (int j = 0; j < num; j++) { this.nodes[j] = new TriangleMeshNode(this.active); TriangleMeshNode triangleMeshNode = this.nodes[j]; triangleMeshNode.DeserializeNode(ctx); triangleMeshNode.UpdatePositionFromVertices(); } this.bbTree.RebuildFrom(this.nodes); }
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()); } for (int i = 0; i < c1; i++) { nodes[i] = new TriangleMeshNode(active); TriangleMeshNode node = nodes[i]; node.DeserializeNode(ctx); node.UpdatePositionFromVertices(); } }
/** Relocates the nodes to match the newMatrix. * The "oldMatrix" variable can be left out in this function call (only for this graph generator) since it is not used */ public override void RelocateNodes(Matrix4x4 oldMatrix, Matrix4x4 newMatrix) { //base.RelocateNodes (oldMatrix,newMatrix); if (vertices == null || vertices.Length == 0 || originalVertices == null || originalVertices.Length != vertices.Length) { return; } for (int i = 0; i < _vertices.Length; i++) { //Vector3 tmp = inv.MultiplyPoint3x4 (vertices[i]); //vertices[i] = (Int3)newMatrix.MultiplyPoint3x4 (tmp); _vertices[i] = (Int3)newMatrix.MultiplyPoint3x4((Vector3)originalVertices[i]); } for (int i = 0; i < nodes.Length; i++) { TriangleMeshNode node = (TriangleMeshNode)nodes[i]; node.UpdatePositionFromVertices(); if (node.connections != null) { for (int q = 0; q < node.connections.Length; q++) { node.connectionCosts[q] = (uint)(node.position - node.connections[q].position).costMagnitude; } } } SetMatrix(newMatrix); }
public override void DeserializeExtraInfo(GraphSerializationContext ctx) { uint graphIndex = (uint)base.active.astarData.GetGraphIndex(this); TriangleMeshNode.SetNavmeshHolder(0, (int)graphIndex, this); int num2 = ctx.reader.ReadInt32(); int num3 = ctx.reader.ReadInt32(); if (num2 == -1) { this.nodes = new TriangleMeshNode[0]; this._vertices = new VInt3[0]; this.originalVertices = new Vector3[0]; } this.nodes = new TriangleMeshNode[num2]; this._vertices = new VInt3[num3]; this.originalVertices = new Vector3[num3]; for (int i = 0; i < num3; i++) { this._vertices[i] = new VInt3(ctx.reader.ReadInt32(), ctx.reader.ReadInt32(), ctx.reader.ReadInt32()); this.originalVertices[i] = new Vector3(ctx.reader.ReadSingle(), ctx.reader.ReadSingle(), ctx.reader.ReadSingle()); } this.bbTree = new BBTree(this); for (int j = 0; j < num2; j++) { this.nodes[j] = new TriangleMeshNode(base.active); TriangleMeshNode node = this.nodes[j]; node.DeserializeNode(ctx); node.GraphIndex = graphIndex; node.UpdatePositionFromVertices(); this.bbTree.Insert(node); } }
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); }
private void GenerateNodes(Vector3[] vectorVertices, int[] triangles, out Vector3[] originalVertices, out VInt3[] vertices) { if (vectorVertices.Length == 0 || triangles.Length == 0) { originalVertices = vectorVertices; vertices = new VInt3[0]; this.nodes = new TriangleMeshNode[0]; return; } vertices = new VInt3[vectorVertices.Length]; int num = 0; for (int i = 0; i < vertices.Length; i++) { vertices[i] = (VInt3)this.matrix.MultiplyPoint3x4(vectorVertices[i]); } Dictionary<VInt3, int> dictionary = new Dictionary<VInt3, int>(); int[] array = new int[vertices.Length]; for (int j = 0; j < vertices.Length; j++) { if (!dictionary.ContainsKey(vertices[j])) { array[num] = j; dictionary.Add(vertices[j], num); num++; } } for (int k = 0; k < triangles.Length; k++) { VInt3 vInt = vertices[triangles[k]]; triangles[k] = dictionary.get_Item(vInt); } VInt3[] array2 = vertices; vertices = new VInt3[num]; originalVertices = new Vector3[num]; for (int l = 0; l < num; l++) { vertices[l] = array2[array[l]]; originalVertices[l] = vectorVertices[array[l]]; } this.nodes = new TriangleMeshNode[triangles.Length / 3]; int graphIndex = this.active.astarData.GetGraphIndex(this); for (int m = 0; m < this.nodes.Length; m++) { this.nodes[m] = new TriangleMeshNode(this.active); TriangleMeshNode triangleMeshNode = this.nodes[m]; triangleMeshNode.GraphIndex = (uint)graphIndex; triangleMeshNode.Penalty = this.initialPenalty; triangleMeshNode.Walkable = true; triangleMeshNode.v0 = triangles[m * 3]; triangleMeshNode.v1 = triangles[m * 3 + 1]; triangleMeshNode.v2 = triangles[m * 3 + 2]; if (!Polygon.IsClockwise(vertices[triangleMeshNode.v0], vertices[triangleMeshNode.v1], vertices[triangleMeshNode.v2])) { int v = triangleMeshNode.v0; triangleMeshNode.v0 = triangleMeshNode.v2; triangleMeshNode.v2 = v; } if (Polygon.IsColinear(vertices[triangleMeshNode.v0], vertices[triangleMeshNode.v1], vertices[triangleMeshNode.v2])) { Debug.DrawLine((Vector3)vertices[triangleMeshNode.v0], (Vector3)vertices[triangleMeshNode.v1], Color.red); Debug.DrawLine((Vector3)vertices[triangleMeshNode.v1], (Vector3)vertices[triangleMeshNode.v2], Color.red); Debug.DrawLine((Vector3)vertices[triangleMeshNode.v2], (Vector3)vertices[triangleMeshNode.v0], Color.red); } triangleMeshNode.UpdatePositionFromVertices(); } DictionaryView<VInt2, TriangleMeshNode> dictionaryView = new DictionaryView<VInt2, TriangleMeshNode>(); int n = 0; int num2 = 0; while (n < triangles.Length) { dictionaryView[new VInt2(triangles[n], triangles[n + 1])] = this.nodes[num2]; dictionaryView[new VInt2(triangles[n + 1], triangles[n + 2])] = this.nodes[num2]; dictionaryView[new VInt2(triangles[n + 2], triangles[n])] = this.nodes[num2]; num2++; n += 3; } ListLinqView<MeshNode> listLinqView = new ListLinqView<MeshNode>(); List<uint> list = new List<uint>(); int num3 = 0; int num4 = 0; int num5 = 0; while (num4 < triangles.Length) { listLinqView.Clear(); list.Clear(); TriangleMeshNode triangleMeshNode2 = this.nodes[num5]; for (int num6 = 0; num6 < 3; num6++) { TriangleMeshNode triangleMeshNode3; if (dictionaryView.TryGetValue(new VInt2(triangles[num4 + (num6 + 1) % 3], triangles[num4 + num6]), out triangleMeshNode3)) { listLinqView.Add(triangleMeshNode3); list.Add((uint)(triangleMeshNode2.position - triangleMeshNode3.position).costMagnitude); } } triangleMeshNode2.connections = listLinqView.ToArray(); triangleMeshNode2.connectionCosts = list.ToArray(); num5++; num4 += 3; } if (num3 > 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: " + num3 + "\n"); } NavMeshGraph.RebuildBBTree(this); }
/** 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]; 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 //Debug.Log ("Graph Generation - NavMesh - Time to compute graph "+((Time.realtimeSinceStartup-startTime)*1000F).ToString ("0")+"ms"); }
private 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]; this.nodes = new TriangleMeshNode[0]; } else { vertices = new Int3[vectorVertices.Length]; int index = 0; for (int i = 0; i < vertices.Length; i++) { vertices[i] = (Int3)this.matrix.MultiplyPoint3x4(vectorVertices[i]); } Dictionary <Int3, int> dictionary = new Dictionary <Int3, int>(); int[] numArray = new int[vertices.Length]; for (int j = 0; j < vertices.Length; j++) { if (!dictionary.ContainsKey(vertices[j])) { numArray[index] = j; dictionary.Add(vertices[j], index); index++; } } for (int k = 0; k < triangles.Length; k++) { Int3 num5 = vertices[triangles[k]]; triangles[k] = dictionary[num5]; } Int3[] numArray2 = vertices; vertices = new Int3[index]; originalVertices = new Vector3[index]; for (int m = 0; m < index; m++) { vertices[m] = numArray2[numArray[m]]; originalVertices[m] = vectorVertices[numArray[m]]; } this.nodes = new TriangleMeshNode[triangles.Length / 3]; int graphIndex = base.active.astarData.GetGraphIndex(this); for (int n = 0; n < this.nodes.Length; n++) { this.nodes[n] = new TriangleMeshNode(base.active); TriangleMeshNode node = this.nodes[n]; node.GraphIndex = (uint)graphIndex; node.Penalty = base.initialPenalty; node.Walkable = true; node.v0 = triangles[n * 3]; node.v1 = triangles[(n * 3) + 1]; node.v2 = triangles[(n * 3) + 2]; if (!VectorMath.IsClockwiseXZ(vertices[node.v0], vertices[node.v1], vertices[node.v2])) { int num9 = node.v0; node.v0 = node.v2; node.v2 = num9; } if (VectorMath.IsColinearXZ(vertices[node.v0], vertices[node.v1], vertices[node.v2])) { UnityEngine.Debug.DrawLine((Vector3)vertices[node.v0], (Vector3)vertices[node.v1], Color.red); UnityEngine.Debug.DrawLine((Vector3)vertices[node.v1], (Vector3)vertices[node.v2], Color.red); UnityEngine.Debug.DrawLine((Vector3)vertices[node.v2], (Vector3)vertices[node.v0], Color.red); } node.UpdatePositionFromVertices(); } Dictionary <Int2, TriangleMeshNode> dictionary2 = new Dictionary <Int2, TriangleMeshNode>(); int num10 = 0; int num11 = 0; while (num10 < triangles.Length) { dictionary2[new Int2(triangles[num10], triangles[num10 + 1])] = this.nodes[num11]; dictionary2[new Int2(triangles[num10 + 1], triangles[num10 + 2])] = this.nodes[num11]; dictionary2[new Int2(triangles[num10 + 2], triangles[num10])] = this.nodes[num11]; num11++; num10 += 3; } List <MeshNode> list = new List <MeshNode>(); List <uint> list2 = new List <uint>(); int num12 = 0; int num13 = 0; while (num12 < triangles.Length) { list.Clear(); list2.Clear(); TriangleMeshNode node2 = this.nodes[num13]; for (int num14 = 0; num14 < 3; num14++) { TriangleMeshNode node3; if (dictionary2.TryGetValue(new Int2(triangles[num12 + ((num14 + 1) % 3)], triangles[num12 + num14]), out node3)) { list.Add(node3); Int3 num15 = node2.position - node3.position; list2.Add((uint)num15.costMagnitude); } } node2.connections = list.ToArray(); node2.connectionCosts = list2.ToArray(); num13++; num12 += 3; } RebuildBBTree(this); } }
/** Generates a navmesh. Based on the supplied vertices and triangles */ void GenerateNodes(Vector3[] vectorVertices, int[] triangles, out Vector3[] originalVertices, out Int3[] vertices) { UnityEngine.Profiling.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]; UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.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]]; } UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.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 (!VectorMath.IsClockwiseXZ(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 (VectorMath.IsColinearXZ(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(); } UnityEngine.Profiling.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]; } UnityEngine.Profiling.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(); } UnityEngine.Profiling.Profiler.EndSample(); UnityEngine.Profiling.Profiler.BeginSample("Rebuilding BBTree"); RebuildBBTree(this); UnityEngine.Profiling.Profiler.EndSample(); }
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); } } } }
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); } } } }
private 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]; this.nodes = new TriangleMeshNode[0]; return; } vertices = new Int3[vectorVertices.Length]; int num = 0; for (int i = 0; i < vertices.Length; i++) { vertices[i] = (Int3)this.matrix.MultiplyPoint3x4(vectorVertices[i]); } Dictionary <Int3, int> dictionary = new Dictionary <Int3, int>(); int[] array = new int[vertices.Length]; for (int j = 0; j < vertices.Length; j++) { if (!dictionary.ContainsKey(vertices[j])) { array[num] = j; dictionary.Add(vertices[j], num); num++; } } for (int k = 0; k < triangles.Length; k++) { Int3 key = vertices[triangles[k]]; triangles[k] = dictionary[key]; } Int3[] array2 = vertices; vertices = new Int3[num]; originalVertices = new Vector3[num]; for (int l = 0; l < num; l++) { vertices[l] = array2[array[l]]; originalVertices[l] = vectorVertices[array[l]]; } this.nodes = new TriangleMeshNode[triangles.Length / 3]; int graphIndex = this.active.astarData.GetGraphIndex(this); for (int m = 0; m < this.nodes.Length; m++) { this.nodes[m] = new TriangleMeshNode(this.active); TriangleMeshNode triangleMeshNode = this.nodes[m]; triangleMeshNode.GraphIndex = (uint)graphIndex; triangleMeshNode.Penalty = this.initialPenalty; triangleMeshNode.Walkable = true; triangleMeshNode.v0 = triangles[m * 3]; triangleMeshNode.v1 = triangles[m * 3 + 1]; triangleMeshNode.v2 = triangles[m * 3 + 2]; if (!Polygon.IsClockwise(vertices[triangleMeshNode.v0], vertices[triangleMeshNode.v1], vertices[triangleMeshNode.v2])) { int v = triangleMeshNode.v0; triangleMeshNode.v0 = triangleMeshNode.v2; triangleMeshNode.v2 = v; } if (Polygon.IsColinear(vertices[triangleMeshNode.v0], vertices[triangleMeshNode.v1], vertices[triangleMeshNode.v2])) { Debug.DrawLine((Vector3)vertices[triangleMeshNode.v0], (Vector3)vertices[triangleMeshNode.v1], Color.red); Debug.DrawLine((Vector3)vertices[triangleMeshNode.v1], (Vector3)vertices[triangleMeshNode.v2], Color.red); Debug.DrawLine((Vector3)vertices[triangleMeshNode.v2], (Vector3)vertices[triangleMeshNode.v0], Color.red); } triangleMeshNode.UpdatePositionFromVertices(); } Dictionary <Int2, TriangleMeshNode> dictionary2 = new Dictionary <Int2, TriangleMeshNode>(); int n = 0; int num2 = 0; while (n < triangles.Length) { dictionary2[new Int2(triangles[n], triangles[n + 1])] = this.nodes[num2]; dictionary2[new Int2(triangles[n + 1], triangles[n + 2])] = this.nodes[num2]; dictionary2[new Int2(triangles[n + 2], triangles[n])] = this.nodes[num2]; num2++; n += 3; } List <MeshNode> list = new List <MeshNode>(); List <uint> list2 = new List <uint>(); int num3 = 0; int num4 = 0; while (num3 < triangles.Length) { list.Clear(); list2.Clear(); TriangleMeshNode triangleMeshNode2 = this.nodes[num4]; for (int num5 = 0; num5 < 3; num5++) { TriangleMeshNode triangleMeshNode3; if (dictionary2.TryGetValue(new Int2(triangles[num3 + (num5 + 1) % 3], triangles[num3 + num5]), out triangleMeshNode3)) { list.Add(triangleMeshNode3); list2.Add((uint)(triangleMeshNode2.position - triangleMeshNode3.position).costMagnitude); } } triangleMeshNode2.connections = list.ToArray(); triangleMeshNode2.connectionCosts = list2.ToArray(); num4++; num3 += 3; } NavMeshGraph.RebuildBBTree(this); }
/** 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); //Debug.Log ("Graph Generation - NavMesh - Time to compute graph "+((Time.realtimeSinceStartup-startTime)*1000F).ToString ("0")+"ms"); }
private void GenerateNodes(Vector3[] vectorVertices, int[] triangles, out Vector3[] originalVertices, out VInt3[] vertices) { if ((vectorVertices.Length == 0) || (triangles.Length == 0)) { originalVertices = vectorVertices; vertices = new VInt3[0]; this.nodes = new TriangleMeshNode[0]; } else { vertices = new VInt3[vectorVertices.Length]; int index = 0; for (int i = 0; i < vertices.Length; i++) { vertices[i] = (VInt3)this.matrix.MultiplyPoint3x4(vectorVertices[i]); } Dictionary <VInt3, int> dictionary = new Dictionary <VInt3, int>(); int[] numArray = new int[vertices.Length]; for (int j = 0; j < vertices.Length; j++) { if (!dictionary.ContainsKey(vertices[j])) { numArray[index] = j; dictionary.Add(vertices[j], index); index++; } } for (int k = 0; k < triangles.Length; k++) { VInt3 num5 = vertices[triangles[k]]; triangles[k] = dictionary[num5]; } VInt3[] numArray2 = vertices; vertices = new VInt3[index]; originalVertices = new Vector3[index]; for (int m = 0; m < index; m++) { vertices[m] = numArray2[numArray[m]]; originalVertices[m] = vectorVertices[numArray[m]]; } this.nodes = new TriangleMeshNode[triangles.Length / 3]; int graphIndex = base.active.astarData.GetGraphIndex(this); for (int n = 0; n < this.nodes.Length; n++) { this.nodes[n] = new TriangleMeshNode(base.active); TriangleMeshNode node = this.nodes[n]; node.GraphIndex = (uint)graphIndex; node.Penalty = base.initialPenalty; node.Walkable = true; node.v0 = triangles[n * 3]; node.v1 = triangles[(n * 3) + 1]; node.v2 = triangles[(n * 3) + 2]; if (!Polygon.IsClockwise(vertices[node.v0], vertices[node.v1], vertices[node.v2])) { int num9 = node.v0; node.v0 = node.v2; node.v2 = num9; } 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); } node.UpdatePositionFromVertices(); } DictionaryView <VInt2, TriangleMeshNode> view = new DictionaryView <VInt2, TriangleMeshNode>(); int num10 = 0; int num11 = 0; while (num10 < triangles.Length) { view[new VInt2(triangles[num10], triangles[num10 + 1])] = this.nodes[num11]; view[new VInt2(triangles[num10 + 1], triangles[num10 + 2])] = this.nodes[num11]; view[new VInt2(triangles[num10 + 2], triangles[num10])] = this.nodes[num11]; num11++; num10 += 3; } ListLinqView <MeshNode> view2 = new ListLinqView <MeshNode>(); List <uint> list = new List <uint>(); int num12 = 0; int num13 = 0; int num14 = 0; while (num13 < triangles.Length) { view2.Clear(); list.Clear(); TriangleMeshNode node2 = this.nodes[num14]; for (int num15 = 0; num15 < 3; num15++) { TriangleMeshNode node3; if (view.TryGetValue(new VInt2(triangles[num13 + ((num15 + 1) % 3)], triangles[num13 + num15]), out node3)) { view2.Add(node3); VInt3 num16 = node2.position - node3.position; list.Add((uint)num16.costMagnitude); } } node2.connections = view2.ToArray(); node2.connectionCosts = list.ToArray(); num14++; num13 += 3; } if (num12 > 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: " + num12 + "\n"); } RebuildBBTree(this); } }
protected NavmeshTile CreateTile(int[] tris, Int3[] verts, int x, int z) { #if BNICKSON_UPDATED if (tris == null) { throw new System.ArgumentNullException("The mesh must be valid. tris is null."); } if (verts == null) { throw new System.ArgumentNullException("The mesh must be valid. verts is null."); } //Create a new navmesh tile and assign its settings var tile = new NavmeshTile(); tile.x = x; tile.z = z; tile.w = 1; tile.d = 1; tile.tris = tris; tile.verts = verts; tile.bbTree = new BBTree(); #endif 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(); var 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]]; } var compressed = new Int3[count]; for (int i = 0; i < count; i++) { compressed[i] = tile.verts[i]; } tile.verts = compressed; var 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++) { var 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 occur, 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 (!VectorMath.IsClockwiseXZ(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); }
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; } }
/** 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; }
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; }
/** 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"); }
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; }