for unity3d

This commit is contained in:
ikpil 2023-06-07 23:19:25 +09:00
parent cfe8378f1d
commit 17891c2d43
27 changed files with 658 additions and 644 deletions

View File

@ -1,97 +0,0 @@
using DotRecast.Detour;
using DotRecast.Recast.Demo.Geom;
namespace DotRecast.Recast.Demo.Builder;
public abstract class AbstractNavMeshBuilder
{
protected NavMeshDataCreateParams GetNavMeshCreateParams(DemoInputGeomProvider m_geom, float m_cellSize,
float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb,
RecastBuilderResult rcResult)
{
PolyMesh m_pmesh = rcResult.GetMesh();
PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
NavMeshDataCreateParams option = new NavMeshDataCreateParams();
for (int i = 0; i < m_pmesh.npolys; ++i)
{
m_pmesh.flags[i] = 1;
}
option.verts = m_pmesh.verts;
option.vertCount = m_pmesh.nverts;
option.polys = m_pmesh.polys;
option.polyAreas = m_pmesh.areas;
option.polyFlags = m_pmesh.flags;
option.polyCount = m_pmesh.npolys;
option.nvp = m_pmesh.nvp;
if (m_dmesh != null)
{
option.detailMeshes = m_dmesh.meshes;
option.detailVerts = m_dmesh.verts;
option.detailVertsCount = m_dmesh.nverts;
option.detailTris = m_dmesh.tris;
option.detailTriCount = m_dmesh.ntris;
}
option.walkableHeight = m_agentHeight;
option.walkableRadius = m_agentRadius;
option.walkableClimb = m_agentMaxClimb;
option.bmin = m_pmesh.bmin;
option.bmax = m_pmesh.bmax;
option.cs = m_cellSize;
option.ch = m_cellHeight;
option.buildBvTree = true;
option.offMeshConCount = m_geom.GetOffMeshConnections().Count;
option.offMeshConVerts = new float[option.offMeshConCount * 6];
option.offMeshConRad = new float[option.offMeshConCount];
option.offMeshConDir = new int[option.offMeshConCount];
option.offMeshConAreas = new int[option.offMeshConCount];
option.offMeshConFlags = new int[option.offMeshConCount];
option.offMeshConUserID = new int[option.offMeshConCount];
for (int i = 0; i < option.offMeshConCount; i++)
{
DemoOffMeshConnection offMeshCon = m_geom.GetOffMeshConnections()[i];
for (int j = 0; j < 6; j++)
{
option.offMeshConVerts[6 * i + j] = offMeshCon.verts[j];
}
option.offMeshConRad[i] = offMeshCon.radius;
option.offMeshConDir[i] = offMeshCon.bidir ? 1 : 0;
option.offMeshConAreas[i] = offMeshCon.area;
option.offMeshConFlags[i] = offMeshCon.flags;
}
return option;
}
protected MeshData UpdateAreaAndFlags(MeshData meshData)
{
// Update poly flags from areas.
for (int i = 0; i < meshData.polys.Length; ++i)
{
if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WALKABLE)
{
meshData.polys[i].SetArea(SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND);
}
if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND
|| meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS
|| meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD)
{
meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_WALK;
}
else if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER)
{
meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_SWIM;
}
else if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_DOOR)
{
meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_DOOR;
}
}
return meshData;
}
}

View File

@ -1,66 +0,0 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using System.Collections.Immutable;
using System.Linq;
namespace DotRecast.Recast.Demo.Builder;
public class SampleAreaModifications
{
public const int SAMPLE_POLYAREA_TYPE_GROUND = 0x0;
public const int SAMPLE_POLYAREA_TYPE_WATER = 0x1;
public const int SAMPLE_POLYAREA_TYPE_ROAD = 0x2;
public const int SAMPLE_POLYAREA_TYPE_DOOR = 0x3;
public const int SAMPLE_POLYAREA_TYPE_GRASS = 0x4;
public const int SAMPLE_POLYAREA_TYPE_JUMP = 0x5;
public const int SAMPLE_POLYAREA_TYPE_JUMP_AUTO = 0x6;
public const int SAMPLE_POLYAREA_TYPE_WALKABLE = 0x3f;
public static readonly AreaModification SAMPLE_AREAMOD_WALKABLE = new(SAMPLE_POLYAREA_TYPE_WALKABLE);
public static readonly AreaModification SAMPLE_AREAMOD_GROUND = new(SAMPLE_POLYAREA_TYPE_GROUND);
public static readonly AreaModification SAMPLE_AREAMOD_WATER = new(SAMPLE_POLYAREA_TYPE_WATER);
public static readonly AreaModification SAMPLE_AREAMOD_ROAD = new(SAMPLE_POLYAREA_TYPE_ROAD);
public static readonly AreaModification SAMPLE_AREAMOD_GRASS = new(SAMPLE_POLYAREA_TYPE_GRASS);
public static readonly AreaModification SAMPLE_AREAMOD_DOOR = new(SAMPLE_POLYAREA_TYPE_DOOR);
public static readonly AreaModification SAMPLE_AREAMOD_JUMP = new(SAMPLE_POLYAREA_TYPE_JUMP);
public static readonly ImmutableArray<AreaModification> Values = ImmutableArray.Create(
SAMPLE_AREAMOD_WALKABLE,
SAMPLE_AREAMOD_GROUND,
SAMPLE_AREAMOD_WATER,
SAMPLE_AREAMOD_ROAD,
SAMPLE_AREAMOD_GRASS,
SAMPLE_AREAMOD_DOOR,
SAMPLE_AREAMOD_JUMP
);
public static AreaModification OfValue(int value)
{
return Values.FirstOrDefault(x => x.Value == value, SAMPLE_AREAMOD_GRASS);
}
public static readonly int SAMPLE_POLYFLAGS_WALK = 0x01; // Ability to walk (ground, grass, road)
public static readonly int SAMPLE_POLYFLAGS_SWIM = 0x02; // Ability to swim (water).
public static readonly int SAMPLE_POLYFLAGS_DOOR = 0x04; // Ability to move through doors.
public static readonly int SAMPLE_POLYFLAGS_JUMP = 0x08; // Ability to jump.
public static readonly int SAMPLE_POLYFLAGS_DISABLED = 0x10; // Disabled polygon
public static readonly int SAMPLE_POLYFLAGS_ALL = 0xffff; // All abilities.
}

View File

@ -1,72 +0,0 @@
/*
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using DotRecast.Detour;
using DotRecast.Recast.Demo.Geom;
namespace DotRecast.Recast.Demo.Builder;
public class SoloNavMeshBuilder : AbstractNavMeshBuilder
{
public Tuple<IList<RecastBuilderResult>, NavMesh> Build(DemoInputGeomProvider geom, PartitionType partitionType,
float cellSize, float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb,
float agentMaxSlope, int regionMinSize, int regionMergeSize, float edgeMaxLen, float edgeMaxError,
int vertsPerPoly, float detailSampleDist, float detailSampleMaxError, bool filterLowHangingObstacles,
bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
{
RecastBuilderResult rcResult = BuildRecastResult(geom, partitionType, cellSize, cellHeight, agentHeight,
agentRadius, agentMaxClimb, agentMaxSlope, regionMinSize, regionMergeSize, edgeMaxLen, edgeMaxError,
vertsPerPoly, detailSampleDist, detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans,
filterWalkableLowHeightSpans);
return Tuple.Create(ImmutableArray.Create(rcResult) as IList<RecastBuilderResult>,
BuildNavMesh(
BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult),
vertsPerPoly));
}
private NavMesh BuildNavMesh(MeshData meshData, int vertsPerPoly)
{
return new NavMesh(meshData, vertsPerPoly, 0);
}
private RecastBuilderResult BuildRecastResult(DemoInputGeomProvider geom, PartitionType partitionType, float cellSize,
float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb, float agentMaxSlope,
int regionMinSize, int regionMergeSize, float edgeMaxLen, float edgeMaxError, int vertsPerPoly,
float detailSampleDist, float detailSampleMaxError, bool filterLowHangingObstacles, bool filterLedgeSpans,
bool filterWalkableLowHeightSpans)
{
RecastConfig cfg = new RecastConfig(partitionType, cellSize, cellHeight, agentMaxSlope, filterLowHangingObstacles,
filterLedgeSpans, filterWalkableLowHeightSpans, agentHeight, agentRadius, agentMaxClimb, regionMinSize,
regionMergeSize, edgeMaxLen, edgeMaxError, vertsPerPoly, detailSampleDist, detailSampleMaxError,
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
RecastBuilder rcBuilder = new RecastBuilder();
return rcBuilder.Build(geom, bcfg);
}
private MeshData BuildMeshData(DemoInputGeomProvider geom, float cellSize, float cellHeight, float agentHeight,
float agentRadius, float agentMaxClimb, RecastBuilderResult result)
{
NavMeshDataCreateParams option = GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius,
agentMaxClimb, result);
return UpdateAreaAndFlags(NavMeshBuilder.CreateNavMeshData(option));
}
}

View File

@ -1,137 +0,0 @@
/*
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DotRecast.Core;
using DotRecast.Detour;
using DotRecast.Recast.Demo.Geom;
using static DotRecast.Core.RcMath;
namespace DotRecast.Recast.Demo.Builder;
public class TileNavMeshBuilder : AbstractNavMeshBuilder
{
public TileNavMeshBuilder()
{
}
public Tuple<IList<RecastBuilderResult>, NavMesh> Build(DemoInputGeomProvider geom, PartitionType partitionType,
float cellSize, float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb,
float agentMaxSlope, int regionMinSize, int regionMergeSize, float edgeMaxLen, float edgeMaxError,
int vertsPerPoly, float detailSampleDist, float detailSampleMaxError, bool filterLowHangingObstacles,
bool filterLedgeSpans, bool filterWalkableLowHeightSpans, int tileSize)
{
List<RecastBuilderResult> rcResult = BuildRecastResult(geom, partitionType, cellSize, cellHeight, agentHeight,
agentRadius, agentMaxClimb, agentMaxSlope, regionMinSize, regionMergeSize, edgeMaxLen, edgeMaxError,
vertsPerPoly, detailSampleDist, detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans,
filterWalkableLowHeightSpans, tileSize);
return Tuple.Create((IList<RecastBuilderResult>)rcResult,
BuildNavMesh(geom,
BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult),
cellSize, tileSize, vertsPerPoly));
}
private List<RecastBuilderResult> BuildRecastResult(DemoInputGeomProvider geom, PartitionType partitionType,
float cellSize, float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb,
float agentMaxSlope, int regionMinSize, int regionMergeSize, float edgeMaxLen, float edgeMaxError,
int vertsPerPoly, float detailSampleDist, float detailSampleMaxError, bool filterLowHangingObstacles,
bool filterLedgeSpans, bool filterWalkableLowHeightSpans, int tileSize)
{
RecastConfig cfg = new RecastConfig(true, tileSize, tileSize, RecastConfig.CalcBorder(agentRadius, cellSize),
partitionType, cellSize, cellHeight, agentMaxSlope, filterLowHangingObstacles, filterLedgeSpans,
filterWalkableLowHeightSpans, agentHeight, agentRadius, agentMaxClimb,
regionMinSize * regionMinSize * cellSize * cellSize,
regionMergeSize * regionMergeSize * cellSize * cellSize, edgeMaxLen, edgeMaxError, vertsPerPoly,
true, detailSampleDist, detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE);
RecastBuilder rcBuilder = new RecastBuilder();
return rcBuilder.BuildTiles(geom, cfg, Task.Factory);
}
private NavMesh BuildNavMesh(DemoInputGeomProvider geom, List<MeshData> meshData, float cellSize, int tileSize,
int vertsPerPoly)
{
NavMeshParams navMeshParams = new NavMeshParams();
navMeshParams.orig.x = geom.GetMeshBoundsMin().x;
navMeshParams.orig.y = geom.GetMeshBoundsMin().y;
navMeshParams.orig.z = geom.GetMeshBoundsMin().z;
navMeshParams.tileWidth = tileSize * cellSize;
navMeshParams.tileHeight = tileSize * cellSize;
// Snprintf(text, 64, "Tiles %d x %d", tw, th);
navMeshParams.maxTiles = GetMaxTiles(geom, cellSize, tileSize);
navMeshParams.maxPolys = GetMaxPolysPerTile(geom, cellSize, tileSize);
NavMesh navMesh = new NavMesh(navMeshParams, vertsPerPoly);
meshData.ForEach(md => navMesh.AddTile(md, 0, 0));
return navMesh;
}
public int GetMaxTiles(DemoInputGeomProvider geom, float cellSize, int tileSize)
{
int tileBits = GetTileBits(geom, cellSize, tileSize);
return 1 << tileBits;
}
public int GetMaxPolysPerTile(DemoInputGeomProvider geom, float cellSize, int tileSize)
{
int polyBits = 22 - GetTileBits(geom, cellSize, tileSize);
return 1 << polyBits;
}
private int GetTileBits(DemoInputGeomProvider geom, float cellSize, int tileSize)
{
Recast.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
int tw = (gw + tileSize - 1) / tileSize;
int th = (gh + tileSize - 1) / tileSize;
int tileBits = Math.Min(DetourCommon.Ilog2(DetourCommon.NextPow2(tw * th)), 14);
return tileBits;
}
public int[] GetTiles(DemoInputGeomProvider geom, float cellSize, int tileSize)
{
Recast.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
int tw = (gw + tileSize - 1) / tileSize;
int th = (gh + tileSize - 1) / tileSize;
return new int[] { tw, th };
}
private List<MeshData> BuildMeshData(DemoInputGeomProvider geom, float cellSize, float cellHeight, float agentHeight,
float agentRadius, float agentMaxClimb, List<RecastBuilderResult> results)
{
// Add tiles to nav mesh
List<MeshData> meshData = new();
foreach (RecastBuilderResult result in results)
{
int x = result.tileX;
int z = result.tileZ;
NavMeshDataCreateParams option = GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight,
agentRadius, agentMaxClimb, result);
option.tileX = x;
option.tileZ = z;
MeshData md = NavMeshBuilder.CreateNavMeshData(option);
if (md != null)
{
meshData.Add(UpdateAreaAndFlags(md));
}
}
return meshData;
}
}

View File

@ -20,7 +20,7 @@ freely, subject to the following restrictions:
using System;
using DotRecast.Core;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using Silk.NET.OpenGL;
namespace DotRecast.Recast.Demo.Draw;

View File

@ -21,8 +21,8 @@ freely, subject to the following restrictions:
using System.Collections.Generic;
using DotRecast.Core;
using DotRecast.Detour;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.Demo.Geom;
using DotRecast.Recast.DemoTool.Builder;
using DotRecast.Recast.DemoTool.Geom;
using DotRecast.Recast.Demo.UI;
namespace DotRecast.Recast.Demo.Draw;

View File

@ -24,7 +24,7 @@ using System.Numerics;
using DotRecast.Core;
using DotRecast.Detour;
using DotRecast.Detour.QueryResults;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using Silk.NET.OpenGL;
namespace DotRecast.Recast.Demo.Draw;

View File

@ -1,226 +0,0 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using DotRecast.Core;
using DotRecast.Recast.Geom;
namespace DotRecast.Recast.Demo.Geom;
public class DemoInputGeomProvider : IInputGeomProvider
{
public readonly float[] vertices;
public readonly int[] faces;
public readonly float[] normals;
private readonly RcVec3f bmin;
private readonly RcVec3f bmax;
private readonly List<ConvexVolume> _convexVolumes = new();
private readonly List<DemoOffMeshConnection> offMeshConnections = new();
private readonly TriMesh _mesh;
public DemoInputGeomProvider(List<float> vertexPositions, List<int> meshFaces) :
this(MapVertices(vertexPositions), MapFaces(meshFaces))
{
}
private static int[] MapFaces(List<int> meshFaces)
{
int[] faces = new int[meshFaces.Count];
for (int i = 0; i < faces.Length; i++)
{
faces[i] = meshFaces[i];
}
return faces;
}
private static float[] MapVertices(List<float> vertexPositions)
{
float[] vertices = new float[vertexPositions.Count];
for (int i = 0; i < vertices.Length; i++)
{
vertices[i] = vertexPositions[i];
}
return vertices;
}
public DemoInputGeomProvider(float[] vertices, int[] faces)
{
this.vertices = vertices;
this.faces = faces;
normals = new float[faces.Length];
CalculateNormals();
bmin = RcVec3f.Zero;
bmax = RcVec3f.Zero;
RcVec3f.Copy(ref bmin, vertices, 0);
RcVec3f.Copy(ref bmax, vertices, 0);
for (int i = 1; i < vertices.Length / 3; i++)
{
bmin.Min(vertices, i * 3);
bmax.Max(vertices, i * 3);
}
_mesh = new TriMesh(vertices, faces);
}
public RcVec3f GetMeshBoundsMin()
{
return bmin;
}
public RcVec3f GetMeshBoundsMax()
{
return bmax;
}
public void CalculateNormals()
{
for (int i = 0; i < faces.Length; i += 3)
{
int v0 = faces[i] * 3;
int v1 = faces[i + 1] * 3;
int v2 = faces[i + 2] * 3;
RcVec3f e0 = new RcVec3f();
RcVec3f e1 = new RcVec3f();
for (int j = 0; j < 3; ++j)
{
e0[j] = vertices[v1 + j] - vertices[v0 + j];
e1[j] = vertices[v2 + j] - vertices[v0 + j];
}
normals[i] = e0.y * e1.z - e0.z * e1.y;
normals[i + 1] = e0.z * e1.x - e0.x * e1.z;
normals[i + 2] = e0.x * e1.y - e0.y * e1.x;
float d = (float)Math.Sqrt(normals[i] * normals[i] + normals[i + 1] * normals[i + 1] + normals[i + 2] * normals[i + 2]);
if (d > 0)
{
d = 1.0f / d;
normals[i] *= d;
normals[i + 1] *= d;
normals[i + 2] *= d;
}
}
}
public IList<ConvexVolume> ConvexVolumes()
{
return _convexVolumes;
}
public IEnumerable<TriMesh> Meshes()
{
return ImmutableArray.Create(_mesh);
}
public List<DemoOffMeshConnection> GetOffMeshConnections()
{
return offMeshConnections;
}
public void AddOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags)
{
offMeshConnections.Add(new DemoOffMeshConnection(start, end, radius, bidir, area, flags));
}
public void RemoveOffMeshConnections(Predicate<DemoOffMeshConnection> filter)
{
//offMeshConnections.RetainAll(offMeshConnections.Stream().Filter(c -> !filter.Test(c)).Collect(ToList()));
offMeshConnections.RemoveAll(filter); // TODO : 확인 필요
}
public float? RaycastMesh(RcVec3f src, RcVec3f dst)
{
// Prune hit ray.
if (!Intersections.IsectSegAABB(src, dst, bmin, bmax, out var btmin, out var btmax))
{
return null;
}
float[] p = new float[2];
float[] q = new float[2];
p[0] = src.x + (dst.x - src.x) * btmin;
p[1] = src.z + (dst.z - src.z) * btmin;
q[0] = src.x + (dst.x - src.x) * btmax;
q[1] = src.z + (dst.z - src.z) * btmax;
List<ChunkyTriMeshNode> chunks = _mesh.chunkyTriMesh.GetChunksOverlappingSegment(p, q);
if (0 == chunks.Count)
{
return null;
}
float tmin = 1.0f;
bool hit = false;
foreach (ChunkyTriMeshNode chunk in chunks)
{
int[] tris = chunk.tris;
for (int j = 0; j < chunk.tris.Length; j += 3)
{
RcVec3f v1 = RcVec3f.Of(
vertices[tris[j] * 3],
vertices[tris[j] * 3 + 1],
vertices[tris[j] * 3 + 2]
);
RcVec3f v2 = RcVec3f.Of(
vertices[tris[j + 1] * 3],
vertices[tris[j + 1] * 3 + 1],
vertices[tris[j + 1] * 3 + 2]
);
RcVec3f v3 = RcVec3f.Of(
vertices[tris[j + 2] * 3],
vertices[tris[j + 2] * 3 + 1],
vertices[tris[j + 2] * 3 + 2]
);
float? t = Intersections.IntersectSegmentTriangle(src, dst, v1, v2, v3);
if (null != t)
{
if (t.Value < tmin)
{
tmin = t.Value;
}
hit = true;
}
}
}
return hit ? tmin : null;
}
public void AddConvexVolume(float[] verts, float minh, float maxh, AreaModification areaMod)
{
ConvexVolume volume = new ConvexVolume();
volume.verts = verts;
volume.hmin = minh;
volume.hmax = maxh;
volume.areaMod = areaMod;
_convexVolumes.Add(volume);
}
public void ClearConvexVolumes()
{
_convexVolumes.Clear();
}
}

View File

@ -35,9 +35,9 @@ using DotRecast.Core;
using DotRecast.Detour;
using DotRecast.Detour.Extras.Unity.Astar;
using DotRecast.Detour.Io;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using DotRecast.Recast.Demo.Draw;
using DotRecast.Recast.Demo.Geom;
using DotRecast.Recast.DemoTool.Geom;
using DotRecast.Recast.Demo.Tools;
using DotRecast.Recast.Demo.UI;
using static DotRecast.Core.RcMath;
@ -385,10 +385,12 @@ public class RecastDemo
var renderGl = _gl.GetStringS(GLEnum.Renderer);
var glslString = _gl.GetStringS(GLEnum.ShadingLanguageVersion);
Logger.Debug(vendor);
Logger.Debug(version);
Logger.Debug(renderGl);
Logger.Debug(glslString);
var workingDirectory = Directory.GetCurrentDirectory();
Logger.Information($"working directory - {workingDirectory}");
Logger.Information(vendor);
Logger.Information(version);
Logger.Information(renderGl);
Logger.Information(glslString);
DemoInputGeomProvider geom = LoadInputMesh(Loader.ToBytes("nav_test.obj"));

View File

@ -21,7 +21,7 @@ freely, subject to the following restrictions:
using System.Collections.Generic;
using DotRecast.Detour;
using DotRecast.Recast.Demo.Draw;
using DotRecast.Recast.Demo.Geom;
using DotRecast.Recast.DemoTool.Geom;
using DotRecast.Recast.Demo.UI;

View File

@ -22,9 +22,9 @@ using System;
using System.Collections.Generic;
using Silk.NET.Windowing;
using DotRecast.Core;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using DotRecast.Recast.Demo.Draw;
using DotRecast.Recast.Demo.Geom;
using DotRecast.Recast.DemoTool.Geom;
using ImGuiNET;
using static DotRecast.Recast.Demo.Draw.DebugDraw;
using static DotRecast.Recast.Demo.Draw.DebugDrawPrimitives;

View File

@ -24,7 +24,7 @@ using DotRecast.Core;
using DotRecast.Detour;
using DotRecast.Detour.Crowd;
using DotRecast.Detour.QueryResults;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using DotRecast.Recast.Demo.Draw;
using ImGuiNET;
using Silk.NET.Windowing;

View File

@ -1,6 +1,7 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -26,9 +27,9 @@ using DotRecast.Detour;
using DotRecast.Detour.Crowd;
using DotRecast.Detour.Crowd.Tracking;
using DotRecast.Detour.QueryResults;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using DotRecast.Recast.Demo.Draw;
using DotRecast.Recast.Demo.Geom;
using DotRecast.Recast.DemoTool.Geom;
using ImGuiNET;
using static DotRecast.Recast.Demo.Draw.DebugDraw;
using static DotRecast.Recast.Demo.Draw.DebugDrawPrimitives;

View File

@ -1,6 +1,6 @@
using System;
using System.IO;
using DotRecast.Recast.Demo.Geom;
using DotRecast.Recast.DemoTool.Geom;
namespace DotRecast.Recast.Demo.Tools;

View File

@ -30,9 +30,9 @@ using DotRecast.Core;
using DotRecast.Detour.Dynamic;
using DotRecast.Detour.Dynamic.Colliders;
using DotRecast.Detour.Dynamic.Io;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using DotRecast.Recast.Demo.Draw;
using DotRecast.Recast.Demo.Geom;
using DotRecast.Recast.DemoTool.Geom;
using DotRecast.Recast.Demo.Tools.Gizmos;
using DotRecast.Recast.Demo.UI;
using ImGuiNET;

View File

@ -21,9 +21,9 @@ using System.Linq;
using DotRecast.Core;
using Silk.NET.Windowing;
using DotRecast.Detour.Extras.Jumplink;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using DotRecast.Recast.Demo.Draw;
using DotRecast.Recast.Demo.Geom;
using DotRecast.Recast.DemoTool.Geom;
using ImGuiNET;
using static DotRecast.Core.RcMath;
using static DotRecast.Recast.Demo.Draw.DebugDraw;

View File

@ -21,9 +21,9 @@ freely, subject to the following restrictions:
using System;
using Silk.NET.Windowing;
using DotRecast.Core;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using DotRecast.Recast.Demo.Draw;
using DotRecast.Recast.Demo.Geom;
using DotRecast.Recast.DemoTool.Geom;
using ImGuiNET;
using static DotRecast.Recast.Demo.Draw.DebugDraw;

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using DotRecast.Core;
using DotRecast.Detour;
using DotRecast.Detour.QueryResults;
using DotRecast.Recast.Demo.Builder;
using DotRecast.Recast.DemoTool.Builder;
using DotRecast.Recast.Demo.Draw;
using ImGuiNET;
using static DotRecast.Core.RcMath;

View File

@ -1,6 +1,7 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View File

@ -0,0 +1,98 @@
using DotRecast.Detour;
using DotRecast.Recast.DemoTool.Geom;
namespace DotRecast.Recast.DemoTool.Builder
{
public abstract class AbstractNavMeshBuilder
{
protected NavMeshDataCreateParams GetNavMeshCreateParams(DemoInputGeomProvider m_geom, float m_cellSize,
float m_cellHeight, float m_agentHeight, float m_agentRadius, float m_agentMaxClimb,
RecastBuilderResult rcResult)
{
PolyMesh m_pmesh = rcResult.GetMesh();
PolyMeshDetail m_dmesh = rcResult.GetMeshDetail();
NavMeshDataCreateParams option = new NavMeshDataCreateParams();
for (int i = 0; i < m_pmesh.npolys; ++i)
{
m_pmesh.flags[i] = 1;
}
option.verts = m_pmesh.verts;
option.vertCount = m_pmesh.nverts;
option.polys = m_pmesh.polys;
option.polyAreas = m_pmesh.areas;
option.polyFlags = m_pmesh.flags;
option.polyCount = m_pmesh.npolys;
option.nvp = m_pmesh.nvp;
if (m_dmesh != null)
{
option.detailMeshes = m_dmesh.meshes;
option.detailVerts = m_dmesh.verts;
option.detailVertsCount = m_dmesh.nverts;
option.detailTris = m_dmesh.tris;
option.detailTriCount = m_dmesh.ntris;
}
option.walkableHeight = m_agentHeight;
option.walkableRadius = m_agentRadius;
option.walkableClimb = m_agentMaxClimb;
option.bmin = m_pmesh.bmin;
option.bmax = m_pmesh.bmax;
option.cs = m_cellSize;
option.ch = m_cellHeight;
option.buildBvTree = true;
option.offMeshConCount = m_geom.GetOffMeshConnections().Count;
option.offMeshConVerts = new float[option.offMeshConCount * 6];
option.offMeshConRad = new float[option.offMeshConCount];
option.offMeshConDir = new int[option.offMeshConCount];
option.offMeshConAreas = new int[option.offMeshConCount];
option.offMeshConFlags = new int[option.offMeshConCount];
option.offMeshConUserID = new int[option.offMeshConCount];
for (int i = 0; i < option.offMeshConCount; i++)
{
DemoOffMeshConnection offMeshCon = m_geom.GetOffMeshConnections()[i];
for (int j = 0; j < 6; j++)
{
option.offMeshConVerts[6 * i + j] = offMeshCon.verts[j];
}
option.offMeshConRad[i] = offMeshCon.radius;
option.offMeshConDir[i] = offMeshCon.bidir ? 1 : 0;
option.offMeshConAreas[i] = offMeshCon.area;
option.offMeshConFlags[i] = offMeshCon.flags;
}
return option;
}
protected MeshData UpdateAreaAndFlags(MeshData meshData)
{
// Update poly flags from areas.
for (int i = 0; i < meshData.polys.Length; ++i)
{
if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WALKABLE)
{
meshData.polys[i].SetArea(SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND);
}
if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GROUND
|| meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_GRASS
|| meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_ROAD)
{
meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_WALK;
}
else if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_WATER)
{
meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_SWIM;
}
else if (meshData.polys[i].GetArea() == SampleAreaModifications.SAMPLE_POLYAREA_TYPE_DOOR)
{
meshData.polys[i].flags = SampleAreaModifications.SAMPLE_POLYFLAGS_DOOR;
}
}
return meshData;
}
}
}

View File

@ -0,0 +1,68 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using System.Collections.Immutable;
using System.Linq;
namespace DotRecast.Recast.DemoTool.Builder
{
public class SampleAreaModifications
{
public const int SAMPLE_POLYAREA_TYPE_GROUND = 0x0;
public const int SAMPLE_POLYAREA_TYPE_WATER = 0x1;
public const int SAMPLE_POLYAREA_TYPE_ROAD = 0x2;
public const int SAMPLE_POLYAREA_TYPE_DOOR = 0x3;
public const int SAMPLE_POLYAREA_TYPE_GRASS = 0x4;
public const int SAMPLE_POLYAREA_TYPE_JUMP = 0x5;
public const int SAMPLE_POLYAREA_TYPE_JUMP_AUTO = 0x6;
public const int SAMPLE_POLYAREA_TYPE_WALKABLE = 0x3f;
public static readonly AreaModification SAMPLE_AREAMOD_WALKABLE = new AreaModification(SAMPLE_POLYAREA_TYPE_WALKABLE);
public static readonly AreaModification SAMPLE_AREAMOD_GROUND = new AreaModification(SAMPLE_POLYAREA_TYPE_GROUND);
public static readonly AreaModification SAMPLE_AREAMOD_WATER = new AreaModification(SAMPLE_POLYAREA_TYPE_WATER);
public static readonly AreaModification SAMPLE_AREAMOD_ROAD = new AreaModification(SAMPLE_POLYAREA_TYPE_ROAD);
public static readonly AreaModification SAMPLE_AREAMOD_GRASS = new AreaModification(SAMPLE_POLYAREA_TYPE_GRASS);
public static readonly AreaModification SAMPLE_AREAMOD_DOOR = new AreaModification(SAMPLE_POLYAREA_TYPE_DOOR);
public static readonly AreaModification SAMPLE_AREAMOD_JUMP = new AreaModification(SAMPLE_POLYAREA_TYPE_JUMP);
public static readonly ImmutableArray<AreaModification> Values = ImmutableArray.Create(
SAMPLE_AREAMOD_WALKABLE,
SAMPLE_AREAMOD_GROUND,
SAMPLE_AREAMOD_WATER,
SAMPLE_AREAMOD_ROAD,
SAMPLE_AREAMOD_GRASS,
SAMPLE_AREAMOD_DOOR,
SAMPLE_AREAMOD_JUMP
);
public static AreaModification OfValue(int value)
{
return Values.FirstOrDefault(x => x.Value == value) ?? SAMPLE_AREAMOD_GRASS;
}
public static readonly int SAMPLE_POLYFLAGS_WALK = 0x01; // Ability to walk (ground, grass, road)
public static readonly int SAMPLE_POLYFLAGS_SWIM = 0x02; // Ability to swim (water).
public static readonly int SAMPLE_POLYFLAGS_DOOR = 0x04; // Ability to move through doors.
public static readonly int SAMPLE_POLYFLAGS_JUMP = 0x08; // Ability to jump.
public static readonly int SAMPLE_POLYFLAGS_DISABLED = 0x10; // Disabled polygon
public static readonly int SAMPLE_POLYFLAGS_ALL = 0xffff; // All abilities.
}
}

View File

@ -0,0 +1,73 @@
/*
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using DotRecast.Detour;
using DotRecast.Recast.DemoTool.Geom;
namespace DotRecast.Recast.DemoTool.Builder
{
public class SoloNavMeshBuilder : AbstractNavMeshBuilder
{
public Tuple<IList<RecastBuilderResult>, NavMesh> Build(DemoInputGeomProvider geom, PartitionType partitionType,
float cellSize, float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb,
float agentMaxSlope, int regionMinSize, int regionMergeSize, float edgeMaxLen, float edgeMaxError,
int vertsPerPoly, float detailSampleDist, float detailSampleMaxError, bool filterLowHangingObstacles,
bool filterLedgeSpans, bool filterWalkableLowHeightSpans)
{
RecastBuilderResult rcResult = BuildRecastResult(geom, partitionType, cellSize, cellHeight, agentHeight,
agentRadius, agentMaxClimb, agentMaxSlope, regionMinSize, regionMergeSize, edgeMaxLen, edgeMaxError,
vertsPerPoly, detailSampleDist, detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans,
filterWalkableLowHeightSpans);
return Tuple.Create(ImmutableArray.Create(rcResult) as IList<RecastBuilderResult>,
BuildNavMesh(
BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult),
vertsPerPoly));
}
private NavMesh BuildNavMesh(MeshData meshData, int vertsPerPoly)
{
return new NavMesh(meshData, vertsPerPoly, 0);
}
private RecastBuilderResult BuildRecastResult(DemoInputGeomProvider geom, PartitionType partitionType, float cellSize,
float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb, float agentMaxSlope,
int regionMinSize, int regionMergeSize, float edgeMaxLen, float edgeMaxError, int vertsPerPoly,
float detailSampleDist, float detailSampleMaxError, bool filterLowHangingObstacles, bool filterLedgeSpans,
bool filterWalkableLowHeightSpans)
{
RecastConfig cfg = new RecastConfig(partitionType, cellSize, cellHeight, agentMaxSlope, filterLowHangingObstacles,
filterLedgeSpans, filterWalkableLowHeightSpans, agentHeight, agentRadius, agentMaxClimb, regionMinSize,
regionMergeSize, edgeMaxLen, edgeMaxError, vertsPerPoly, detailSampleDist, detailSampleMaxError,
SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE, true);
RecastBuilderConfig bcfg = new RecastBuilderConfig(cfg, geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax());
RecastBuilder rcBuilder = new RecastBuilder();
return rcBuilder.Build(geom, bcfg);
}
private MeshData BuildMeshData(DemoInputGeomProvider geom, float cellSize, float cellHeight, float agentHeight,
float agentRadius, float agentMaxClimb, RecastBuilderResult result)
{
NavMeshDataCreateParams option = GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight, agentRadius,
agentMaxClimb, result);
return UpdateAreaAndFlags(NavMeshBuilder.CreateNavMeshData(option));
}
}
}

View File

@ -0,0 +1,138 @@
/*
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using DotRecast.Core;
using DotRecast.Detour;
using DotRecast.Recast.DemoTool.Geom;
using static DotRecast.Core.RcMath;
namespace DotRecast.Recast.DemoTool.Builder
{
public class TileNavMeshBuilder : AbstractNavMeshBuilder
{
public TileNavMeshBuilder()
{
}
public Tuple<IList<RecastBuilderResult>, NavMesh> Build(DemoInputGeomProvider geom, PartitionType partitionType,
float cellSize, float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb,
float agentMaxSlope, int regionMinSize, int regionMergeSize, float edgeMaxLen, float edgeMaxError,
int vertsPerPoly, float detailSampleDist, float detailSampleMaxError, bool filterLowHangingObstacles,
bool filterLedgeSpans, bool filterWalkableLowHeightSpans, int tileSize)
{
List<RecastBuilderResult> rcResult = BuildRecastResult(geom, partitionType, cellSize, cellHeight, agentHeight,
agentRadius, agentMaxClimb, agentMaxSlope, regionMinSize, regionMergeSize, edgeMaxLen, edgeMaxError,
vertsPerPoly, detailSampleDist, detailSampleMaxError, filterLowHangingObstacles, filterLedgeSpans,
filterWalkableLowHeightSpans, tileSize);
return Tuple.Create((IList<RecastBuilderResult>)rcResult,
BuildNavMesh(geom,
BuildMeshData(geom, cellSize, cellHeight, agentHeight, agentRadius, agentMaxClimb, rcResult),
cellSize, tileSize, vertsPerPoly));
}
private List<RecastBuilderResult> BuildRecastResult(DemoInputGeomProvider geom, PartitionType partitionType,
float cellSize, float cellHeight, float agentHeight, float agentRadius, float agentMaxClimb,
float agentMaxSlope, int regionMinSize, int regionMergeSize, float edgeMaxLen, float edgeMaxError,
int vertsPerPoly, float detailSampleDist, float detailSampleMaxError, bool filterLowHangingObstacles,
bool filterLedgeSpans, bool filterWalkableLowHeightSpans, int tileSize)
{
RecastConfig cfg = new RecastConfig(true, tileSize, tileSize, RecastConfig.CalcBorder(agentRadius, cellSize),
partitionType, cellSize, cellHeight, agentMaxSlope, filterLowHangingObstacles, filterLedgeSpans,
filterWalkableLowHeightSpans, agentHeight, agentRadius, agentMaxClimb,
regionMinSize * regionMinSize * cellSize * cellSize,
regionMergeSize * regionMergeSize * cellSize * cellSize, edgeMaxLen, edgeMaxError, vertsPerPoly,
true, detailSampleDist, detailSampleMaxError, SampleAreaModifications.SAMPLE_AREAMOD_WALKABLE);
RecastBuilder rcBuilder = new RecastBuilder();
return rcBuilder.BuildTiles(geom, cfg, Task.Factory);
}
private NavMesh BuildNavMesh(DemoInputGeomProvider geom, List<MeshData> meshData, float cellSize, int tileSize,
int vertsPerPoly)
{
NavMeshParams navMeshParams = new NavMeshParams();
navMeshParams.orig.x = geom.GetMeshBoundsMin().x;
navMeshParams.orig.y = geom.GetMeshBoundsMin().y;
navMeshParams.orig.z = geom.GetMeshBoundsMin().z;
navMeshParams.tileWidth = tileSize * cellSize;
navMeshParams.tileHeight = tileSize * cellSize;
// Snprintf(text, 64, "Tiles %d x %d", tw, th);
navMeshParams.maxTiles = GetMaxTiles(geom, cellSize, tileSize);
navMeshParams.maxPolys = GetMaxPolysPerTile(geom, cellSize, tileSize);
NavMesh navMesh = new NavMesh(navMeshParams, vertsPerPoly);
meshData.ForEach(md => navMesh.AddTile(md, 0, 0));
return navMesh;
}
public int GetMaxTiles(DemoInputGeomProvider geom, float cellSize, int tileSize)
{
int tileBits = GetTileBits(geom, cellSize, tileSize);
return 1 << tileBits;
}
public int GetMaxPolysPerTile(DemoInputGeomProvider geom, float cellSize, int tileSize)
{
int polyBits = 22 - GetTileBits(geom, cellSize, tileSize);
return 1 << polyBits;
}
private int GetTileBits(DemoInputGeomProvider geom, float cellSize, int tileSize)
{
Recast.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
int tw = (gw + tileSize - 1) / tileSize;
int th = (gh + tileSize - 1) / tileSize;
int tileBits = Math.Min(DetourCommon.Ilog2(DetourCommon.NextPow2(tw * th)), 14);
return tileBits;
}
public int[] GetTiles(DemoInputGeomProvider geom, float cellSize, int tileSize)
{
Recast.CalcGridSize(geom.GetMeshBoundsMin(), geom.GetMeshBoundsMax(), cellSize, out var gw, out var gh);
int tw = (gw + tileSize - 1) / tileSize;
int th = (gh + tileSize - 1) / tileSize;
return new int[] { tw, th };
}
private List<MeshData> BuildMeshData(DemoInputGeomProvider geom, float cellSize, float cellHeight, float agentHeight,
float agentRadius, float agentMaxClimb, List<RecastBuilderResult> results)
{
// Add tiles to nav mesh
List<MeshData> meshData = new List<MeshData>();
foreach (RecastBuilderResult result in results)
{
int x = result.tileX;
int z = result.tileZ;
NavMeshDataCreateParams option = GetNavMeshCreateParams(geom, cellSize, cellHeight, agentHeight,
agentRadius, agentMaxClimb, result);
option.tileX = x;
option.tileZ = z;
MeshData md = NavMeshBuilder.CreateNavMeshData(option);
if (md != null)
{
meshData.Add(UpdateAreaAndFlags(md));
}
}
return meshData;
}
}
}

View File

@ -0,0 +1,228 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using DotRecast.Core;
using DotRecast.Recast.Geom;
namespace DotRecast.Recast.DemoTool.Geom
{
public class DemoInputGeomProvider : IInputGeomProvider
{
public readonly float[] vertices;
public readonly int[] faces;
public readonly float[] normals;
private readonly RcVec3f bmin;
private readonly RcVec3f bmax;
private readonly List<ConvexVolume> _convexVolumes = new List<ConvexVolume>();
private readonly List<DemoOffMeshConnection> offMeshConnections = new List<DemoOffMeshConnection>();
private readonly TriMesh _mesh;
public DemoInputGeomProvider(List<float> vertexPositions, List<int> meshFaces) :
this(MapVertices(vertexPositions), MapFaces(meshFaces))
{
}
private static int[] MapFaces(List<int> meshFaces)
{
int[] faces = new int[meshFaces.Count];
for (int i = 0; i < faces.Length; i++)
{
faces[i] = meshFaces[i];
}
return faces;
}
private static float[] MapVertices(List<float> vertexPositions)
{
float[] vertices = new float[vertexPositions.Count];
for (int i = 0; i < vertices.Length; i++)
{
vertices[i] = vertexPositions[i];
}
return vertices;
}
public DemoInputGeomProvider(float[] vertices, int[] faces)
{
this.vertices = vertices;
this.faces = faces;
normals = new float[faces.Length];
CalculateNormals();
bmin = RcVec3f.Zero;
bmax = RcVec3f.Zero;
RcVec3f.Copy(ref bmin, vertices, 0);
RcVec3f.Copy(ref bmax, vertices, 0);
for (int i = 1; i < vertices.Length / 3; i++)
{
bmin.Min(vertices, i * 3);
bmax.Max(vertices, i * 3);
}
_mesh = new TriMesh(vertices, faces);
}
public RcVec3f GetMeshBoundsMin()
{
return bmin;
}
public RcVec3f GetMeshBoundsMax()
{
return bmax;
}
public void CalculateNormals()
{
for (int i = 0; i < faces.Length; i += 3)
{
int v0 = faces[i] * 3;
int v1 = faces[i + 1] * 3;
int v2 = faces[i + 2] * 3;
RcVec3f e0 = new RcVec3f();
RcVec3f e1 = new RcVec3f();
for (int j = 0; j < 3; ++j)
{
e0[j] = vertices[v1 + j] - vertices[v0 + j];
e1[j] = vertices[v2 + j] - vertices[v0 + j];
}
normals[i] = e0.y * e1.z - e0.z * e1.y;
normals[i + 1] = e0.z * e1.x - e0.x * e1.z;
normals[i + 2] = e0.x * e1.y - e0.y * e1.x;
float d = (float)Math.Sqrt(normals[i] * normals[i] + normals[i + 1] * normals[i + 1] + normals[i + 2] * normals[i + 2]);
if (d > 0)
{
d = 1.0f / d;
normals[i] *= d;
normals[i + 1] *= d;
normals[i + 2] *= d;
}
}
}
public IList<ConvexVolume> ConvexVolumes()
{
return _convexVolumes;
}
public IEnumerable<TriMesh> Meshes()
{
return ImmutableArray.Create(_mesh);
}
public List<DemoOffMeshConnection> GetOffMeshConnections()
{
return offMeshConnections;
}
public void AddOffMeshConnection(RcVec3f start, RcVec3f end, float radius, bool bidir, int area, int flags)
{
offMeshConnections.Add(new DemoOffMeshConnection(start, end, radius, bidir, area, flags));
}
public void RemoveOffMeshConnections(Predicate<DemoOffMeshConnection> filter)
{
//offMeshConnections.RetainAll(offMeshConnections.Stream().Filter(c -> !filter.Test(c)).Collect(ToList()));
offMeshConnections.RemoveAll(filter); // TODO : 확인 필요
}
public float? RaycastMesh(RcVec3f src, RcVec3f dst)
{
// Prune hit ray.
if (!Intersections.IsectSegAABB(src, dst, bmin, bmax, out var btmin, out var btmax))
{
return null;
}
float[] p = new float[2];
float[] q = new float[2];
p[0] = src.x + (dst.x - src.x) * btmin;
p[1] = src.z + (dst.z - src.z) * btmin;
q[0] = src.x + (dst.x - src.x) * btmax;
q[1] = src.z + (dst.z - src.z) * btmax;
List<ChunkyTriMeshNode> chunks = _mesh.chunkyTriMesh.GetChunksOverlappingSegment(p, q);
if (0 == chunks.Count)
{
return null;
}
float? tmin = 1.0f;
bool hit = false;
foreach (ChunkyTriMeshNode chunk in chunks)
{
int[] tris = chunk.tris;
for (int j = 0; j < chunk.tris.Length; j += 3)
{
RcVec3f v1 = RcVec3f.Of(
vertices[tris[j] * 3],
vertices[tris[j] * 3 + 1],
vertices[tris[j] * 3 + 2]
);
RcVec3f v2 = RcVec3f.Of(
vertices[tris[j + 1] * 3],
vertices[tris[j + 1] * 3 + 1],
vertices[tris[j + 1] * 3 + 2]
);
RcVec3f v3 = RcVec3f.Of(
vertices[tris[j + 2] * 3],
vertices[tris[j + 2] * 3 + 1],
vertices[tris[j + 2] * 3 + 2]
);
float? t = Intersections.IntersectSegmentTriangle(src, dst, v1, v2, v3);
if (null != t)
{
if (t.Value < tmin)
{
tmin = t.Value;
}
hit = true;
}
}
}
return hit
? tmin
: null;
}
public void AddConvexVolume(float[] verts, float minh, float maxh, AreaModification areaMod)
{
ConvexVolume volume = new ConvexVolume();
volume.verts = verts;
volume.hmin = minh;
volume.hmax = maxh;
volume.areaMod = areaMod;
_convexVolumes.Add(volume);
}
public void ClearConvexVolumes()
{
_convexVolumes.Clear();
}
}
}

View File

@ -20,8 +20,8 @@ freely, subject to the following restrictions:
using DotRecast.Core;
namespace DotRecast.Recast.Demo.Geom;
namespace DotRecast.Recast.DemoTool.Geom
{
public class DemoOffMeshConnection
{
public readonly float[] verts;
@ -45,3 +45,4 @@ public class DemoOffMeshConnection
this.flags = flags;
}
}
}

View File

@ -1,6 +1,7 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
Recast4J Copyright (c) 2015 Piotr Piastucki piotr@jtilia.org
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages

View File

@ -1,6 +1,7 @@
/*
Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
recast4j copyright (c) 2021 Piotr Piastucki piotr@jtilia.org
DotRecast Copyright (c) 2023 Choi Ikpil ikpil@naver.com
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages