/// <summary> /// Creates a compact open heightfield from a solid heightfield. /// </summary> /// <param name="context">The context to use duing the operation.</param> /// <param name="sourceField"> /// The solid heighfield to derive the compact heightfield from. /// </param> /// <param name="walkableHeight"> /// The minimum floor to ceiling height that is still considered walkable. /// [Limit: >= <see cref="NMGen.MinWalkableHeight"/>] /// </param> /// <param name="walkableStep"> /// The maximum floor to floor step that is still considered walkable.</param> /// <returns>True if the operation completed successfully.</returns> public static CompactHeightfield Build(BuildContext context , Heightfield sourceField , int walkableHeight , int walkableStep) { if (context == null || sourceField == null || sourceField.IsDisposed || walkableHeight < NMGen.MinWalkableHeight || walkableStep < 0) { return(null); } CompactHeightfield field = new CompactHeightfield(); if (CompactHeightfieldEx.nmcfBuildField(context.root , walkableHeight , walkableStep , sourceField.root , field)) { return(field); } return(null); }
/// <summary> /// Builds the distance field for the heightfield. /// </summary> /// <remarks> /// <para> /// This method must be called before attempting to build region data. /// </para> /// <para> /// The distance data is avaiable via <see cref="MaxDistance"/> and /// <see cref="GetDistanceData"/>. /// </para> /// </remarks> /// <param name="context">The context to use duing the operation.</param> /// <returns>True if the operation completed successfully.</returns> public bool BuildDistanceField(BuildContext context) { if (IsDisposed) { return(false); } return(CompactHeightfieldEx.nmcfBuildDistanceField(context.root, this)); }
/// <summary> /// Applies a median filter to the walkable areas. (Removes noise.) /// </summary> /// <param name="context">The context to use duing the operation. </param> /// <returns>True if the operation completed successfully.</returns> public bool ApplyMedianFilter(BuildContext context) { if (IsDisposed) { return(false); } return(CompactHeightfieldEx.nmcfMedianFilterWalkableArea(context.root, this)); }
/// <summary> /// Erodes the walkable area within the heightfield by the specified radius. /// </summary> /// <remarks> /// <para> /// Basically, any spans that are closer to a boundary or obstruction than the specified /// radius are marked as unwalkable. /// </para> /// <para> /// This method is usually called immediately after the heightfield has been created. /// </para> /// </remarks> /// <param name="context">The context to use during the operation. </param> /// <param name="radius">The radius to apply. [Units: Spans]</param> /// <returns>True if the operation completed successfully.</returns> public bool ErodeWalkableArea(BuildContext context, int radius) { if (IsDisposed) { return(false); } return(CompactHeightfieldEx.nmcfErodeWalkableArea(context.root , radius , this)); }
/// <summary> /// Loads the heightfield's <see cref="CompactSpan"/> data into the provided buffer. /// </summary> /// <param name="buffer">The buffer to load the data into. [Size: >= SpanCount]</param> /// <returns>True if the buffer was successfully loaded.</returns> public bool GetSpanData(CompactSpan[] buffer) { if (IsDisposed) { return(false); } return(CompactHeightfieldEx.nmcfGetSpanData(this , buffer , buffer.Length)); }
/// <summary> /// Builds region data for the heightfield using watershed partitioning. /// </summary> /// <remarks> /// <para> /// Non-null regions consist of connected, non-overlapping walkable spans that form a /// single contour. /// </para> /// <para> /// The region data is available via <see cref="MaxRegion"/> and <see cref="GetSpanData"/>. /// </para> /// <para> /// If a region forms an area that is smaller than <paramref name="minRegionArea"/>, /// all spans in the region is set to <see cref="NMGen.NullRegion"/>. /// </para> /// <para> /// Watershed partitioning can result in smaller than necessary regions, especially /// in diagonal corridors. <paramref name="mergeRegionArea"/> helps reduce unecessarily /// small regions. /// </para> /// </remarks> /// <param name="context">The context to use duing the operation.</param> /// <param name="borderSize">The AABB border size to apply.</param> /// <param name="minRegionArea"> /// The minimum area allowed for unconnected (island) regions. [Units: Spans] /// </param> /// <param name="mergeRegionArea"> /// The maximum region size that will be considered for merging with another region. /// [Units: Spans] /// </param> /// <returns>True if the operation completed successfully.</returns> public bool BuildRegions(BuildContext context , int borderSize, int minRegionArea, int mergeRegionArea) { if (IsDisposed) { return(false); } return(CompactHeightfieldEx.nmcfBuildRegions(context.root , this , borderSize , minRegionArea , mergeRegionArea)); }
/// <summary> /// Applied the area to all spans within the specified cylinder. /// </summary> /// <remarks> /// <para> /// The method will return false if the cylinder is completely outside of the heightfield. /// </para> /// </remarks> /// <param name="context">The context to use duing the operation.</param> /// <param name="centerBase">The center of the base of the cylinder.</param> /// <param name="radius">The radius of the cylinder.</param> /// <param name="height">The height of the cylinder.</param> /// <param name="area">The area to apply.</param> /// <returns>True if the operation completed successfully.</returns> public bool MarkCylinderArea(BuildContext context , Vector3 centerBase, float radius, float height , byte area) { if (IsDisposed) { return(false); } return(CompactHeightfieldEx.nmcfMarkCylinderArea(context.root , ref centerBase , radius , height , area , this)); }
/// <summary> /// Applies the area to all spans within the specified bounding box. (AABB) /// </summary> /// <remarks> /// <para> /// The method will return false if the AABB is completely outside of the heightfield. /// </para> /// </remarks> /// <param name="context">The context to use duing the operation.</param> /// <param name="boundsMin">The minimum bounds of the AABB.</param> /// <param name="boundsMax">The maximum bounds of the AABB. </param> /// <param name="area">The area to apply.</param> /// <returns>True if the operation completed successfully.</returns> public bool MarkBoxArea(BuildContext context , Vector3 boundsMin, Vector3 boundsMax , byte area) { if (IsDisposed) { return(false); } return(CompactHeightfieldEx.nmcfMarkBoxArea(context.root , ref boundsMin , ref boundsMax , area , this)); }
/// <summary> /// Applies the area to the all spans within the specified convex polygon. /// </summary> /// <remarks> /// <para> /// The y-values of the polygon vertices are ignored. So the polygon is effectively /// projected onto the xz-plane at yMin, then extruded to yMax. /// </para> /// <para> /// The method will return false if the polygon is completely outside of the heightfield. /// </para> /// </remarks> /// <param name="context">The context to use duing the operation.</param> /// <param name="verts">The vertices of the polygon [Length: vertCount]</param> /// <param name="yMin">The height of the base of the polygon.</param> /// <param name="yMax">The height of the top of the polygon.</param> /// <param name="area">The area to apply.</param> /// <returns>True if the operation completed successfully.</returns> public bool MarkConvexPolyArea(BuildContext context , Vector3[] verts, float yMin, float yMax , byte area) { if (IsDisposed) { return(false); } return(CompactHeightfieldEx.nmcfMarkConvexPolyArea(context.root , verts , verts.Length , yMin , yMax , area , this)); }
/// <summary> /// Frees all unmanaged resources controlled by the object and marks it as disposed. /// </summary> public void RequestDisposal() { if (!IsDisposed) { CompactHeightfieldEx.nmcfFreeFieldData(this); mWidth = 0; mDepth = 0; mBorderSize = 0; mBoundsMin = Vector3Util.Zero; mBoundsMax = Vector3Util.Zero; mMaxDistance = 0; mMaxRegions = 0; mSpanCount = 0; mWalkableHeight = 0; mWalkableStep = 0; mXZCellSize = 0; mYCellSize = 0; } }