protected NavmeshTile BuildTileMesh(Voxelize vox, int x, int z, int threadIndex = 0) { vox.borderSize = this.TileBorderSizeInVoxels; vox.forcedBounds = this.CalculateTileBoundsWithBorder(x, z); vox.width = this.tileSizeX + vox.borderSize * 2; vox.depth = this.tileSizeZ + vox.borderSize * 2; if (!this.useTiles && this.relevantGraphSurfaceMode == RecastGraph.RelevantGraphSurfaceMode.OnlyForCompletelyInsideTile) { vox.relevantGraphSurfaceMode = RecastGraph.RelevantGraphSurfaceMode.RequireForAll; } else { vox.relevantGraphSurfaceMode = this.relevantGraphSurfaceMode; } vox.minRegionSize = Mathf.RoundToInt(this.minRegionSize / (this.cellSize * this.cellSize)); vox.Init(); vox.VoxelizeInput(this.transform, this.CalculateTileBoundsWithBorder(x, z)); vox.FilterLedges(vox.voxelWalkableHeight, vox.voxelWalkableClimb, vox.cellSize, vox.cellHeight); vox.FilterLowHeightSpans(vox.voxelWalkableHeight, vox.cellSize, vox.cellHeight); vox.BuildCompactField(); vox.BuildVoxelConnections(); vox.ErodeWalkableArea(this.CharacterRadiusInVoxels); vox.BuildDistanceField(); vox.BuildRegions(); VoxelContourSet cset = new VoxelContourSet(); vox.BuildContours(this.contourMaxError, 1, cset, 5); VoxelMesh mesh; vox.BuildPolyMesh(cset, 3, out mesh); for (int i = 0; i < mesh.verts.Length; i++) { mesh.verts[i] *= 1000; } vox.transformVoxel2Graph.Transform(mesh.verts); return(this.CreateTile(vox, mesh, x, z, threadIndex)); }
protected NavmeshTile BuildTileMesh(Voxelize vox, int x, int z, int threadIndex = 0) { AstarProfiler.StartProfile("Build Tile"); AstarProfiler.StartProfile("Init"); vox.borderSize = TileBorderSizeInVoxels; vox.forcedBounds = CalculateTileBoundsWithBorder(x, z); vox.width = tileSizeX + vox.borderSize * 2; vox.depth = tileSizeZ + vox.borderSize * 2; if (!useTiles && relevantGraphSurfaceMode == RelevantGraphSurfaceMode.OnlyForCompletelyInsideTile) { // This best reflects what the user would actually want vox.relevantGraphSurfaceMode = RelevantGraphSurfaceMode.RequireForAll; } else { vox.relevantGraphSurfaceMode = relevantGraphSurfaceMode; } vox.minRegionSize = Mathf.RoundToInt(minRegionSize / (cellSize * cellSize)); AstarProfiler.EndProfile("Init"); // Init voxelizer vox.Init(); vox.VoxelizeInput(transform, CalculateTileBoundsWithBorder(x, z)); AstarProfiler.StartProfile("Filter Ledges"); vox.FilterLedges(vox.voxelWalkableHeight, vox.voxelWalkableClimb, vox.cellSize, vox.cellHeight); AstarProfiler.EndProfile("Filter Ledges"); AstarProfiler.StartProfile("Filter Low Height Spans"); vox.FilterLowHeightSpans(vox.voxelWalkableHeight, vox.cellSize, vox.cellHeight); AstarProfiler.EndProfile("Filter Low Height Spans"); vox.BuildCompactField(); vox.BuildVoxelConnections(); vox.ErodeWalkableArea(CharacterRadiusInVoxels); vox.BuildDistanceField(); vox.BuildRegions(); var cset = new VoxelContourSet(); vox.BuildContours(contourMaxError, 1, cset, Voxelize.RC_CONTOUR_TESS_WALL_EDGES | Voxelize.RC_CONTOUR_TESS_TILE_EDGES); VoxelMesh mesh; vox.BuildPolyMesh(cset, 3, out mesh); AstarProfiler.StartProfile("Build Nodes"); // Position the vertices correctly in graph space (all tiles are laid out on the xz plane with the (0,0) tile at the origin) for (int i = 0; i < mesh.verts.Length; i++) { mesh.verts[i] *= Int3.Precision; } vox.transformVoxel2Graph.Transform(mesh.verts); NavmeshTile tile = CreateTile(vox, mesh, x, z, threadIndex); AstarProfiler.EndProfile("Build Nodes"); AstarProfiler.EndProfile("Build Tile"); return(tile); }
//Nvp = Maximum allowed vertices per polygon public void BuildPolyMesh (VoxelContourSet cset, int nvp, out VoxelMesh mesh) { nvp = 3; int maxVertices = 0; int maxTris = 0; int maxVertsPerCont = 0; for (int i = 0; i < cset.conts.Length; i++) { // Skip null contours. if (cset.conts[i].nverts < 3) continue; maxVertices += cset.conts[i].nverts; maxTris += cset.conts[i].nverts - 2; maxVertsPerCont = Mathfx.Max (maxVertsPerCont, cset.conts[i].nverts); } if (maxVertices >= 65534) { Debug.LogWarning ("To many vertices for unity to render - Unity might screw up rendering, but hopefully the navmesh will work ok"); //mesh = new VoxelMesh (); //yield break; //return; } //int[] vflags = new int[maxVertices]; Int3[] verts = new Int3[maxVertices]; int[] polys = new int[maxTris*nvp];//@Why *2*2 //int[] regs = new int[maxTris]; //int[] areas = new int[maxTris]; #if ASTAR_MEMCPY Pathfinding.Util.Memory.MemSet<int> (polys, 0xff, sizeof(int)); #else for (int i=0;i<polys.Length;i++) { polys[i] = 0xff; } #endif //int[] nexVert = new int[maxVertices]; //int[] firstVert = new int[VERTEX_BUCKET_COUNT]; int[] indices = new int[maxVertsPerCont]; int[] tris = new int[maxVertsPerCont*3]; //ushort[] polys int vertexIndex = 0; int polyIndex = 0; for (int i=0;i<cset.conts.Length;i++) { VoxelContour cont = cset.conts[i]; //Skip null contours if (cont.nverts < 3) { continue; } for (int j=0; j < cont.nverts;j++) { indices[j] = j; cont.verts[j*4+2] /= voxelArea.width; } //yield return (GameObject.FindObjectOfType (typeof(MonoBehaviour)) as MonoBehaviour).StartCoroutine ( //Triangulate (cont.nverts, cont.verts, indices, tris); int ntris = Triangulate (cont.nverts, cont.verts, ref indices, ref tris); /*if (ntris > cont.nverts-2) { Debug.LogError (ntris + " "+cont.nverts+" "+cont.verts.Length+" "+(cont.nverts-2)); } if (ntris > maxVertsPerCont) { Debug.LogError (ntris*3 + " "+maxVertsPerCont); } int tmp = polyIndex; Debug.Log (maxTris + " "+polyIndex+" "+polys.Length+" "+ntris+" "+(ntris*3) + " " + cont.nverts);*/ int startIndex = vertexIndex; for (int j=0;j<ntris*3; polyIndex++, j++) { //@Error sometimes polys[polyIndex] = tris[j]+startIndex; } /*int tmp2 = polyIndex; if (tmp+ntris*3 != tmp2) { Debug.LogWarning (tmp+" "+(tmp+ntris*3)+" "+tmp2+" "+ntris*3); }*/ for (int j=0;j<cont.nverts; vertexIndex++, j++) { verts[vertexIndex] = new Int3(cont.verts[j*4],cont.verts[j*4+1],cont.verts[j*4+2]); } } mesh = new VoxelMesh (); //yield break; Int3[] trimmedVerts = new Int3[vertexIndex]; for (int i=0;i<vertexIndex;i++) { trimmedVerts[i] = verts[i]; } int[] trimmedTris = new int[polyIndex]; #if ASTAR_MEMCPY System.Buffer.BlockCopy (polys, 0, trimmedTris, 0, polyIndex*sizeof(int)); #else for (int i=0;i<polyIndex;i++) { trimmedTris[i] = polys[i]; } #endif mesh.verts = trimmedVerts; mesh.tris = trimmedTris; /*for (int i=0;i<mesh.tris.Length/3;i++) { int p = i*3; int p1 = mesh.tris[p]; int p2 = mesh.tris[p+1]; int p3 = mesh.tris[p+2]; //Debug.DrawLine (ConvertPosCorrZ (mesh.verts[p1].x,mesh.verts[p1].y,mesh.verts[p1].z),ConvertPosCorrZ (mesh.verts[p2].x,mesh.verts[p2].y,mesh.verts[p2].z),Color.yellow); //Debug.DrawLine (ConvertPosCorrZ (mesh.verts[p1].x,mesh.verts[p1].y,mesh.verts[p1].z),ConvertPosCorrZ (mesh.verts[p3].x,mesh.verts[p3].y,mesh.verts[p3].z),Color.yellow); //Debug.DrawLine (ConvertPosCorrZ (mesh.verts[p3].x,mesh.verts[p3].y,mesh.verts[p3].z),ConvertPosCorrZ (mesh.verts[p2].x,mesh.verts[p2].y,mesh.verts[p2].z),Color.yellow); //Debug.DrawLine (ConvertPosCorrZ (verts[p1],0,verts[p1+2]),ConvertPosCorrZ (verts[p2],0,verts[p2+2]),Color.blue); //Debug.DrawLine (ConvertPosCorrZ (verts[p1],0,verts[p1+2]),ConvertPosCorrZ (verts[p3],0,verts[p3+2]),Color.blue); //Debug.DrawLine (ConvertPosCorrZ (verts[p2],0,verts[p2+2]),ConvertPosCorrZ (verts[p3],0,verts[p3+2]),Color.blue); }*/ }
public void BuildContours (float maxError, int maxEdgeLength, VoxelContourSet cset, int buildFlags) { int w = voxelArea.width; int d = voxelArea.depth; int wd = w*d; //cset.bounds = voxelArea.bounds; int maxContours = Mathf.Max (8/*Max Regions*/,8); //cset.conts = new VoxelContour[maxContours]; List<VoxelContour> contours = new List<VoxelContour>(maxContours); //cset.nconts = 0; int[] flags = new int[voxelArea.compactSpans.Length]; // Mark boundaries. (@?) for (int z=0;z < wd;z += voxelArea.width) { for (int x=0;x < voxelArea.width;x++) { CompactVoxelCell c = voxelArea.compactCells[x+z]; for (int i= (int)c.index, ci = (int)(c.index+c.count); i < ci; i++) { int res = 0; CompactVoxelSpan s = voxelArea.compactSpans[i]; if (s.reg == 0 || (s.reg & BorderReg) == BorderReg) { flags[i] = 0; continue; } for (int dir=0;dir < 4; dir++) { int r = 0; if (s.GetConnection (dir) != NotConnected) { int nx = x + voxelArea.DirectionX[dir]; int nz = z + voxelArea.DirectionZ[dir]; int ni = (int)voxelArea.compactCells[nx+nz].index + s.GetConnection (dir); r = voxelArea.compactSpans[ni].reg; } //@TODO - Why isn't this inside the previous IF if (r == s.reg) { res |= (1 << dir); } } //Inverse, mark non connected edges. flags[i] = res ^ 0xf; } } } List<int> verts = new List<int> (256); List<int> simplified = new List<int> (64); for (int z=0;z < wd;z += voxelArea.width) { for (int x=0;x < voxelArea.width;x++) { CompactVoxelCell c = voxelArea.compactCells[x+z]; for (int i= (int)c.index, ci = (int)(c.index+c.count); i < ci; i++) { //CompactVoxelSpan s = voxelArea.compactSpans[i]; if (flags[i] == 0 || flags[i] == 0xf) { flags[i] = 0; continue; } int reg = voxelArea.compactSpans[i].reg; if (reg == 0 || (reg & BorderReg) == BorderReg) { continue; } int area = voxelArea.areaTypes[i]; verts.Clear (); simplified.Clear (); WalkContour(x, z, i, flags, verts); SimplifyContour(verts, simplified, maxError, maxEdgeLength, buildFlags); RemoveDegenerateSegments (simplified); VoxelContour contour = new VoxelContour (); contour.verts = simplified.ToArray (); contour.rverts = verts.ToArray (); contour.nverts = simplified.Count/4; contour.reg = reg; contour.area = area; contours.Add (contour); #if ASTARDEBUG for (int q=0, j = (simplified.Count/4)-1;q<(simplified.Count/4);j=q, q++) { int i4 = q*4; int j4 = j*4; Vector3 p1 = Vector3.Scale ( new Vector3 ( simplified[i4+0], simplified[i4+1], (simplified[i4+2]/(float)voxelArea.width) ), CellScale) +voxelOffset; Vector3 p2 = Vector3.Scale ( new Vector3 ( simplified[j4+0], simplified[j4+1], (simplified[j4+2]/(float)voxelArea.width) ) ,CellScale) +voxelOffset; if (CalcAreaOfPolygon2D(contour.verts, contour.nverts) > 0) { Debug.DrawLine (p1,p2,Mathfx.IntToColor (reg,0.5F)); } else { Debug.DrawLine (p1,p2,Color.red); } } #endif } } } // Check and merge droppings. // Sometimes the previous algorithms can fail and create several contours // per area. This pass will try to merge the holes into the main region. for (int i = 0; i < contours.Count; i++) { VoxelContour cont = contours[i]; // Check if the contour is would backwards. if (CalcAreaOfPolygon2D(cont.verts, cont.nverts) < 0) { // Find another contour which has the same region ID. int mergeIdx = -1; for (int j = 0; j < contours.Count; j++) { if (i == j) continue; if (contours[j].nverts > 0 && contours[j].reg == cont.reg) { // Make sure the polygon is correctly oriented. if (CalcAreaOfPolygon2D(contours[j].verts, contours[j].nverts) > 0) { mergeIdx = j; break; } } } if (mergeIdx == -1) { Debug.LogError ("rcBuildContours: Could not find merge target for bad contour "+i+"."); } else { Debug.LogWarning ("Fixing contour"); VoxelContour mcont = contours[mergeIdx]; // Merge by closest points. int ia = 0, ib = 0; GetClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ref ia, ref ib); if (ia == -1 || ib == -1) { Debug.LogWarning ("rcBuildContours: Failed to find merge points for "+i+" and "+mergeIdx+"."); continue; } int p4 = ia*4; int p42 = ib*4; Vector3 p12 = Vector3.Scale ( new Vector3 ( mcont.verts[p4+0], mcont.verts[p4+1], (mcont.verts[p4+2]/(float)voxelArea.width) ), CellScale) +voxelOffset; Vector3 p22 = Vector3.Scale ( new Vector3 ( cont.verts[p42+0], cont.verts[p42+1], (cont.verts[p42+2]/(float)voxelArea.width) ) ,CellScale) +voxelOffset; Debug.DrawLine (p12,p22,Color.green); if (!MergeContours(ref mcont, ref cont, ia, ib)) { Debug.LogWarning ("rcBuildContours: Failed to merge contours "+i+" and "+mergeIdx+"."); continue; } contours[mergeIdx] = mcont; contours[i] = cont; #if ASTARDEBUG Debug.Log (mcont.nverts); for (int q=0, j = (mcont.nverts)-1;q<(mcont.nverts);j=q, q++) { int i4 = q*4; int j4 = j*4; Vector3 p1 = Vector3.Scale ( new Vector3 ( mcont.verts[i4+0], mcont.verts[i4+1], (mcont.verts[i4+2]/(float)voxelArea.width) ), CellScale) +voxelOffset; Vector3 p2 = Vector3.Scale ( new Vector3 ( mcont.verts[j4+0], mcont.verts[j4+1], (mcont.verts[j4+2]/(float)voxelArea.width) ) ,CellScale) +voxelOffset; Debug.DrawLine (p1,p2,Color.red); //} } #endif } } } cset.conts = contours.ToArray (); }
public override void Scan () { AstarProfiler.Reset (); //AstarProfiler.StartProfile ("Base Scan"); //base.Scan (); //AstarProfiler.EndProfile ("Base Scan"); if (useCRecast) { ScanCRecast (); } else { #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Collecting Meshes"); #endif AstarProfiler.StartProfile ("Collecting Meshes"); AstarProfiler.StartProfile ("Collecting Meshes"); MeshFilter[] filters; ExtraMesh[] extraMeshes; if (!CollectMeshes (out filters, out extraMeshes)) { nodes = new Node[0]; return; } AstarProfiler.EndProfile ("Collecting Meshes"); #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Creating Voxel Base"); #endif Voxelize vox = new Voxelize (cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope); vox.maxEdgeLength = maxEdgeLength; vox.forcedBounds = forcedBounds; vox.includeOutOfBounds = includeOutOfBounds; #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Voxelizing"); #endif AstarProfiler.EndProfile ("Collecting Meshes"); //g.GetComponent<Voxelize>(); vox.VoxelizeMesh (filters, extraMeshes); /*bool[,] open = new bool[width,depth]; int[,] visited = new int[width+1,depth+1]; for (int z=0;z<depth;z++) { for (int x = 0;x < width;x++) { open[x,z] = graphNodes[z*width+x].walkable; } }*/ /*for (int i=0;i<depth*width;i++) { open[i] = graphNodes[i].walkable; } int wd = width*depth; List<int> boundary = new List<int>(); int p = 0; for (int i=0;i<wd;i++) { if (!open[i]) { boundary.Add (i); p = i; int backtrack = i-1; }*/ #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Eroding"); #endif vox.ErodeWalkableArea (Mathf.CeilToInt (2*characterRadius/cellSize)); #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Building Distance Field"); #endif vox.BuildDistanceField (); #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Building Regions"); #endif vox.BuildRegions (); #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Building Contours"); #endif VoxelContourSet cset = new VoxelContourSet (); vox.BuildContours (contourMaxError,1,cset,Voxelize.RC_CONTOUR_TESS_WALL_EDGES); #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Building Poly Mesh"); #endif VoxelMesh mesh; vox.BuildPolyMesh (cset,3,out mesh); #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Building Nodes"); #endif Vector3[] vertices = new Vector3[mesh.verts.Length]; AstarProfiler.StartProfile ("Build Nodes"); for (int i=0;i<vertices.Length;i++) { vertices[i] = (Vector3)mesh.verts[i]; } matrix = Matrix4x4.TRS (vox.voxelOffset,Quaternion.identity,Int3.Precision*Voxelize.CellScale); //Int3.Precision*Voxelize.CellScale+(Int3)vox.voxelOffset //GenerateNodes (this,vectorVertices,triangles, out originalVertices, out _vertices); #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Generating Nodes"); #endif NavMeshGraph.GenerateNodes (this,vertices,mesh.tris, out _vectorVertices, out _vertices); AstarProfiler.EndProfile ("Build Nodes"); AstarProfiler.PrintResults (); #if ASTARDEBUG Console.WriteLine ("Recast Graph -- Done"); #endif } }
public override void Scan() { AstarProfiler.Reset(); //AstarProfiler.StartProfile ("Base Scan"); //base.Scan (); //AstarProfiler.EndProfile ("Base Scan"); if (useCRecast) { ScanCRecast(); } else { MeshFilter[] filters; ExtraMesh[] extraMeshes; if (!CollectMeshes(out filters, out extraMeshes)) { nodes = new Node[0]; return; } Voxelize vox = new Voxelize(cellHeight, cellSize, walkableClimb, walkableHeight, maxSlope); vox.maxEdgeLength = maxEdgeLength; vox.forcedBounds = forcedBounds; vox.includeOutOfBounds = includeOutOfBounds; //g.GetComponent<Voxelize>(); vox.VoxelizeMesh(filters, extraMeshes); /*bool[,] open = new bool[width,depth]; * int[,] visited = new int[width+1,depth+1]; * * for (int z=0;z<depth;z++) { * for (int x = 0;x < width;x++) { * open[x,z] = graphNodes[z*width+x].walkable; * } * }*/ /*for (int i=0;i<depth*width;i++) { * open[i] = graphNodes[i].walkable; * } * * * int wd = width*depth; * * List<int> boundary = new List<int>(); * * int p = 0; * * for (int i=0;i<wd;i++) { * if (!open[i]) { * boundary.Add (i); * * p = i; * * int backtrack = i-1; * * * }*/ vox.ErodeWalkableArea(Mathf.CeilToInt(2 * characterRadius / cellSize)); vox.BuildDistanceField(); vox.BuildRegions(); VoxelContourSet cset = new VoxelContourSet(); vox.BuildContours(contourMaxError, 1, cset, Voxelize.RC_CONTOUR_TESS_WALL_EDGES); VoxelMesh mesh; vox.BuildPolyMesh(cset, 3, out mesh); Vector3[] vertices = new Vector3[mesh.verts.Length]; AstarProfiler.StartProfile("Build Nodes"); for (int i = 0; i < vertices.Length; i++) { vertices[i] = (Vector3)mesh.verts[i]; } matrix = Matrix4x4.TRS(vox.voxelOffset, Quaternion.identity, Int3.Precision * Voxelize.CellScale); //Int3.Precision*Voxelize.CellScale+(Int3)vox.voxelOffset //GenerateNodes (this,vectorVertices,triangles, out originalVertices, out _vertices); NavMeshGraph.GenerateNodes(this, vertices, mesh.tris, out _vectorVertices, out _vertices); AstarProfiler.EndProfile("Build Nodes"); AstarProfiler.PrintResults(); } }