/** Generates a navmesh. Based on the supplied vertices and triangles. Memory usage is about O(n) */ public static void GenerateNodes (NavGraph graph, Vector3[] vectorVertices, int[] triangles, out Vector3[] originalVertices, out Int3[] vertices) { if (!(graph is INavmesh)) { Debug.LogError ("The specified graph does not implement interface 'INavmesh'"); originalVertices = vectorVertices; vertices = new Int3[0]; graph.nodes = graph.CreateNodes (0); return; } if (vectorVertices.Length == 0 || triangles.Length == 0) { originalVertices = vectorVertices; vertices = new Int3[0]; graph.nodes = graph.CreateNodes (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)graph.matrix.MultiplyPoint (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] = vertices[i];//vectorVertices[newVertices[i]]; } Node[] nodes = graph.CreateNodes (triangles.Length/3);//new Node[triangles.Length/3]; graph.nodes = nodes; for (int i=0;i<nodes.Length;i++) { MeshNode node = (MeshNode)nodes[i];//new MeshNode (); node.walkable = true; node.position = (vertices[triangles[i*3]] + vertices[triangles[i*3+1]] + vertices[triangles[i*3+2]])/3F; node.v1 = triangles[i*3]; node.v2 = triangles[i*3+1]; node.v3 = triangles[i*3+2]; if (!Polygon.IsClockwise (vertices[node.v1],vertices[node.v2],vertices[node.v3])) { //Debug.DrawLine (vertices[node.v1],vertices[node.v2],Color.red); //Debug.DrawLine (vertices[node.v2],vertices[node.v3],Color.red); //Debug.DrawLine (vertices[node.v3],vertices[node.v1],Color.red); int tmp = node.v1; node.v1 = node.v3; node.v3 = tmp; } if (Polygon.IsColinear (vertices[node.v1],vertices[node.v2],vertices[node.v3])) { Debug.DrawLine (vertices[node.v1],vertices[node.v2],Color.red); Debug.DrawLine (vertices[node.v2],vertices[node.v3],Color.red); Debug.DrawLine (vertices[node.v3],vertices[node.v1],Color.red); } nodes[i] = node; } List<Node> connections = new List<Node> (); List<int> connectionCosts = new List<int> (); 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]); Node 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 (vertices[triangles[x]],vertices[triangles[x+1]],Color.red); Debug.DrawLine (vertices[triangles[x]],vertices[triangles[x+2]],Color.red); Debug.DrawLine (vertices[triangles[x+2]],vertices[triangles[x+1]],Color.red); } if (count == 2) { Node other = nodes[x/3]; connections.Add (other); connectionCosts.Add (Mathf.RoundToInt ((node.position-other.position).magnitude)); } } 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 (graph); //Debug.Log ("Graph Generation - NavMesh - Time to compute graph "+((Time.realtimeSinceStartup-startTime)*1000F).ToString ("0")+"ms"); }
/** Generates a navmesh. Based on the supplied vertices and triangles. Memory usage is about O(n) */ public static void GenerateNodes(NavGraph graph, Vector3[] vectorVertices, int[] triangles, out Vector3[] originalVertices, out Int3[] vertices) { if (!(graph is INavmesh)) { Debug.LogError("The specified graph does not implement interface 'INavmesh'"); originalVertices = vectorVertices; vertices = new Int3[0]; graph.nodes = graph.CreateNodes(0); return; } if (vectorVertices.Length == 0 || triangles.Length == 0) { originalVertices = vectorVertices; vertices = new Int3[0]; graph.nodes = graph.CreateNodes(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)graph.matrix.MultiplyPoint(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++) { originalVertices[i] = vectorVertices[newVertices[i]]; vertices[i] = totalIntVertices[newVertices[i]]; //(Int3)graph.matrix.MultiplyPoint (vectorVertices[i]); } Node[] nodes = graph.CreateNodes(triangles.Length / 3); //new Node[triangles.Length/3]; graph.nodes = nodes; for (int i = 0; i < nodes.Length; i++) { MeshNode node = (MeshNode)nodes[i]; //new MeshNode (); node.walkable = true; node.position = (vertices[triangles[i * 3]] + vertices[triangles[i * 3 + 1]] + vertices[triangles[i * 3 + 2]]) / 3F; node.v1 = triangles[i * 3]; node.v2 = triangles[i * 3 + 1]; node.v3 = triangles[i * 3 + 2]; if (!Polygon.IsClockwise(vertices[node.v1], vertices[node.v2], vertices[node.v3])) { //Debug.DrawLine (vertices[node.v1],vertices[node.v2],Color.red); //Debug.DrawLine (vertices[node.v2],vertices[node.v3],Color.red); //Debug.DrawLine (vertices[node.v3],vertices[node.v1],Color.red); int tmp = node.v1; node.v1 = node.v3; node.v3 = tmp; } if (Polygon.IsColinear(vertices[node.v1], vertices[node.v2], vertices[node.v3])) { Debug.DrawLine(vertices[node.v1], vertices[node.v2], Color.red); Debug.DrawLine(vertices[node.v2], vertices[node.v3], Color.red); Debug.DrawLine(vertices[node.v3], vertices[node.v1], Color.red); } nodes[i] = node; } List <Node> connections = new List <Node> (); List <int> connectionCosts = new List <int> (); 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]); Node 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(vertices[triangles[x]], vertices[triangles[x + 1]], Color.red); Debug.DrawLine(vertices[triangles[x]], vertices[triangles[x + 2]], Color.red); Debug.DrawLine(vertices[triangles[x + 2]], vertices[triangles[x + 1]], Color.red); } if (count == 2) { Node other = nodes[x / 3]; connections.Add(other); connectionCosts.Add(Mathf.RoundToInt((node.position - other.position).magnitude)); } } 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(graph); //Debug.Log ("Graph Generation - NavMesh - Time to compute graph "+((Time.realtimeSinceStartup-startTime)*1000F).ToString ("0")+"ms"); }