/// <summary> /// Creates a new heightfield object. /// </summary> /// <param name="width">The width of the field. [Limit: >= 1] [Units: Cells]</param> /// <param name="depth">The depth of the field. [Limit: >= 1] [Units: Cells]</param> /// <param name="boundsMin">The minimum bounds of the field's AABB. [Units: World]</param> /// <param name="boundsMax">The maximum bounds of the field's AABB. [Units: World]</param> /// <param name="xzCellSize"> /// The xz-plane cell size. [Limit:>= <see cref="NMGen.MinCellSize"/>] [Units: World] /// </param> /// <param name="yCellSize"> /// The y-axis span increments. [Limit:>= <see cref="NMGen.MinCellSize"/>] [Units: World] /// </param> /// <returns>The heightfield, or null on error.</returns> public static Heightfield Create(int width, int depth , Vector3 boundsMin, Vector3 boundsMax , float xzCellSize, float yCellSize) { if (width < 1 || depth < 1 || !TriangleMesh.IsBoundsValid(boundsMin, boundsMax) || xzCellSize < NMGen.MinCellSize || yCellSize < NMGen.MinCellSize) { return(null); } IntPtr root = HeightfieldEx.nmhfAllocField(width, depth , ref boundsMin, ref boundsMax, xzCellSize, yCellSize); if (root == IntPtr.Zero) { return(null); } return(new Heightfield(root , width, depth , boundsMin, boundsMax , xzCellSize, yCellSize)); }
/// <summary> /// Voxelizes the triangles from the provided <see cref="ChunkyTriMesh"/> into the /// heightfield. /// </summary> /// <remarks> /// <para> /// The chunks that are voxelized is controled by the bounds parameters. /// </para> /// </remarks> /// <param name="context">The build context.</param> /// <param name="mesh">The mesh.</param> /// <param name="boundsMin">The minimum bounds for the mesh query.</param> /// <param name="boundsMax">The maximum bounds for the mesh query.</param> /// <param name="flagMergeThreshold"> /// The distance where the walkable flag is favored over the non-walkable flag. /// [Limit: >= 0] [Normal: 1] /// </param> /// <returns>True if the operation was successful.</returns> public bool AddTriangles(BuildContext context, ChunkyTriMesh mesh , Vector3 boundsMin, Vector3 boundsMax , int flagMergeThreshold) { if (IsDisposed || mesh == null || mesh.IsDisposed) { return(false); } List <ChunkyTriMeshNode> nodeList = new List <ChunkyTriMeshNode>(); int triCount = mesh.GetChunks(boundsMin.x, boundsMin.z , boundsMax.x, boundsMax.z , nodeList); if (triCount == 0) { return(true); } return(HeightfieldEx.nmhfRasterizeNodes(context.root , mesh.verts , mesh.tris , mesh.areas , nodeList.ToArray() , nodeList.Count , root , flagMergeThreshold)); }
/// <summary> /// The number of spans in the field. /// </summary> /// <remarks> /// <para> /// This is a non-trivial method call. Cache the result when possible. /// </para> /// </remarks> /// <returns>The number of spans in the field.</returns> public int GetSpanCount() { if (IsDisposed) { return(0); } return(HeightfieldEx.nmhfGetHeightFieldSpanCount(root)); }
/// <summary> /// Marks walkable spans as not walkable if the clearence above the span is less than the /// specified height. /// </summary> /// <remarks> /// <para> /// For this method, the clearance above the span is the distance from the span's maximum /// to the next higher span's minimum. (Same column.) /// </para> /// </remarks> /// <param name="context">The context to use for the operation</param> /// <param name="walkableHeight"> /// The maximum allowed floor to ceiling height that is considered still walkable. /// [Limit: > <see cref="NMGen.MinWalkableHeight"/>] /// </param> /// <returns>True if the operation was successful.</returns> public bool MarkLowHeightSpansNotWalkable(BuildContext context, int walkableHeight) { if (IsDisposed) { return(false); } return(HeightfieldEx.nmhfFilterWalkableLowHeightSpans(context.root , walkableHeight , root)); }
/// <summary> /// Marks non-walkable spans as walkable if their maximum is within walkableStep of a /// walkable neighbor. /// </summary> /// <remarks> /// <para> /// Example of test: <c>Math.Abs(currentSpan.Max - neighborSpan.Max) < walkableStep</c> /// </para> /// <para /// >Allows the formation of walkable regions that will flow over low lying objects such /// as curbs, and up structures such as stairways. /// </para> /// </remarks> /// <param name="context">The context to use for the operation</param> /// <param name="walkableStep"> /// The maximum allowed difference between span maximum's for the step to be considered /// waklable. [Limit: > 0] /// </param> /// <returns>True if the operation was successful.</returns> public bool MarkLowObstaclesWalkable(BuildContext context, int walkableStep) { if (IsDisposed) { return(false); } return(HeightfieldEx.nmhfFilterLowHangingWalkableObstacles(context.root , walkableStep , root)); }
/// <summary> /// Gets an buffer that is sized to fit the maximum number of spans within a column of /// the field. /// </summary> /// <returns>A buffer that is sized to fit the maximum spans within a column.</returns> public HeightfieldSpan[] GetSpanBuffer() { if (IsDisposed) { return(null); } int size = HeightfieldEx.nmhfGetMaxSpansInColumn(root); return(new HeightfieldSpan[size]); }
/// <summary> /// Voxelizes the provided triangles into the heightfield. /// </summary> /// <param name="context">The context to use for the operation</param> /// <param name="verts">The triangles. [(vertA, vertB, vertC) * triCount]</param> /// <param name="areas"> /// The ids of the areas the triangles belong to. /// [Limit: <= <see cref="NMGen.MaxArea"/>] [Size: >= triCount] /// </param> /// <param name="triCount">The number of triangles in the vertex array.</param> /// <param name="flagMergeThreshold"> /// The distance where the walkable flag is favored over the non-walkable flag. /// [Limit: >= 0] [Normal: 1] /// </param> /// <returns>True if the operation was successful.</returns> public bool AddTriangles(BuildContext context , Vector3[] verts, byte[] areas, int triCount , int flagMergeThreshold) { if (IsDisposed) { return(false); } return(HeightfieldEx.nmhfRasterizeTriangles(context.root , verts, areas, triCount , root , flagMergeThreshold)); }
/// <summary> /// Frees all resources and marks object as disposed. /// </summary> public void RequestDisposal() { if (!IsDisposed) { HeightfieldEx.nmhfFreeField(root); root = IntPtr.Zero; mWidth = 0; mDepth = 0; mXZCellSize = 0; mYCellSize = 0; mBoundsMin = Vector3Util.Zero; mBoundsMax = Vector3Util.Zero; } }
/// <summary> /// Gets the spans within the specified column. /// </summary> /// <remarks> /// <para> /// The spans will be ordered from lowest height to highest. /// </para> /// <para> /// The <see cref="GetSpanBuffer"/> method can be used to get a properly sized buffer. /// </para> /// </remarks> /// <param name="widthIndex"> /// The width index. [Limits: 0 <= value < <see cref="Width"/>] /// </param> /// <param name="depthIndex"> /// The depth index. [Limits: 0 <= value < <see cref="Depth"/>] /// </param> /// <param name="buffer"> /// The buffer to load the result into. [Size: Maximum spans in a column] /// </param> /// <returns>The number of spans returned.</returns> public int GetSpans(int widthIndex , int depthIndex , HeightfieldSpan[] buffer) { if (IsDisposed) { return(-1); } return(HeightfieldEx.nmhfGetSpans(root , widthIndex , depthIndex , buffer , buffer.Length)); }
/// <summary> /// Voxelizes the triangles in the provided mesh into the heightfield. /// </summary> /// <param name="context">The context to use for the operation</param> /// <param name="mesh">The triangle mesh.</param> /// <param name="areas"> /// The ids of the areas the triangles belong to. /// [Limit: <= <see cref="NMGen.MaxArea"/>] [Size: >= mesh.triCount] /// </param> /// <param name="flagMergeThreshold"> /// The distance where the walkable flag is favored over the non-walkable flag. /// [Limit: >= 0] [Normal: 1] /// </param> /// <returns>True if the operation was successful.</returns> public bool AddTriangles(BuildContext context, TriangleMesh mesh, byte[] areas , int flagMergeThreshold) { if (IsDisposed) { return(false); } return(HeightfieldEx.nmhfRasterizeTriMesh(context.root , mesh.verts , mesh.vertCount , mesh.tris , areas , mesh.triCount , root , flagMergeThreshold)); }
/// <summary> /// Voxelizes the provided triangles into the heightfield. /// </summary> /// <remarks> /// <para> /// Unlike many other methods in the library, the arrays must be sized exactly to the /// content. If you need to pass buffers, use the method that takes a /// <see cref="TriangleMesh"/> object. /// </para> /// </remarks> /// <param name="context">The context to use for the operation</param> /// <param name="verts">The vertices. [Length: >= vertCount] (No buffering allowed.)</param> /// <param name="tris"> /// The triangles. [(vertAIndex, vertBIndex, vertCIndex) * triCount] /// </param> /// <param name="areas"> /// The ids of the areas the triangles belong to. /// [Limit: <= <see cref="NMGen.MaxArea"/>] [Size: >= triCount] /// </param> /// <param name="flagMergeThreshold"> /// The distance where the walkable flag is favored over the non-walkable flag. /// [Limit: >= 0] [Normal: 1] /// </param> /// <returns>True if the operation was successful.</returns> public bool AddTriangles(BuildContext context , Vector3[] verts, ushort[] tris, byte[] areas , int flagMergeThreshold) { if (IsDisposed) { return(false); } return(HeightfieldEx.nmhfRasterizeTriMeshShort(context.root , verts , verts.Length / 3 , tris , areas , tris.Length / 3 , root , flagMergeThreshold)); }