/// <summary> /// Constructor /// </summary> /// <remarks> /// <para> /// A 'no result' object will be created if the <paramref name="polyMesh"/> parameter /// is null or has a polygon count of zero. /// </para> /// </remarks> /// <param name="tx">The x-index of the tile within the tile grid. (tx, tz)</param> /// <param name="tz">The z-index of the tile within the tile grid. (tx, tz)</param> /// <param name="polyMesh">The polymesh.</param> /// <param name="detailMesh">The detail mesh.</param> /// <param name="heightfield">The heightfield.</param> /// <param name="compactField">The compact field.</param> /// <param name="contours">The contour set.</param> public NMGenAssets(int tx, int tz , PolyMesh polyMesh , PolyMeshDetail detailMesh , Heightfield heightfield , CompactHeightfield compactField , ContourSet contours) { mTileX = tx; mTileZ = tz; if (polyMesh == null || polyMesh.PolyCount == 0) { mPolyMesh = null; mDetailMesh = null; mHeightfield = null; mCompactField = null; mContours = null; } else { mPolyMesh = polyMesh; mDetailMesh = detailMesh; // OK to be null. mHeightfield = heightfield; mCompactField = compactField; mContours = contours; } }
/// <summary> /// Generates a <see cref="NavMesh"/> given a collection of triangles and some settings. /// </summary> /// <param name="triangles">The triangles that form the level.</param> /// <param name="settings">The settings to generate with.</param> /// <returns>A <see cref="NavMesh"/>.</returns> public static NavMesh Generate(IEnumerable <Triangle3> triangles, NavMeshGenerationSettings settings) { BBox3 bounds = triangles.GetBoundingBox(settings.CellSize); var hf = new Heightfield(bounds, settings); hf.RasterizeTriangles(triangles); hf.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); hf.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); hf.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); var chf = new CompactHeightfield(hf, settings); chf.Erode(settings.VoxelAgentRadius); chf.BuildDistanceField(); chf.BuildRegions(2, settings.MinRegionSize, settings.MergedRegionSize); var cont = chf.BuildContourSet(settings); var polyMesh = new PolyMesh(cont, settings); var polyMeshDetail = new PolyMeshDetail(polyMesh, chf, settings); var buildData = new NavMeshBuilder(polyMesh, polyMeshDetail, new Pathfinding.OffMeshConnection[0], settings); var navMesh = new NavMesh(buildData); return(navMesh); }
public NavMeshBuilder GenerateNavmesh(BBox3 bbox) { float[] vertices; int[] indices; AreaId[] areas; GetRawData(out vertices, out indices, out areas); var settings = WoWSettings; var hf = new Heightfield(bbox, settings); hf.RasterizeTrianglesWithAreas(vertices, areas); hf.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); hf.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); hf.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); var chf = new CompactHeightfield(hf, settings); chf.Erode(settings.VoxelAgentWidth); chf.BuildDistanceField(); chf.BuildRegions((int)(settings.AgentWidth / settings.CellSize) + 8, settings.MinRegionSize, settings.MergedRegionSize); var cset = new ContourSet(chf, settings); var pmesh = new PolyMesh(cset, settings); var dmesh = new PolyMeshDetail(pmesh, chf, settings); var buildData = new NavMeshBuilder(pmesh, dmesh, new SharpNav.Pathfinding.OffMeshConnection[0], settings); return(buildData); }
public static extern bool rcpdFlattenMesh([In] PolyMeshDetail detailMesh , [In, Out] Vector3[] verts , ref int vertCount , int vertsSize , [In, Out] int[] tris , ref int triCount , int trisSize);
/// <summary> /// Sets the context as having produced no result. /// </summary> public void SetAsNoResult() { mHeightfield = null; mCompactField = null; mContours = null; mPolyMesh = null; mDetailMesh = null; mNoResult = true; }
internal void SetWorkingData(int x, int z, PolyMesh polyMesh, PolyMeshDetail detailMesh) { int i = GetIndex(x, z); if (i == IndexError) { return; } unsafeItems[i].SetWorkingData(polyMesh, detailMesh); mIsDirty = true; unsafeVersion++; }
public NavMeshDataResult CreateNavMeshData(RcConfig config, PolyMeshDetail polyMeshDetail, PolyMesh polyMesh, InputGeom geom, int tx, int ty, float agentHeight, float agentRadius, float agentMaxClimb) { return(RecastLibrary.navmesh_data_create( _context.DangerousGetHandle(), ref config, polyMeshDetail.DangerousGetHandle(), polyMesh.DangerousGetHandle(), geom.DangerousGetHandle(), tx, ty, agentHeight, agentRadius, agentMaxClimb)); }
//private void GenerateNavMesh() //{ // Console.WriteLine("Generating NavMesh"); // long prevMs = 0; // try // { // var levelTris = level.GetTriangles(); // var triEnumerable = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length); // BBox3 bounds = triEnumerable.GetBoundingBox(); // settings = NavMeshGenerationSettings.Default; // heightfield = new Heightfield(bounds, settings); // heightfield.RasterizeTriangles(levelTris, Area.Default); // heightfield.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); // heightfield.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); // heightfield.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); // compactHeightfield = new CompactHeightfield(heightfield, settings); // compactHeightfield.Erode(settings.VoxelAgentRadius); // compactHeightfield.BuildDistanceField(); // compactHeightfield.BuildRegions(0, settings.MinRegionSize, settings.MergedRegionSize); // contourSet = compactHeightfield.BuildContourSet(settings); // polyMesh = new PolyMesh(contourSet, settings); // polyMeshDetail = new PolyMeshDetail(polyMesh, compactHeightfield, settings); // buildData = new NavMeshBuilder(polyMesh, polyMeshDetail, new SharpNav.Pathfinding.OffMeshConnection[0], settings); // tiledNavMesh = new TiledNavMesh(buildData); // navMeshQuery = new NavMeshQuery(tiledNavMesh, 2048); // } // catch (Exception e) // { // //if (!interceptExceptions) // // throw; // //else // // Console.WriteLine("Navmesh generation failed with exception:" + Environment.NewLine + e.ToString()); // } // finally // { // //sw.Stop(); // } //} private void GenerateNavMesh() { Console.WriteLine("Generating NavMesh"); long prevMs = 0; //try //{ var levelTris = level.GetTriangles(); var triEnumerable = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length); BBox3 bounds = triEnumerable.GetBoundingBox(); settings = NavMeshGenerationSettings.Default; heightfield = new Heightfield(bounds, settings); heightfield.RasterizeTriangles(levelTris, Area.Default); heightfield.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); heightfield.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); heightfield.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); compactHeightfield = new CompactHeightfield(heightfield, settings); compactHeightfield.Erode(settings.VoxelAgentRadius); compactHeightfield.BuildDistanceField(); compactHeightfield.BuildRegions(0, settings.MinRegionSize, settings.MergedRegionSize); contourSet = compactHeightfield.BuildContourSet(settings); polyMesh = new PolyMesh(contourSet, settings); polyMeshDetail = new PolyMeshDetail(polyMesh, compactHeightfield, settings); buildData = new NavMeshBuilder(polyMesh, polyMeshDetail, new SharpNav.Pathfinding.OffMeshConnection[0], settings); tiledNavMesh = new TiledNavMesh(buildData); navMeshQuery = new NavMeshQuery(tiledNavMesh, 2048); OutMesh(); //} //catch (Exception e) //{ // //if (!interceptExceptions) // // throw; // //else // // Console.WriteLine("Navmesh generation failed with exception:" + Environment.NewLine + e.ToString()); //} //finally //{ // //sw.Stop(); //} }
private void BuildDetailMesh() { if ((mResultOptions & NMGenAssetFlag.DetailMesh) == 0) { UnityEngine.Debug.Log("(mResultOptions & NMGenAssetFlag.DetailMesh) == 0"); FinalizeComplete(); return; } PolyMesh polyMesh = mBuildContext.PolyMesh; CompactHeightfield chf = mBuildContext.CompactField; PolyMeshDetail detailMesh = PolyMeshDetail.Build(mBuildContext , polyMesh , chf , mConfig.detailSampleDistance , mConfig.detailMaxDeviation); if (CanDispose(NMGenAssetFlag.CompactField)) { chf.RequestDisposal(); mBuildContext.CompactField = null; } if (detailMesh == null) { UnityEngine.Debug.Log("BuildDetailMesh==null"); FinalizeAbort("Aborted at detail mesh build."); return; } mBuildContext.DetailMesh = detailMesh; if (detailMesh.MeshCount < 1) { // Will only happen on an error. FinalizeAbort("Aborted after detail mesh build. No detail meshes generated."); return; } if (PostProcess() & PostPolyMeshCheck() & PostDetailCheck()) { mBuildContext.Log("Built detail mesh. TriangleCount: " + detailMesh.TriCount, this); FinalizeComplete(); } }
internal PolyMeshDetail GetDetailMesh(int x, int z) { int i = GetIndex(x, z); if (i == IndexError) { return(null); } BuildDataItem item = unsafeItems[i]; if (item.detailMesh.Length == 0) { return(null); } return(PolyMeshDetail.Create(item.detailMesh)); }
private bool PostDetailCheck() { PolyMeshDetail detailMesh = mBuildContext.DetailMesh; PolyMesh polyMesh = mBuildContext.PolyMesh; if (detailMesh == null || detailMesh.IsDisposed) { FinalizeAbort("Custom processors destroyed the detail mesh. (" + mState + " Post)"); return(false); } else if (polyMesh.PolyCount != detailMesh.MeshCount) { FinalizeAbort("Custom processors returned with poly/detail count mismatch. (" + mState + " Post)"); return(false); } return(true); }
internal void SetWorkingData(PolyMesh polyMesh, PolyMeshDetail detailMesh) { if (polyMesh == null || polyMesh.PolyCount == 0) { SetAsEmpty(); return; } this.polyMesh = polyMesh.GetSerializedData(false); if (detailMesh == null) { this.detailMesh = new byte[0]; } else { this.detailMesh = detailMesh.GetSerializedData(false); } }
public void HandleDetailMesh(NavmeshBuild build, int tx, int tz) { if (!build) { return; } if (mDebugObject == null) { PolyMeshDetail mesh = build.BuildData.GetDetailMesh(tx, tz); if (mesh != null) { mDebugObject = mesh.GetData(false); } } if (mDebugObject != null) { NMGenDebug.Draw(( PolyMeshDetailData )mDebugObject); } }
public NavMeshBuilder Build() { // Generate tile data LoadTileData(); // Extract raw data from geometry float[] vertices; int[] indices; s_Geometry.GetRawData(out vertices, out indices /*, out areas*/); var hf = new Heightfield(Bounds, NavmeshSettings); hf.RasterizeTriangles(vertices, Area.Default); hf.FilterLedgeSpans(NavmeshSettings.VoxelAgentHeight, NavmeshSettings.VoxelMaxClimb); hf.FilterLowHangingWalkableObstacles(NavmeshSettings.VoxelMaxClimb); hf.FilterWalkableLowHeightSpans(NavmeshSettings.VoxelAgentHeight); var chf = new CompactHeightfield(hf, NavmeshSettings); chf.Erode(NavmeshSettings.VoxelAgentRadius); chf.BuildDistanceField(); chf.BuildRegions((int)(NavmeshSettings.AgentRadius / NavmeshSettings.CellSize) + 8, NavmeshSettings.MinRegionSize, NavmeshSettings.MergedRegionSize); var cset = chf.BuildContourSet(NavmeshSettings); var pmesh = new PolyMesh(cset, NavmeshSettings); var dmesh = new PolyMeshDetail(pmesh, chf, NavmeshSettings); var buildData = new NavMeshBuilder(pmesh, dmesh, new SharpNav.Pathfinding.OffMeshConnection[0], NavmeshSettings); Console.WriteLine("Rasterized " + vertices.Length / 9 + " triangles."); Console.WriteLine("Generated " + cset.Count + " regions."); Console.WriteLine("PolyMesh contains " + pmesh.VertCount + " vertices in " + pmesh.PolyCount + " polys."); Console.WriteLine("PolyMeshDetail contains " + dmesh.VertCount + " vertices and " + dmesh.TrisCount + " tris in " + dmesh.MeshCount + " meshes."); return(buildData); }
public bool QueueTask(BuildContext context , int tx, int tz , PolyMesh polyMesh, PolyMeshDetail detailMesh , bool bvTreeEnabled , int priority) { TileBuildTask task = TileBuildTask.Create(tx, tz , polyMesh.GetData(false) , (detailMesh == null ? null : detailMesh.GetData(true)) , Build.Connections , bvTreeEnabled , true , priority); if (!mTaskProcessor.QueueTask(task)) { context.LogError("Task processor rejected task.", this); return(false); } mTileTasks.Add(task); return(true); }
private void GenerateNavMesh() { //Debug.Log("Generating NavMesh"); Stopwatch sw = new Stopwatch(); sw.Start(); long prevMs = 0; try { //level.SetBoundingBoxOffset(new SVector3(settings.CellSize * 0.5f, settings.CellHeight * 0.5f, settings.CellSize * 0.5f)); var levelTris = level.GetTriangles(); var triEnumerable = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length); BBox3 bounds = triEnumerable.GetBoundingBox(); heightfield = new Heightfield(bounds, settings); //Debug.Log("Heightfield"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; /*Area[] areas = AreaGenerator.From(triEnumerable, Area.Default) * .MarkAboveHeight(areaSettings.MaxLevelHeight, Area.Null) * .MarkBelowHeight(areaSettings.MinLevelHeight, Area.Null) * .MarkBelowSlope(areaSettings.MaxTriSlope, Area.Null) * .ToArray(); * heightfield.RasterizeTrianglesWithAreas(levelTris, areas);*/ heightfield.RasterizeTriangles(levelTris, Area.Default); //Debug.Log(" + Rasterization\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); //Debug.Log(" + Filtering"); prevMs = sw.ElapsedMilliseconds; heightfield.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); //Debug.Log(" + Ledge Spans\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; heightfield.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); //Debug.Log(" + Low Hanging Obstacles\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; heightfield.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); //Debug.Log(" + Low Height Spans\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield = new CompactHeightfield(heightfield, settings); //Debug.Log("CompactHeightfield"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield.Erode(settings.VoxelAgentRadius); //Debug.Log(" + Erosion\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield.BuildDistanceField(); //Debug.Log(" + Distance Field\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; compactHeightfield.BuildRegions(0, settings.MinRegionSize, settings.MergedRegionSize); //Debug.Log(" + Regions\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; contourSet = compactHeightfield.BuildContourSet(settings); //Debug.Log("ContourSet"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; polyMesh = new PolyMesh(contourSet, settings); //Debug.Log("PolyMesh"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; polyMeshDetail = new PolyMeshDetail(polyMesh, compactHeightfield, settings); //Debug.Log("PolyMeshDetail"); //Debug.Log(" + Ctor\t\t\t\t" + (sw.ElapsedMilliseconds - prevMs).ToString("D3") + " ms"); prevMs = sw.ElapsedMilliseconds; hasGenerated = true; } catch (Exception e) { if (!interceptExceptions) { throw; } else { //Debug.Log("Navmesh generation failed with exception:" + Environment.NewLine + e.ToString()); } } finally { sw.Stop(); } if (hasGenerated) { try { GeneratePathfinding(); //Pathfinding with multiple units //GenerateCrowd(); } catch (Exception e) { //Debug.Log("Pathfinding generation failed with exception" + Environment.NewLine + e.ToString()); hasGenerated = false; } //Label l = (Label)statusBar.FindChildByName("GenTime"); //l.Text = "Generation Time: " + sw.ElapsedMilliseconds + "ms"; //Debug.Log("Navmesh generated successfully in " + sw.ElapsedMilliseconds + "ms."); //Debug.Log("Rasterized " + level.GetTriangles().Length + " triangles."); //Debug.Log("Generated " + contourSet.Count + " regions."); //Debug.Log("PolyMesh contains " + polyMesh.VertCount + " vertices in " + polyMesh.PolyCount + " polys."); //Debug.Log("PolyMeshDetail contains " + polyMeshDetail.VertCount + " vertices and " + polyMeshDetail.TrisCount + " tris in " + polyMeshDetail.MeshCount + " meshes."); } }
/// <summary> /// Initializes a new instance of the <see cref="NavMeshBuilder" /> class. /// Add all the PolyMesh and PolyMeshDetail attributes to the Navigation Mesh. /// Then, add Off-Mesh connection support. /// </summary> /// <param name="polyMesh">The PolyMesh</param> /// <param name="polyMeshDetail">The PolyMeshDetail</param> /// <param name="offMeshCons">Offmesh connection data</param> /// <param name="settings">The settings used to build.</param> public NavMeshBuilder(PolyMesh polyMesh, PolyMeshDetail polyMeshDetail, OffMeshConnection[] offMeshCons, NavMeshGenerationSettings settings) { if (settings.VertsPerPoly > PathfindingCommon.VERTS_PER_POLYGON) { throw new InvalidOperationException("The number of vertices per polygon is above SharpNav's limit"); } if (polyMesh.VertCount == 0) { throw new InvalidOperationException("The provided PolyMesh has no vertices."); } if (polyMesh.PolyCount == 0) { throw new InvalidOperationException("The provided PolyMesh has not polys."); } int nvp = settings.VertsPerPoly; //classify off-mesh connection points BoundarySide[] offMeshSides = new BoundarySide[offMeshCons.Length * 2]; int storedOffMeshConCount = 0; int offMeshConLinkCount = 0; if (offMeshCons.Length > 0) { //find height bounds float hmin = float.MaxValue; float hmax = -float.MaxValue; if (polyMeshDetail != null) { for (int i = 0; i < polyMeshDetail.VertCount; i++) { float h = polyMeshDetail.Verts[i].Y; hmin = Math.Min(hmin, h); hmax = Math.Max(hmax, h); } } else { for (int i = 0; i < polyMesh.VertCount; i++) { PolyVertex iv = polyMesh.Verts[i]; float h = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight; hmin = Math.Min(hmin, h); hmax = Math.Max(hmax, h); } } hmin -= settings.MaxClimb; hmax += settings.MaxClimb; BBox3 bounds = polyMesh.Bounds; bounds.Min.Y = hmin; bounds.Max.Y = hmax; for (int i = 0; i < offMeshCons.Length; i++) { Vector3 p0 = offMeshCons[i].Pos0; Vector3 p1 = offMeshCons[i].Pos1; offMeshSides[i * 2 + 0] = BoundarySideExtensions.FromPoint(p0, bounds); offMeshSides[i * 2 + 1] = BoundarySideExtensions.FromPoint(p1, bounds); //off-mesh start position isn't touching mesh if (offMeshSides[i * 2 + 0] == BoundarySide.Internal) { if (p0.Y < bounds.Min.Y || p0.Y > bounds.Max.Y) { offMeshSides[i * 2 + 0] = 0; } } //count number of links to allocate if (offMeshSides[i * 2 + 0] == BoundarySide.Internal) { offMeshConLinkCount++; } if (offMeshSides[i * 2 + 1] == BoundarySide.Internal) { offMeshConLinkCount++; } if (offMeshSides[i * 2 + 0] == BoundarySide.Internal) { storedOffMeshConCount++; } } } //off-mesh connections stored as polygons, adjust values int totPolyCount = polyMesh.PolyCount + storedOffMeshConCount; int totVertCount = polyMesh.VertCount + storedOffMeshConCount * 2; //find portal edges int edgeCount = 0; int portalCount = 0; for (int i = 0; i < polyMesh.PolyCount; i++) { PolyMesh.Polygon p = polyMesh.Polys[i]; for (int j = 0; j < nvp; j++) { if (p.Vertices[j] == PolyMesh.NullId) { break; } edgeCount++; if (PolyMesh.IsBoundaryEdge(p.NeighborEdges[j])) { int dir = p.NeighborEdges[j] % 16; if (dir != 15) { portalCount++; } } } } int maxLinkCount = edgeCount + portalCount * 2 + offMeshConLinkCount * 2; //find unique detail vertices int uniqueDetailVertCount = 0; int detailTriCount = 0; if (polyMeshDetail != null) { detailTriCount = polyMeshDetail.TrisCount; for (int i = 0; i < polyMesh.PolyCount; i++) { int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount; int numPolyVerts = polyMesh.Polys[i].VertexCount; uniqueDetailVertCount += numDetailVerts - numPolyVerts; } } else { uniqueDetailVertCount = 0; detailTriCount = 0; for (int i = 0; i < polyMesh.PolyCount; i++) { int numPolyVerts = polyMesh.Polys[i].VertexCount; uniqueDetailVertCount += numPolyVerts - 2; } } //allocate data header = new PathfindingCommon.NavMeshInfo(); navVerts = new Vector3[totVertCount]; navPolys = new Poly[totPolyCount]; navDMeshes = new PolyMeshDetail.MeshData[polyMesh.PolyCount]; navDVerts = new Vector3[uniqueDetailVertCount]; navDTris = new PolyMeshDetail.TriangleData[detailTriCount]; offMeshConnections = new OffMeshConnection[storedOffMeshConCount]; //store header //HACK TiledNavMesh should figure out the X/Y/layer instead of the user maybe? header.X = 0; header.Y = 0; header.Layer = 0; header.PolyCount = totPolyCount; header.VertCount = totVertCount; header.MaxLinkCount = maxLinkCount; header.Bounds = polyMesh.Bounds; header.DetailMeshCount = polyMesh.PolyCount; header.DetailVertCount = uniqueDetailVertCount; header.DetailTriCount = detailTriCount; header.OffMeshBase = polyMesh.PolyCount; header.WalkableHeight = settings.AgentHeight; header.WalkableRadius = settings.AgentRadius; header.WalkableClimb = settings.MaxClimb; header.OffMeshConCount = storedOffMeshConCount; header.BvNodeCount = settings.BuildBoundingVolumeTree ? polyMesh.PolyCount * 2 : 0; header.BvQuantFactor = 1f / settings.CellSize; int offMeshVertsBase = polyMesh.VertCount; int offMeshPolyBase = polyMesh.PolyCount; //store vertices for (int i = 0; i < polyMesh.VertCount; i++) { PolyVertex iv = polyMesh.Verts[i]; navVerts[i].X = polyMesh.Bounds.Min.X + iv.X * settings.CellSize; navVerts[i].Y = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight; navVerts[i].Z = polyMesh.Bounds.Min.Z + iv.Z * settings.CellSize; } //off-mesh link vertices int n = 0; for (int i = 0; i < offMeshCons.Length; i++) { //only store connections which start from this tile if (offMeshSides[i * 2 + 0] == BoundarySide.Internal) { navVerts[offMeshVertsBase + (n * 2 + 0)] = offMeshCons[i].Pos0; navVerts[offMeshVertsBase + (n * 2 + 1)] = offMeshCons[i].Pos1; n++; } } //store polygons for (int i = 0; i < polyMesh.PolyCount; i++) { navPolys[i] = new Poly(); navPolys[i].VertCount = 0; navPolys[i].Tag = polyMesh.Polys[i].Tag; navPolys[i].Area = polyMesh.Polys[i].Area; navPolys[i].PolyType = PolygonType.Ground; navPolys[i].Verts = new int[nvp]; navPolys[i].Neis = new int[nvp]; for (int j = 0; j < nvp; j++) { if (polyMesh.Polys[i].Vertices[j] == PolyMesh.NullId) { break; } navPolys[i].Verts[j] = polyMesh.Polys[i].Vertices[j]; if (PolyMesh.IsBoundaryEdge(polyMesh.Polys[i].NeighborEdges[j])) { //border or portal edge int dir = polyMesh.Polys[i].NeighborEdges[j] % 16; if (dir == 0xf) //border { navPolys[i].Neis[j] = 0; } else if (dir == 0) //portal x- { navPolys[i].Neis[j] = Link.External | 4; } else if (dir == 1) //portal z+ { navPolys[i].Neis[j] = Link.External | 2; } else if (dir == 2) //portal x+ { navPolys[i].Neis[j] = Link.External | 0; } else if (dir == 3) //portal z- { navPolys[i].Neis[j] = Link.External | 6; } } else { //normal connection navPolys[i].Neis[j] = polyMesh.Polys[i].NeighborEdges[j] + 1; } navPolys[i].VertCount++; } } //off-mesh connection vertices n = 0; for (int i = 0; i < offMeshCons.Length; i++) { //only store connections which start from this tile if (offMeshSides[i * 2 + 0] == BoundarySide.Internal) { navPolys[offMeshPolyBase + n].VertCount = 2; navPolys[offMeshPolyBase + n].Verts = new int[nvp]; navPolys[offMeshPolyBase + n].Verts[0] = offMeshVertsBase + (n * 2 + 0); navPolys[offMeshPolyBase + n].Verts[1] = offMeshVertsBase + (n * 2 + 1); navPolys[offMeshPolyBase + n].Tag = offMeshCons[i].Flags; navPolys[offMeshPolyBase + n].Area = polyMesh.Polys[offMeshCons[i].Poly].Area; //HACK is this correct? navPolys[offMeshPolyBase + n].PolyType = PolygonType.OffMeshConnection; n++; } } //store detail meshes and vertices if (polyMeshDetail != null) { int vbase = 0; List <Vector3> storedDetailVerts = new List <Vector3>(); for (int i = 0; i < polyMesh.PolyCount; i++) { int vb = polyMeshDetail.Meshes[i].VertexIndex; int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount; int numPolyVerts = navPolys[i].VertCount; navDMeshes[i].VertexIndex = vbase; navDMeshes[i].VertexCount = numDetailVerts - numPolyVerts; navDMeshes[i].TriangleIndex = polyMeshDetail.Meshes[i].TriangleIndex; navDMeshes[i].TriangleCount = polyMeshDetail.Meshes[i].TriangleCount; //Copy detail vertices //first 'nv' verts are equal to nav poly verts //the rest are detail verts for (int j = 0; j < navDMeshes[i].VertexCount; j++) { storedDetailVerts.Add(polyMeshDetail.Verts[vb + numPolyVerts + j]); } vbase += numDetailVerts - numPolyVerts; } navDVerts = storedDetailVerts.ToArray(); //store triangles for (int j = 0; j < polyMeshDetail.TrisCount; j++) { navDTris[j] = polyMeshDetail.Tris[j]; } } else { //create dummy detail mesh by triangulating polys int tbase = 0; for (int i = 0; i < polyMesh.PolyCount; i++) { int numPolyVerts = navPolys[i].VertCount; navDMeshes[i].VertexIndex = 0; navDMeshes[i].VertexCount = 0; navDMeshes[i].TriangleIndex = tbase; navDMeshes[i].TriangleCount = numPolyVerts - 2; //triangulate polygon for (int j = 2; j < numPolyVerts; j++) { navDTris[tbase].VertexHash0 = 0; navDTris[tbase].VertexHash1 = j - 1; navDTris[tbase].VertexHash2 = j; //bit for each edge that belongs to the poly boundary navDTris[tbase].Flags = 1 << 2; if (j == 2) { navDTris[tbase].Flags |= 1 << 0; } if (j == numPolyVerts - 1) { navDTris[tbase].Flags |= 1 << 4; } tbase++; } } } //store and create BV tree if (settings.BuildBoundingVolumeTree) { //build tree navBvTree = new BVTree(polyMesh.Verts, polyMesh.Polys, nvp, settings.CellSize, settings.CellHeight); } //store off-mesh connections n = 0; for (int i = 0; i < offMeshConnections.Length; i++) { //only store connections which start from this tile if (offMeshSides[i * 2 + 0] == BoundarySide.Internal) { offMeshConnections[n].Poly = offMeshPolyBase + n; //copy connection end points offMeshConnections[n].Pos0 = offMeshCons[i].Pos0; offMeshConnections[n].Pos1 = offMeshCons[i].Pos1; offMeshConnections[n].Radius = offMeshCons[i].Radius; offMeshConnections[n].Flags = offMeshCons[i].Flags; offMeshConnections[n].Side = offMeshSides[i * 2 + 1]; offMeshConnections[n].Tag = offMeshCons[i].Tag; n++; } } }
public void GenNavMesh() { // MeshCollider List <Triangle3> colliderTringles = new List <Triangle3>(); Collider[] colliders = GameObject.FindObjectsOfType <Collider>(); List <GameObject> destroyGos = new List <GameObject>(); foreach (Collider collider in colliders) { Mesh mesh = null; Matrix4x4 localToWorldMatrix = Matrix4x4.identity; if (collider is MeshCollider) { MeshCollider mc = collider as MeshCollider; mesh = mc.sharedMesh; localToWorldMatrix = mc.transform.localToWorldMatrix; } if (collider is BoxCollider) { BoxCollider bc = collider as BoxCollider; GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube); mesh = go.GetComponent <MeshFilter>().sharedMesh; go.transform.parent = collider.transform; go.transform.localRotation = Quaternion.identity; go.transform.localPosition = bc.center; go.transform.localScale = bc.size; localToWorldMatrix = go.transform.localToWorldMatrix; destroyGos.Add(go); } if (null != mesh) { UnityEngine.Vector3[] vertices = mesh.vertices; for (int i = 0; i < mesh.subMeshCount; ++i) { var subMesh = mesh.GetIndices(i); for (int j = 0; j < subMesh.Length; j += 3) { UnityEngine.Vector3 a = localToWorldMatrix.MultiplyPoint(vertices[subMesh[j]]); UnityEngine.Vector3 b = localToWorldMatrix.MultiplyPoint(vertices[subMesh[j + 1]]); UnityEngine.Vector3 c = localToWorldMatrix.MultiplyPoint(vertices[subMesh[j + 2]]); colliderTringles.Add(new Triangle3(ConvertVector3(a), ConvertVector3(b), ConvertVector3(c))); } } } } foreach (var go in destroyGos) { GameObject.DestroyImmediate(go); } destroyGos.Clear(); Triangle3[] levelTris = colliderTringles.ToArray(); var triEnumerable = TriangleEnumerable.FromTriangle(levelTris, 0, levelTris.Length); BBox3 bounds = triEnumerable.GetBoundingBox(); heightfield = new Heightfield(bounds, settings); heightfield.RasterizeTriangles(levelTris, Area.Default); heightfield.FilterLedgeSpans(settings.VoxelAgentHeight, settings.VoxelMaxClimb); heightfield.FilterLowHangingWalkableObstacles(settings.VoxelMaxClimb); heightfield.FilterWalkableLowHeightSpans(settings.VoxelAgentHeight); compactHeightfield = new CompactHeightfield(heightfield, settings); compactHeightfield.Erode(settings.VoxelAgentRadius); compactHeightfield.BuildDistanceField(); compactHeightfield.BuildRegions(0, settings.MinRegionSize, settings.MergedRegionSize); contourSet = compactHeightfield.BuildContourSet(settings); polyMesh = new PolyMesh(contourSet, settings); polyMeshDetail = new PolyMeshDetail(polyMesh, compactHeightfield, settings); buildData = new NavMeshBuilder(polyMesh, polyMeshDetail, new SharpNav.Pathfinding.OffMeshConnection[0], settings); tiledNavMesh = new TiledNavMesh(buildData); navMeshQuery = new NavMeshQuery(tiledNavMesh, 2048); { System.Random r = new System.Random(); regionColors = new Color[compactHeightfield.MaxRegions]; regionColors[0] = Color.black; for (int i = 1; i < regionColors.Length; i++) { regionColors[i] = new Color((byte)r.Next(0, 255), (byte)r.Next(0, 255), (byte)r.Next(0, 255), 255); } } this.GenDrawMesh(); Debug.Log("GenNavMesh Done!"); }
public bool BuildNavMesh( out string error ) { DestroyNavMesh(); if( !EnabledInHierarchy ) { error = "Is not enabled."; return false; } //get geometry data var collector = GetAllGeometriesForNavigationMesh(); Vector3[] vertices = collector.resultVertices; int[] indices = collector.resultIndices; int vertexCount = collector.resultVertexCount; int indexCount = collector.resultIndexCount; if( vertexCount == 0 ) { error = "No vertices were gathered from collision objects."; return false; } //get settings var settings = new NavMeshGenerationSettings(); settings.CellSize = (float)CellSize; settings.CellHeight = (float)CellHeight; settings.MaxClimb = (float)AgentMaxClimb; settings.AgentHeight = (float)AgentHeight; settings.AgentRadius = (float)AgentRadius; settings.MinRegionSize = MinRegionSize; settings.MergedRegionSize = MergedRegionSize; settings.MaxEdgeLength = MaxEdgeLength; settings.MaxEdgeError = (float)MaxEdgeError; settings.VertsPerPoly = MaxVerticesPerPolygon; settings.SampleDistance = DetailSampleDistance; settings.MaxSampleError = DetailMaxSampleError; settings.BuildBoundingVolumeTree = true; TiledNavMesh newTiledNavMesh; try { //level.SetBoundingBoxOffset(new SVector3(settings.CellSize * 0.5f, settings.CellHeight * 0.5f, settings.CellSize * 0.5f)); var bounds = Bounds.Cleared; bounds.Add( vertices ); var heightfield = new Heightfield( ToSharpNav( bounds ), settings ); var vertices2 = new SharpNav.Geometry.Vector3[ indexCount ]; for( int index = 0; index < indexCount; index++ ) vertices2[ index ] = ToSharpNav( vertices[ indices[ index ] ] ); //Area[] areas = AreaGenerator.From( vertices2, Area.Default ) // .MarkBelowSlope( (float)AgentMaxSlope.Value.InRadians(), Area.Null ) // .ToArray(); //Area[] areas = AreaGenerator.From(triEnumerable, Area.Default) // .MarkAboveHeight(areaSettings.MaxLevelHeight, Area.Null) // .MarkBelowHeight(areaSettings.MinLevelHeight, Area.Null) // .MarkBelowSlope(areaSettings.MaxTriSlope, Area.Null) // .ToArray(); //heightfield.RasterizeTrianglesWithAreas( vertices2, areas ); heightfield.RasterizeTriangles( vertices2, Area.Default ); heightfield.FilterLedgeSpans( settings.VoxelAgentHeight, settings.VoxelMaxClimb ); heightfield.FilterLowHangingWalkableObstacles( settings.VoxelMaxClimb ); heightfield.FilterWalkableLowHeightSpans( settings.VoxelAgentHeight ); var compactHeightfield = new CompactHeightfield( heightfield, settings ); compactHeightfield.Erode( settings.VoxelAgentRadius ); compactHeightfield.BuildDistanceField(); compactHeightfield.BuildRegions( 0, settings.MinRegionSize, settings.MergedRegionSize ); //!!!! System.Random r = new System.Random(); var regionColors = new ColorByte[ compactHeightfield.MaxRegions ]; regionColors[ 0 ] = new ColorByte( 0, 0, 0 ); for( int i = 1; i < regionColors.Length; i++ ) regionColors[ i ] = new ColorByte( (byte)r.Next( 0, 255 ), (byte)r.Next( 0, 255 ), (byte)r.Next( 0, 255 ), (byte)255 ); var contourSet = compactHeightfield.BuildContourSet( settings ); var polyMesh = new PolyMesh( contourSet, settings ); var polyMeshDetail = new PolyMeshDetail( polyMesh, compactHeightfield, settings ); var buildData = new NavMeshBuilder( polyMesh, polyMeshDetail, new OffMeshConnection[ 0 ], settings ); newTiledNavMesh = new TiledNavMesh( buildData ); //!!!! ////Pathfinding with multiple units //GenerateCrowd(); } catch( Exception e ) { DestroyNavMesh(); error = e.Message; return false; } int dataLength; byte[] data; using( var memoryStream = new MemoryStream() ) { var serializer = new NavMeshBinarySerializer(); serializer.Serialize( memoryStream, newTiledNavMesh ); dataLength = (int)memoryStream.Length; data = memoryStream.GetBuffer(); } //generate nav mesh data var writer = new ArrayDataWriter(); writer.Write( navMeshDataVersion ); writer.Write( dataLength ); writer.Write( data, 0, dataLength ); //set NavMeshData and init var newNavMeshData = new byte[ writer.BitLength / 8 ]; Buffer.BlockCopy( writer.Data, 0, newNavMeshData, 0, newNavMeshData.Length ); NavMeshData = newNavMeshData; error = ""; return true; }
public byte[] Build(int i = 0, int j = 0) { float[] bbMin, bbMax; CalculateTileBounds(out bbMin, out bbMax, false, i, j); #if (TIMETHIS) System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch(); stopWatch.Start(); long cur = 0; #endif // add border bbMin[0] -= Config.BorderSize * Config.CellSize; bbMin[2] -= Config.BorderSize * Config.CellSize; bbMax[0] += Config.BorderSize * Config.CellSize; bbMax[2] += Config.BorderSize * Config.CellSize; // get raw geometry - lots of slowness here float[] vertices; int[] triangles; byte[] areas; Geometry.GetRawData(out vertices, out triangles, out areas); #if (TIMETHIS) Console.WriteLine("GetRawData: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif // Following code would check if we have Index out of range error while computing the sum. the result itself is useless. /*float sum = 0; * foreach (int i2 in triangles) * sum += vertices[i2*3+0] + vertices[i2*3+1] + vertices[i2*3+2]; * Console.WriteLine(sum);*/ // now we can find the min/max height for THIS tile float MinHeight, MaxHeight; Geometry.CalculateMinMaxHeight(out MinHeight, out MaxHeight, bbMin, bbMax); //Geometry.Triangles.Clear(); // We should not clear triangles and stuff because we have severals files for one tile. //Geometry.Vertices.Clear(); // It will be reset at the next tile anyway, no memory issues. bbMin[1] = MinHeight; bbMax[1] = MaxHeight; Heightfield hf; int width = Config.TileWidth + (Config.BorderSize * 2); if (!Context.CreateHeightfield(out hf, width, width, bbMin, bbMax, Config.CellSize, Config.CellHeight)) { throw new OutOfMemoryException("CreateHeightfield ran out of memory"); } #if (TIMETHIS) Console.WriteLine("CreateHeightfield: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif if (triangles.Count() > 0) { /*Console.WriteLine("Context.ClearUnwalkableTriangles: verticles: " + vertices.Length + ", triangles: " + triangles.Length + ", areas: " + areas.Length); * Console.WriteLine("Memory allocated GC: " + GC.GetTotalMemory(true));/*/ Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas); #if (TIMETHIS) Console.WriteLine("ClearUnwalkableTriangles: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb); #if (TIMETHIS) Console.WriteLine("RasterizeTriangles: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif GC.KeepAlive(vertices); // force C# to keep vertices, triangles and areas alive while it's in unamanaged code. GC.KeepAlive(triangles); GC.KeepAlive(areas); } vertices = null; triangles = null; areas = null; GC.Collect(); // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. Context.FilterLowHangingWalkableObstacles(Config.WalkableClimb, hf); #if (TIMETHIS) Console.WriteLine("FilterLowHangingWalkableObstacles: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif Context.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb, hf); #if (TIMETHIS) Console.WriteLine("FilterLedgeSpans: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif Context.FilterWalkableLowHeightSpans(Config.WalkableHeight, hf); #if (TIMETHIS) Console.WriteLine("FilterWalkableLowHeightSpans: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif // Rasterize once again after the cleanup we did //Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb); //#if (TIMETHIS) // Console.WriteLine("RasterizeTriangles: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); // cur = stopWatch.ElapsedMilliseconds; //#endif // Compact the heightfield so that it is faster to handle from now on. // This will result in more cache coherent data as well as the neighbours // between walkable cells will be calculated. CompactHeightfield chf; if (!Context.BuildCompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, hf, out chf)) { throw new OutOfMemoryException("BuildCompactHeightfield ran out of memory"); } #if (TIMETHIS) Console.WriteLine("BuildCompactHeightfield: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif hf.Delete(); // Erode the walkable area by agent radius. if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf)) { throw new OutOfMemoryException("ErodeWalkableArea ran out of memory"); } #if (TIMETHIS) Console.WriteLine("ErodeWalkableArea: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!Context.BuildDistanceField(chf)) { throw new OutOfMemoryException("BuildDistanceField ran out of memory"); } #if (TIMETHIS) Console.WriteLine("BuildDistanceField: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif // Partition the walkable surface into simple regions without holes. if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea)) { throw new OutOfMemoryException("BuildRegions ran out of memory"); } #if (TIMETHIS) Console.WriteLine("BuildRegions: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif // Create contours. ContourSet cset; if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset)) { throw new OutOfMemoryException("BuildContours ran out of memory"); } #if (TIMETHIS) Console.WriteLine("BuildContours: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif // Build polygon navmesh from the contours. PolyMesh pmesh; if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh)) { throw new OutOfMemoryException("BuildPolyMesh ran out of memory"); } #if (TIMETHIS) Console.WriteLine("BuildPolyMesh: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); cur = stopWatch.ElapsedMilliseconds; #endif // Build detail mesh. PolyMeshDetail dmesh = null; //if (!Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError,out dmesh)) // throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory"); //#if (TIMETHIS) // Console.WriteLine("BuildPolyMeshDetail: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); // cur = stopWatch.ElapsedMilliseconds; //#endif chf.Delete(); cset.Delete(); // Set flags according to area types (e.g. Swim for Water) pmesh.MarkAll(); // get original bounds float[] tilebMin, tilebMax; CalculateTileBounds(out tilebMin, out tilebMax, false, i, j); tilebMin[1] = bbMin[1]; tilebMax[1] = bbMax[1]; // build off mesh connections for flightmasters // bMax and bMin are switched here because of the coordinate system transformation var connections = new List <OffMeshConnection>(); if (MapId == 1220) { SlimDX.Vector3 from = new SlimDX.Vector3(1685.681f, 4709.121f, 139.4296f); SlimDX.Vector3 to = new SlimDX.Vector3(1682.194f, 4712.713f, 139.6532f); OffMeshConnection conn = new OffMeshConnection { AreaId = PolyArea.Road, Flags = PolyFlag.Walk, From = from.ToRecast().ToFloatArray(), To = to.ToRecast().ToFloatArray(), Radius = 5, Type = ConnectionType.BiDirectional, UserID = 1, }; connections.Add(conn); from = new SlimDX.Vector3(1661.302f, 4727.02f, 139.4618f); to = new SlimDX.Vector3(1669.568f, 4733.722f, 138.7087f); conn = new OffMeshConnection { AreaId = PolyArea.Road, Flags = PolyFlag.Walk, From = from.ToRecast().ToFloatArray(), To = to.ToRecast().ToFloatArray(), Radius = 5f, Type = ConnectionType.BiDirectional, UserID = 2, }; connections.Add(conn); } /*if (MapId == 0 && X == 31 && Y == 58) * { * //<X>-14250.71</X> * //<Y>329.7578</Y> * //<Z>24.17678</Z> * * //<X>-14254.86</X> * //<Y>336.1039</Y> * //<Z>26.79213</Z> * * SlimDX.Vector3 from = new SlimDX.Vector3(1.0f, 1.0f, 1.0f); * SlimDX.Vector3 to = new SlimDX.Vector3(1.0f, 1.0f, 1.0f); * OffMeshConnection conn = new OffMeshConnection * { * From = from.ToRecast().ToFloatArray(), * To = to.ToRecast().ToFloatArray(), * Radius = 2.5f, * Type = ConnectionType.BiDirectional, * UserID = 88, * }; * connections.Add(conn); * }*/ /* // Disable mesh connexion RIVAL * var taxis = TaxiHelper.GetNodesInBBox(MapId, tilebMax.ToWoW(), tilebMin.ToWoW()); * foreach (var taxi in taxis) * { * Log.Log(LogCategory.Warning, * "Flightmaster \"" + taxi.Name + "\", Id: " + taxi.Id + " Horde: " + taxi.IsHorde + " Alliance: " + * taxi.IsAlliance); * * var data = TaxiHelper.GetTaxiData(taxi); * var from = taxi.Location.ToRecast().ToFloatArray(); * connections.AddRange(data.To.Select(to => new OffMeshConnection * { * AreaId = PolyArea.Road, * Flags = PolyFlag.FlightMaster, * From = from, * To = to.Value.Location.ToRecast().ToFloatArray(), * Radius = Config.WorldWalkableRadius, * Type = ConnectionType.OneWay, * UserID = (uint) to.Key * })); * * foreach (var target in data.To) * Log.Log(LogCategory.Warning, * "\tPath to: \"" + target.Value.Name + "\" Id: " + target.Value.Id + " Path Id: " + * target.Key); * }*/ byte[] tileData; if (!Detour.CreateNavMeshData(out tileData, pmesh, dmesh, X * Constant.Division + i, Y * Constant.Division + j, tilebMin, tilebMax, Config.WorldWalkableHeight, Config.WorldWalkableRadius, Config.WorldWalkableClimb, Config.CellSize, Config.CellHeight, Config.BuildBvTree, connections.ToArray())) { pmesh.Delete(); //dmesh.Delete(); return(null); } #if (TIMETHIS) Console.WriteLine("CreateNavMeshData: " + (stopWatch.ElapsedMilliseconds - cur) + ", total: " + stopWatch.ElapsedMilliseconds); #endif pmesh.Delete(); //dmesh.Delete(); GC.Collect(); return(tileData); }
public static extern bool rcpdBuildPolyMeshDetail(IntPtr context , ref PolyMeshEx polyMesh , [In] CompactHeightfield chf , float sampleDist , float sampleMaxError , [In, Out] PolyMeshDetail detailMesh);
public byte[] Build() { Log = new MemoryLog(); //ConsoleLog(); if (!Directory.Exists(_meshDir + "Dungeons")) { Directory.CreateDirectory(_meshDir + "Dungeons"); } if (File.Exists(GetDungeonLockAndPath()) || File.Exists(GetMeshPath())) { return(null); } try { string tlock = GetDungeonLockAndPath(); var sw = File.CreateText(tlock); sw.Close(); } catch (Exception) { // In case 2 builder are trying to create the same file return(null); } InitializeProgress(12); Geometry = new Geometry { Transform = true }; if (Dungeon == "AllianceGunship") { // hardcode for AllianceGunship in Deephome. Geometry.AddAllianceGunShip(); } else { var wdt = new WDT("World\\maps\\" + Dungeon + "\\" + Dungeon + ".wdt"); if (!wdt.IsGlobalModel || !wdt.IsValid) { return(null); } var model = new WorldModelRoot(wdt.ModelFile); Geometry.AddDungeon(model, wdt.ModelDefinition); } CompleteWorkUnit(); if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0) { throw new InvalidOperationException("Can't build mesh with empty geometry"); } InsertAllGameobjectGeometry(MapId); Context = new RecastContext(); Context.SetContextHandler(Log); // get raw geometry - lots of slowness here float[] vertices; int[] triangles; byte[] areas; Geometry.GetRawData(out vertices, out triangles, out areas); Geometry.Triangles.Clear(); float[] bmin, bmax; Geometry.CalculateBoundingBox(out bmin, out bmax); Geometry.Vertices.Clear(); // Allocate voxel heightfield where we rasterize our input data to. Heightfield hf; int width, height; Recast.CalcGridSize(bmin, bmax, Config.CellSize, out width, out height); if (!Context.CreateHeightfield(out hf, width, height, bmin, bmax, Config.CellSize, Config.CellHeight)) { throw new OutOfMemoryException("CreateHeightfield ran out of memory"); } CompleteWorkUnit(); // Find triangles which are walkable based on their slope and rasterize them. Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas); Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb); vertices = null; triangles = null; areas = null; GC.Collect(); CompleteWorkUnit(); // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. Context.FilterLowHangingWalkableObstacles(Config.WalkableClimb, hf); Context.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb, hf); Context.FilterWalkableLowHeightSpans(Config.WalkableHeight, hf); CompleteWorkUnit(); // Compact the heightfield so that it is faster to handle from now on. // This will result in more cache coherent data as well as the neighbours // between walkable cells will be calculated. CompactHeightfield chf; if (!Context.BuildCompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, hf, out chf)) { throw new OutOfMemoryException("BuildCompactHeightfield ran out of memory"); } CompleteWorkUnit(); hf.Delete(); // Erode the walkable area by agent radius. if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf)) { throw new OutOfMemoryException("ErodeWalkableArea ran out of memory"); } CompleteWorkUnit(); // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!Context.BuildDistanceField(chf)) { throw new OutOfMemoryException("BuildDistanceField ran out of memory"); } CompleteWorkUnit(); // Partition the walkable surface into simple regions without holes. if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea)) { throw new OutOfMemoryException("BuildRegions ran out of memory"); } CompleteWorkUnit(); // Create contours. ContourSet cset; if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset)) { throw new OutOfMemoryException("BuildContours ran out of memory"); } CompleteWorkUnit(); // Build polygon navmesh from the contours. PolyMesh pmesh; if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh)) { throw new OutOfMemoryException("BuildPolyMesh ran out of memory"); } CompleteWorkUnit(); // Build detail mesh. PolyMeshDetail dmesh = null; //if (!Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError, out dmesh)) // throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory"); chf.Delete(); cset.Delete(); CompleteWorkUnit(); // Set flags according to area types (e.g. Swim for Water) pmesh.MarkAll(); byte[] meshData; if ( !Detour.CreateNavMeshData(out meshData, pmesh, dmesh, 0, 0, bmin, bmax, Config.WorldWalkableHeight, Config.WorldWalkableRadius, Config.WorldWalkableClimb, Config.CellSize, Config.CellHeight, Config.BuildBvTree, null)) { pmesh.Delete(); //dmesh.Delete(); return(null); } CompleteWorkUnit(); pmesh.Delete(); //dmesh.Delete(); File.Delete(GetDungeonLockAndPath()); return(meshData); }
public static extern bool rcpdBuildFromMeshData([In] byte[] meshData , int dataSize , [In, Out] PolyMeshDetail detailMesh);
public static extern bool rcpdGetSerializedData( [In] PolyMeshDetail detailMesh , bool includeBuffer , ref IntPtr resultData , ref int dataSize);
public static extern bool rcpdFreeMeshData([In, Out] PolyMeshDetail detailMesh);