This commit is contained in:
ikpil 2023-09-09 22:09:14 +09:00
parent db13598295
commit 303f194fe7
10 changed files with 986 additions and 1243 deletions

View File

@ -54,6 +54,91 @@ public class ConvexVolumeSampleTool : ISampleTool
_tool = new RcConvexVolumeTool(); _tool = new RcConvexVolumeTool();
} }
public void Layout()
{
ImGui.SliderFloat("Shape Height", ref boxHeight, 0.1f, 20f, "%.1f");
ImGui.SliderFloat("Shape Descent", ref boxDescent, 0.1f, 20f, "%.1f");
ImGui.SliderFloat("Poly Offset", ref polyOffset, 0.1f, 10f, "%.1f");
ImGui.NewLine();
ImGui.Text("Area Type");
ImGui.Separator();
int prevAreaTypeValue = areaTypeValue;
ImGui.RadioButton("Ground", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_GROUND.Value);
ImGui.RadioButton("Water", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_WATER.Value);
ImGui.RadioButton("Road", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_ROAD.Value);
ImGui.RadioButton("Door", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_DOOR.Value);
ImGui.RadioButton("Grass", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_GRASS.Value);
ImGui.RadioButton("Jump", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_JUMP.Value);
ImGui.NewLine();
if (prevAreaTypeValue != areaTypeValue)
{
areaType = SampleAreaModifications.OfValue(areaTypeValue);
}
if (ImGui.Button("Clear Shape"))
{
hull.Clear();
pts.Clear();
}
if (ImGui.Button("Remove All"))
{
hull.Clear();
pts.Clear();
var geom = _sample.GetInputGeom();
if (geom != null)
{
geom.ClearConvexVolumes();
}
}
}
public void HandleRender(NavMeshRenderer renderer)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
// Find height extent of the shape.
float minh = float.MaxValue, maxh = 0;
for (int i = 0; i < pts.Count; ++i)
{
minh = Math.Min(minh, pts[i].y);
}
minh -= boxDescent;
maxh = minh + boxHeight;
dd.Begin(POINTS, 4.0f);
for (int i = 0; i < pts.Count; ++i)
{
int col = DuRGBA(255, 255, 255, 255);
if (i == pts.Count - 1)
{
col = DuRGBA(240, 32, 16, 255);
}
dd.Vertex(pts[i].x, pts[i].y + 0.1f, pts[i].z, col);
}
dd.End();
dd.Begin(LINES, 2.0f);
for (int i = 0, j = hull.Count - 1; i < hull.Count; j = i++)
{
int vi = hull[j];
int vj = hull[i];
dd.Vertex(pts[vj].x, minh, pts[vj].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vi].x, minh, pts[vi].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vj].x, maxh, pts[vj].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vi].x, maxh, pts[vi].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vj].x, minh, pts[vj].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vj].x, maxh, pts[vj].z, DuRGBA(255, 255, 255, 64));
}
dd.End();
}
public IRcToolable GetTool() public IRcToolable GetTool()
{ {
return _tool; return _tool;
@ -115,90 +200,6 @@ public class ConvexVolumeSampleTool : ISampleTool
} }
} }
public void HandleRender(NavMeshRenderer renderer)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
// Find height extent of the shape.
float minh = float.MaxValue, maxh = 0;
for (int i = 0; i < pts.Count; ++i)
{
minh = Math.Min(minh, pts[i].y);
}
minh -= boxDescent;
maxh = minh + boxHeight;
dd.Begin(POINTS, 4.0f);
for (int i = 0; i < pts.Count; ++i)
{
int col = DuRGBA(255, 255, 255, 255);
if (i == pts.Count - 1)
{
col = DuRGBA(240, 32, 16, 255);
}
dd.Vertex(pts[i].x, pts[i].y + 0.1f, pts[i].z, col);
}
dd.End();
dd.Begin(LINES, 2.0f);
for (int i = 0, j = hull.Count - 1; i < hull.Count; j = i++)
{
int vi = hull[j];
int vj = hull[i];
dd.Vertex(pts[vj].x, minh, pts[vj].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vi].x, minh, pts[vi].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vj].x, maxh, pts[vj].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vi].x, maxh, pts[vi].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vj].x, minh, pts[vj].z, DuRGBA(255, 255, 255, 64));
dd.Vertex(pts[vj].x, maxh, pts[vj].z, DuRGBA(255, 255, 255, 64));
}
dd.End();
}
public void Layout()
{
ImGui.SliderFloat("Shape Height", ref boxHeight, 0.1f, 20f, "%.1f");
ImGui.SliderFloat("Shape Descent", ref boxDescent, 0.1f, 20f, "%.1f");
ImGui.SliderFloat("Poly Offset", ref polyOffset, 0.1f, 10f, "%.1f");
ImGui.NewLine();
ImGui.Text("Area Type");
ImGui.Separator();
int prevAreaTypeValue = areaTypeValue;
ImGui.RadioButton("Ground", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_GROUND.Value);
ImGui.RadioButton("Water", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_WATER.Value);
ImGui.RadioButton("Road", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_ROAD.Value);
ImGui.RadioButton("Door", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_DOOR.Value);
ImGui.RadioButton("Grass", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_GRASS.Value);
ImGui.RadioButton("Jump", ref areaTypeValue, SampleAreaModifications.SAMPLE_AREAMOD_JUMP.Value);
ImGui.NewLine();
if (prevAreaTypeValue != areaTypeValue)
{
areaType = SampleAreaModifications.OfValue(areaTypeValue);
}
if (ImGui.Button("Clear Shape"))
{
hull.Clear();
pts.Clear();
}
if (ImGui.Button("Remove All"))
{
hull.Clear();
pts.Clear();
var geom = _sample.GetInputGeom();
if (geom != null)
{
geom.ClearConvexVolumes();
}
}
}
public void HandleUpdate(float dt) public void HandleUpdate(float dt)
{ {

View File

@ -1,6 +0,0 @@
namespace DotRecast.Recast.Demo.Tools;
public class CrowdFlowTool
{
// ...
}

View File

@ -65,6 +65,124 @@ public class CrowdProfilingSampleTool : ISampleTool
_tool = new(); _tool = new();
} }
public void Layout()
{
var prevOptimizeVis = _option.optimizeVis;
var prevOptimizeTopo = _option.optimizeTopo;
var prevAnticipateTurns = _option.anticipateTurns;
var prevObstacleAvoidance = _option.obstacleAvoidance;
var prevSeparation = _option.separation;
var prevObstacleAvoidanceType = _option.obstacleAvoidanceType;
var prevSeparationWeight = _option.separationWeight;
ImGui.Text("Options");
ImGui.Separator();
ImGui.Checkbox("Optimize Visibility", ref _option.optimizeVis);
ImGui.Checkbox("Optimize Topology", ref _option.optimizeTopo);
ImGui.Checkbox("Anticipate Turns", ref _option.anticipateTurns);
ImGui.Checkbox("Obstacle Avoidance", ref _option.obstacleAvoidance);
ImGui.SliderInt("Avoidance Quality", ref _option.obstacleAvoidanceType, 0, 3);
ImGui.Checkbox("Separation", ref _option.separation);
ImGui.SliderFloat("Separation Weight", ref _option.separationWeight, 0f, 20f, "%.2f");
ImGui.NewLine();
if (prevOptimizeVis != _option.optimizeVis || prevOptimizeTopo != _option.optimizeTopo
|| prevAnticipateTurns != _option.anticipateTurns
|| prevObstacleAvoidance != _option.obstacleAvoidance
|| prevSeparation != _option.separation
|| prevObstacleAvoidanceType != _option.obstacleAvoidanceType
|| !prevSeparationWeight.Equals(_option.separationWeight))
{
UpdateAgentParams();
}
ImGui.Text("Simulation Options");
ImGui.Separator();
ImGui.SliderInt("Agents", ref agents, 0, 10000);
ImGui.SliderInt("Random Seed", ref randomSeed, 0, 1024);
ImGui.SliderInt("Number of Zones", ref numberOfZones, 0, 10);
ImGui.SliderFloat("Zone Radius", ref zoneRadius, 0, 100, "%.0f");
ImGui.SliderFloat("Mobs %", ref percentMobs, 0, 100, "%.0f");
ImGui.SliderFloat("Travellers %", ref percentTravellers, 0, 100, "%.0f");
ImGui.NewLine();
ImGui.Text("Crowd Options");
ImGui.Separator();
ImGui.SliderInt("Path Queue Size", ref pathQueueSize, 0, 1024);
ImGui.SliderInt("Max Iterations", ref maxIterations, 0, 4000);
ImGui.NewLine();
if (ImGui.Button("Start Crowd Profiling"))
{
StartProfiling();
}
ImGui.Text("Times");
ImGui.Separator();
if (crowd != null)
{
ImGui.Text($"Max time to enqueue request: {crowd.Telemetry().MaxTimeToEnqueueRequest()} s");
ImGui.Text($"Max time to find path: {crowd.Telemetry().MaxTimeToFindPath()} s");
var timings = crowd.Telemetry().ToExecutionTimings();
foreach (var rtt in timings)
{
ImGui.Text($"{rtt.Key}: {rtt.Micros} us");
}
ImGui.Text($"Update Time: {crowdUpdateTime} ms");
}
}
public void HandleRender(NavMeshRenderer renderer)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
dd.DepthMask(false);
if (crowd != null)
{
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
float radius = ag.option.radius;
RcVec3f pos = ag.npos;
dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, DuRGBA(0, 0, 0, 32), 2.0f);
}
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
CrowdAgentData crowAgentData = (CrowdAgentData)ag.option.userData;
float height = ag.option.height;
float radius = ag.option.radius;
RcVec3f pos = ag.npos;
int col = DuRGBA(220, 220, 220, 128);
if (crowAgentData.type == CrowdAgentType.TRAVELLER)
{
col = DuRGBA(100, 160, 100, 128);
}
if (crowAgentData.type == CrowdAgentType.VILLAGER)
{
col = DuRGBA(120, 80, 160, 128);
}
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|| ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE)
col = DuLerpCol(col, DuRGBA(255, 255, 32, 128), 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH)
col = DuLerpCol(col, DuRGBA(255, 64, 32, 128), 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
col = DuRGBA(255, 32, 16, 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128);
dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height,
pos.z + radius, col);
}
}
dd.DepthMask(true);
}
public void SetSample(DemoSample sample) public void SetSample(DemoSample sample)
{ {
_sample = sample; _sample = sample;
@ -105,81 +223,6 @@ public class CrowdProfilingSampleTool : ISampleTool
return _tool; return _tool;
} }
public void Layout()
{
ImGui.Text("Options");
ImGui.Separator();
bool m_optimizeVis = _option.optimizeVis;
bool m_optimizeTopo = _option.optimizeTopo;
bool m_anticipateTurns = _option.anticipateTurns;
bool m_obstacleAvoidance = _option.obstacleAvoidance;
bool m_separation = _option.separation;
int m_obstacleAvoidanceType = _option.obstacleAvoidanceType;
float m_separationWeight = _option.separationWeight;
ImGui.Checkbox("Optimize Visibility", ref _option.optimizeVis);
ImGui.Checkbox("Optimize Topology", ref _option.optimizeTopo);
ImGui.Checkbox("Anticipate Turns", ref _option.anticipateTurns);
ImGui.Checkbox("Obstacle Avoidance", ref _option.obstacleAvoidance);
ImGui.SliderInt("Avoidance Quality", ref _option.obstacleAvoidanceType, 0, 3);
ImGui.Checkbox("Separation", ref _option.separation);
ImGui.SliderFloat("Separation Weight", ref _option.separationWeight, 0f, 20f, "%.2f");
ImGui.NewLine();
if (m_optimizeVis != _option.optimizeVis || m_optimizeTopo != _option.optimizeTopo
|| m_anticipateTurns != _option.anticipateTurns || m_obstacleAvoidance != _option.obstacleAvoidance
|| m_separation != _option.separation
|| m_obstacleAvoidanceType != _option.obstacleAvoidanceType
|| m_separationWeight != _option.separationWeight)
{
UpdateAgentParams();
}
ImGui.Text("Simulation Options");
ImGui.Separator();
ImGui.SliderInt("Agents", ref agents, 0, 10000);
ImGui.SliderInt("Random Seed", ref randomSeed, 0, 1024);
ImGui.SliderInt("Number of Zones", ref numberOfZones, 0, 10);
ImGui.SliderFloat("Zone Radius", ref zoneRadius, 0, 100, "%.0f");
ImGui.SliderFloat("Mobs %", ref percentMobs, 0, 100, "%.0f");
ImGui.SliderFloat("Travellers %", ref percentTravellers, 0, 100, "%.0f");
ImGui.NewLine();
ImGui.Text("Crowd Options");
ImGui.Separator();
ImGui.SliderInt("Path Queue Size", ref pathQueueSize, 0, 1024);
ImGui.SliderInt("Max Iterations", ref maxIterations, 0, 4000);
ImGui.NewLine();
if (ImGui.Button("Start Crowd Profiling"))
{
StartProfiling();
}
if (m_optimizeVis != _option.optimizeVis || m_optimizeTopo != _option.optimizeTopo
|| m_anticipateTurns != _option.anticipateTurns || m_obstacleAvoidance != _option.obstacleAvoidance
|| m_separation != _option.separation
|| m_obstacleAvoidanceType != _option.obstacleAvoidanceType
|| m_separationWeight != _option.separationWeight)
{
UpdateAgentParams();
}
ImGui.Text("Times");
ImGui.Separator();
if (crowd != null)
{
ImGui.Text($"Max time to enqueue request: {crowd.Telemetry().MaxTimeToEnqueueRequest()} s");
ImGui.Text($"Max time to find path: {crowd.Telemetry().MaxTimeToFindPath()} s");
var timings = crowd.Telemetry().ToExecutionTimings();
foreach (var rtt in timings)
{
ImGui.Text($"{rtt.Key}: {rtt.Micros} us");
}
ImGui.Text($"Update Time: {crowdUpdateTime} ms");
}
}
public void HandleClick(RcVec3f s, RcVec3f p, bool shift) public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
{ {
@ -435,55 +478,6 @@ public class CrowdProfilingSampleTool : ISampleTool
} }
} }
public void HandleRender(NavMeshRenderer renderer)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
dd.DepthMask(false);
if (crowd != null)
{
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
float radius = ag.option.radius;
RcVec3f pos = ag.npos;
dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, DuRGBA(0, 0, 0, 32), 2.0f);
}
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
CrowdAgentData crowAgentData = (CrowdAgentData)ag.option.userData;
float height = ag.option.height;
float radius = ag.option.radius;
RcVec3f pos = ag.npos;
int col = DuRGBA(220, 220, 220, 128);
if (crowAgentData.type == CrowdAgentType.TRAVELLER)
{
col = DuRGBA(100, 160, 100, 128);
}
if (crowAgentData.type == CrowdAgentType.VILLAGER)
{
col = DuRGBA(120, 80, 160, 128);
}
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|| ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE)
col = DuLerpCol(col, DuRGBA(255, 255, 32, 128), 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH)
col = DuLerpCol(col, DuRGBA(255, 64, 32, 128), 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
col = DuRGBA(255, 32, 16, 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128);
dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height,
pos.z + radius, col);
}
}
dd.DepthMask(true);
}
public void HandleUpdate(float dt) public void HandleUpdate(float dt)
{ {

View File

@ -44,7 +44,7 @@ public class CrowdSampleTool : ISampleTool
private readonly CrowdOption _option = new CrowdOption(); private readonly CrowdOption _option = new CrowdOption();
private DtNavMesh m_nav; private DtNavMesh m_nav;
private DtCrowd crowd; private DtCrowd crowd;
private readonly DtCrowdAgentDebugInfo m_agentDebug = new DtCrowdAgentDebugInfo(); private readonly DtCrowdAgentDebugInfo _agentDebug = new DtCrowdAgentDebugInfo();
private readonly Dictionary<long, CrowdAgentTrail> m_trails = new(); private readonly Dictionary<long, CrowdAgentTrail> m_trails = new();
private RcVec3f m_targetPos; private RcVec3f m_targetPos;
@ -53,28 +53,140 @@ public class CrowdSampleTool : ISampleTool
private int m_modeIdx = CrowdToolMode.CREATE.Idx; private int m_modeIdx = CrowdToolMode.CREATE.Idx;
private long crowdUpdateTime; private long crowdUpdateTime;
private int m_expandSelectedDebugDraw = 1; private int _expandSelectedDebugDraw = 1;
private bool m_showCorners; private bool _showCorners;
private bool m_showCollisionSegments; private bool _showCollisionSegments;
private bool m_showPath; private bool _showPath;
private bool m_showVO; private bool _showVO;
private bool m_showOpt; private bool _showOpt;
private bool m_showNeis; private bool _showNeis;
private int m_expandDebugDraw = 0;
private bool m_showLabels;
private bool m_showGrid;
private bool m_showNodes;
private bool m_showPerfGraph;
private bool m_showDetailAll;
private int _expandDebugDraw = 0;
private bool _showLabels;
private bool _showGrid;
private bool _showNodes;
private bool _showPerfGraph;
private bool _showDetailAll;
public CrowdSampleTool() public CrowdSampleTool()
{ {
m_agentDebug.vod = new DtObstacleAvoidanceDebugData(2048); _agentDebug.vod = new DtObstacleAvoidanceDebugData(2048);
_tool = new(); _tool = new();
} }
public void Layout()
{
ImGui.Text($"Crowd Tool Mode");
ImGui.Separator();
CrowdToolMode previousToolMode = m_mode;
ImGui.RadioButton(CrowdToolMode.CREATE.Label, ref m_modeIdx, CrowdToolMode.CREATE.Idx);
ImGui.RadioButton(CrowdToolMode.MOVE_TARGET.Label, ref m_modeIdx, CrowdToolMode.MOVE_TARGET.Idx);
ImGui.RadioButton(CrowdToolMode.SELECT.Label, ref m_modeIdx, CrowdToolMode.SELECT.Idx);
ImGui.RadioButton(CrowdToolMode.TOGGLE_POLYS.Label, ref m_modeIdx, CrowdToolMode.TOGGLE_POLYS.Idx);
ImGui.NewLine();
if (previousToolMode.Idx != m_modeIdx)
{
m_mode = CrowdToolMode.Values[m_modeIdx];
}
var prevOptimizeVis = _option.optimizeVis;
var prevOptimizeTopo = _option.optimizeTopo;
var prevAnticipateTurns = _option.anticipateTurns;
var prevObstacleAvoidance = _option.obstacleAvoidance;
var prevSeparation = _option.separation;
var prevObstacleAvoidanceType = _option.obstacleAvoidanceType;
var prevSeparationWeight = _option.separationWeight;
ImGui.Text("Options");
ImGui.Separator();
ImGui.Checkbox("Optimize Visibility", ref _option.optimizeVis);
ImGui.Checkbox("Optimize Topology", ref _option.optimizeTopo);
ImGui.Checkbox("Anticipate Turns", ref _option.anticipateTurns);
ImGui.Checkbox("Obstacle Avoidance", ref _option.obstacleAvoidance);
ImGui.SliderInt("Avoidance Quality", ref _option.obstacleAvoidanceType, 0, 3);
ImGui.Checkbox("Separation", ref _option.separation);
ImGui.SliderFloat("Separation Weight", ref _option.separationWeight, 0f, 20f, "%.2f");
ImGui.NewLine();
if (prevOptimizeVis != _option.optimizeVis || prevOptimizeTopo != _option.optimizeTopo
|| prevAnticipateTurns != _option.anticipateTurns
|| prevObstacleAvoidance != _option.obstacleAvoidance
|| prevSeparation != _option.separation
|| prevObstacleAvoidanceType != _option.obstacleAvoidanceType
|| !prevSeparationWeight.Equals(_option.separationWeight))
{
UpdateAgentParams();
}
ImGui.Text("Selected Debug Draw");
ImGui.Separator();
ImGui.Checkbox("Show Corners", ref _showCorners);
ImGui.Checkbox("Show Collision Segs", ref _showCollisionSegments);
ImGui.Checkbox("Show Path", ref _showPath);
ImGui.Checkbox("Show VO", ref _showVO);
ImGui.Checkbox("Show Path Optimization", ref _showOpt);
ImGui.Checkbox("Show Neighbours", ref _showNeis);
ImGui.NewLine();
ImGui.Text("Debug Draw");
ImGui.Separator();
ImGui.Checkbox("Show Proximity Grid", ref _showGrid);
ImGui.Checkbox("Show Nodes", ref _showNodes);
ImGui.Text($"Update Time: {crowdUpdateTime} ms");
}
public void HandleRender(NavMeshRenderer renderer)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
dd.DepthMask(false);
if (crowd != null)
{
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
float radius = ag.option.radius;
RcVec3f pos = ag.npos;
dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, DuRGBA(0, 0, 0, 32), 2.0f);
}
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
CrowdAgentData crowAgentData = (CrowdAgentData)ag.option.userData;
float height = ag.option.height;
float radius = ag.option.radius;
RcVec3f pos = ag.npos;
int col = DuRGBA(220, 220, 220, 128);
if (crowAgentData.type == CrowdAgentType.TRAVELLER)
{
col = DuRGBA(100, 160, 100, 128);
}
if (crowAgentData.type == CrowdAgentType.VILLAGER)
{
col = DuRGBA(120, 80, 160, 128);
}
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|| ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE)
col = DuLerpCol(col, DuRGBA(255, 255, 32, 128), 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH)
col = DuLerpCol(col, DuRGBA(255, 64, 32, 128), 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
col = DuRGBA(255, 32, 16, 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128);
dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height,
pos.z + radius, col);
}
}
dd.DepthMask(true);
}
public IRcToolable GetTool() public IRcToolable GetTool()
{ {
return _tool; return _tool;
@ -96,9 +208,11 @@ public class CrowdSampleTool : ISampleTool
m_nav = navMesh; m_nav = navMesh;
DtCrowdConfig config = new DtCrowdConfig(settings.agentRadius); DtCrowdConfig config = new DtCrowdConfig(settings.agentRadius);
crowd = new DtCrowd(config, navMesh, __ => new DtQueryDefaultFilter(
crowd = new DtCrowd(config, navMesh, __ => new DtQueryDefaultFilter(SampleAreaModifications.SAMPLE_POLYFLAGS_ALL, SampleAreaModifications.SAMPLE_POLYFLAGS_ALL,
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f })); SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f })
);
// Setup local avoidance option to different qualities. // Setup local avoidance option to different qualities.
// Use mostly default settings, copy from dtCrowd. // Use mostly default settings, copy from dtCrowd.
@ -167,7 +281,7 @@ public class CrowdSampleTool : ISampleTool
{ {
// Highlight // Highlight
DtCrowdAgent ahit = HitTestAgents(s, p); DtCrowdAgent ahit = HitTestAgents(s, p);
HilightAgent(ahit); HighlightAgent(ahit);
} }
else if (m_mode == CrowdToolMode.TOGGLE_POLYS) else if (m_mode == CrowdToolMode.TOGGLE_POLYS)
{ {
@ -193,9 +307,9 @@ public class CrowdSampleTool : ISampleTool
private void RemoveAgent(DtCrowdAgent agent) private void RemoveAgent(DtCrowdAgent agent)
{ {
crowd.RemoveAgent(agent); crowd.RemoveAgent(agent);
if (agent == m_agentDebug.agent) if (agent == _agentDebug.agent)
{ {
m_agentDebug.agent = null; _agentDebug.agent = null;
} }
} }
@ -292,10 +406,10 @@ public class CrowdSampleTool : ISampleTool
if (adjust) if (adjust)
{ {
// Request velocity // Request velocity
if (m_agentDebug.agent != null) if (_agentDebug.agent != null)
{ {
RcVec3f vel = CalcVel(m_agentDebug.agent.npos, p, m_agentDebug.agent.option.maxSpeed); RcVec3f vel = CalcVel(_agentDebug.agent.npos, p, _agentDebug.agent.option.maxSpeed);
crowd.RequestMoveVelocity(m_agentDebug.agent, vel); crowd.RequestMoveVelocity(_agentDebug.agent, vel);
} }
else else
{ {
@ -309,9 +423,9 @@ public class CrowdSampleTool : ISampleTool
else else
{ {
navquery.FindNearestPoly(p, halfExtents, filter, out m_targetRef, out m_targetPos, out var _); navquery.FindNearestPoly(p, halfExtents, filter, out m_targetRef, out m_targetPos, out var _);
if (m_agentDebug.agent != null) if (_agentDebug.agent != null)
{ {
crowd.RequestMoveTarget(m_agentDebug.agent, m_targetRef, m_targetPos); crowd.RequestMoveTarget(_agentDebug.agent, m_targetRef, m_targetPos);
} }
else else
{ {
@ -331,315 +445,8 @@ public class CrowdSampleTool : ISampleTool
return vel.Scale(speed); return vel.Scale(speed);
} }
public void HandleRender(NavMeshRenderer renderer)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
var settings = _sample.GetSettings();
float rad = settings.agentRadius;
DtNavMesh nav = _sample.GetNavMesh();
if (nav == null || crowd == null)
return;
if (m_showNodes && crowd.GetPathQueue() != null)
{
// NavMeshQuery navquery = crowd.GetPathQueue().GetNavQuery();
// if (navquery != null) {
// dd.DebugDrawNavMeshNodes(navquery);
// }
}
dd.DepthMask(false);
// Draw paths
if (m_showPath)
{
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
if (!m_showDetailAll && ag != m_agentDebug.agent)
continue;
List<long> path = ag.corridor.GetPath();
int npath = ag.corridor.GetPathCount();
for (int j = 0; j < npath; ++j)
{
dd.DebugDrawNavMeshPoly(nav, path[j], DuRGBA(255, 255, 255, 24));
}
}
}
if (m_targetRef != 0)
dd.DebugDrawCross(m_targetPos.x, m_targetPos.y + 0.1f, m_targetPos.z, rad, DuRGBA(255, 255, 255, 192), 2.0f);
// Occupancy grid.
if (m_showGrid)
{
float gridy = -float.MaxValue;
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
RcVec3f pos = ag.corridor.GetPos();
gridy = Math.Max(gridy, pos.y);
}
gridy += 1.0f;
dd.Begin(QUADS);
DtProximityGrid grid = crowd.GetGrid();
float cs = grid.GetCellSize();
foreach (var (combinedKey, count) in grid.GetItemCounts())
{
DtProximityGrid.DecomposeKey(combinedKey, out var x, out var y);
if (count != 0)
{
int col = DuRGBA(128, 0, 0, Math.Min(count * 40, 255));
dd.Vertex(x * cs, gridy, y * cs, col);
dd.Vertex(x * cs, gridy, y * cs + cs, col);
dd.Vertex(x * cs + cs, gridy, y * cs + cs, col);
dd.Vertex(x * cs + cs, gridy, y * cs, col);
}
}
dd.End();
}
// Trail
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
CrowdAgentTrail trail = m_trails[ag.idx];
RcVec3f pos = ag.npos;
dd.Begin(LINES, 3.0f);
RcVec3f prev = new RcVec3f();
float preva = 1;
prev = pos;
for (int j = 0; j < CrowdAgentTrail.AGENT_MAX_TRAIL - 1; ++j)
{
int idx = (trail.htrail + CrowdAgentTrail.AGENT_MAX_TRAIL - j) % CrowdAgentTrail.AGENT_MAX_TRAIL;
int v = idx * 3;
float a = 1 - j / (float)CrowdAgentTrail.AGENT_MAX_TRAIL;
dd.Vertex(prev.x, prev.y + 0.1f, prev.z, DuRGBA(0, 0, 0, (int)(128 * preva)));
dd.Vertex(trail.trail[v], trail.trail[v + 1] + 0.1f, trail.trail[v + 2], DuRGBA(0, 0, 0, (int)(128 * a)));
preva = a;
prev.Set(trail.trail, v);
}
dd.End();
}
// Corners & co
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
if (m_showDetailAll == false && ag != m_agentDebug.agent)
continue;
float radius = ag.option.radius;
RcVec3f pos = ag.npos;
if (m_showCorners)
{
if (0 < ag.corners.Count)
{
dd.Begin(LINES, 2.0f);
for (int j = 0; j < ag.corners.Count; ++j)
{
RcVec3f va = j == 0 ? pos : ag.corners[j - 1].pos;
RcVec3f vb = ag.corners[j].pos;
dd.Vertex(va.x, va.y + radius, va.z, DuRGBA(128, 0, 0, 192));
dd.Vertex(vb.x, vb.y + radius, vb.z, DuRGBA(128, 0, 0, 192));
}
if ((ag.corners[ag.corners.Count - 1].flags
& DtNavMeshQuery.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
{
RcVec3f v = ag.corners[ag.corners.Count - 1].pos;
dd.Vertex(v.x, v.y, v.z, DuRGBA(192, 0, 0, 192));
dd.Vertex(v.x, v.y + radius * 2, v.z, DuRGBA(192, 0, 0, 192));
}
dd.End();
if (_option.anticipateTurns)
{
/* float dvel[3], pos[3];
CalcSmoothSteerDirection(ag.pos, ag.cornerVerts, ag.ncorners, dvel);
pos.x = ag.pos.x + dvel.x;
pos.y = ag.pos.y + dvel.y;
pos.z = ag.pos.z + dvel.z;
float off = ag.radius+0.1f;
float[] tgt = &ag.cornerVerts.x;
float y = ag.pos.y+off;
dd.Begin(DU_DRAW_LINES, 2.0f);
dd.Vertex(ag.pos.x,y,ag.pos.z, DuRGBA(255,0,0,192));
dd.Vertex(pos.x,y,pos.z, DuRGBA(255,0,0,192));
dd.Vertex(pos.x,y,pos.z, DuRGBA(255,0,0,192));
dd.Vertex(tgt.x,y,tgt.z, DuRGBA(255,0,0,192));
dd.End();*/
}
}
}
if (m_showCollisionSegments)
{
RcVec3f center = ag.boundary.GetCenter();
dd.DebugDrawCross(center.x, center.y + radius, center.z, 0.2f, DuRGBA(192, 0, 128, 255), 2.0f);
dd.DebugDrawCircle(center.x, center.y + radius, center.z, ag.option.collisionQueryRange, DuRGBA(192, 0, 128, 128), 2.0f);
dd.Begin(LINES, 3.0f);
for (int j = 0; j < ag.boundary.GetSegmentCount(); ++j)
{
int col = DuRGBA(192, 0, 128, 192);
RcVec3f[] s = ag.boundary.GetSegment(j);
RcVec3f s0 = s[0];
RcVec3f s3 = s[1];
if (DtUtils.TriArea2D(pos, s0, s3) < 0.0f)
col = DuDarkenCol(col);
dd.AppendArrow(s[0].x, s[0].y + 0.2f, s[0].z, s[1].x, s[1].z + 0.2f, s[1].z, 0.0f, 0.3f, col);
}
dd.End();
}
if (m_showNeis)
{
dd.DebugDrawCircle(pos.x, pos.y + radius, pos.z, ag.option.collisionQueryRange, DuRGBA(0, 192, 128, 128),
2.0f);
dd.Begin(LINES, 2.0f);
for (int j = 0; j < ag.neis.Count; ++j)
{
DtCrowdAgent nei = ag.neis[j].agent;
if (nei != null)
{
dd.Vertex(pos.x, pos.y + radius, pos.z, DuRGBA(0, 192, 128, 128));
dd.Vertex(nei.npos.x, nei.npos.y + radius, nei.npos.z, DuRGBA(0, 192, 128, 128));
}
}
dd.End();
}
if (m_showOpt)
{
dd.Begin(LINES, 2.0f);
dd.Vertex(m_agentDebug.optStart.x, m_agentDebug.optStart.y + 0.3f, m_agentDebug.optStart.z,
DuRGBA(0, 128, 0, 192));
dd.Vertex(m_agentDebug.optEnd.x, m_agentDebug.optEnd.y + 0.3f, m_agentDebug.optEnd.z, DuRGBA(0, 128, 0, 192));
dd.End();
}
}
// Agent cylinders.
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
float radius = ag.option.radius;
RcVec3f pos = ag.npos;
int col = DuRGBA(0, 0, 0, 32);
if (m_agentDebug.agent == ag)
col = DuRGBA(255, 0, 0, 128);
dd.DebugDrawCircle(pos.x, pos.y, pos.z, radius, col, 2.0f);
}
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
float height = ag.option.height;
float radius = ag.option.radius;
RcVec3f pos = ag.npos;
int col = DuRGBA(220, 220, 220, 128);
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|| ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE)
col = DuLerpCol(col, DuRGBA(128, 0, 255, 128), 32);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH)
col = DuLerpCol(col, DuRGBA(128, 0, 255, 128), 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
col = DuRGBA(255, 32, 16, 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
col = DuLerpCol(col, DuRGBA(64, 255, 0, 128), 128);
dd.DebugDrawCylinder(pos.x - radius, pos.y + radius * 0.1f, pos.z - radius, pos.x + radius, pos.y + height,
pos.z + radius, col);
}
if (m_showVO)
{
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
if (m_showDetailAll == false && ag != m_agentDebug.agent)
continue;
// Draw detail about agent sela
DtObstacleAvoidanceDebugData vod = m_agentDebug.vod;
float dx = ag.npos.x;
float dy = ag.npos.y + ag.option.height;
float dz = ag.npos.z;
dd.DebugDrawCircle(dx, dy, dz, ag.option.maxSpeed, DuRGBA(255, 255, 255, 64), 2.0f);
dd.Begin(QUADS);
for (int j = 0; j < vod.GetSampleCount(); ++j)
{
RcVec3f p = vod.GetSampleVelocity(j);
float sr = vod.GetSampleSize(j);
float pen = vod.GetSamplePenalty(j);
float pen2 = vod.GetSamplePreferredSidePenalty(j);
int col = DuLerpCol(DuRGBA(255, 255, 255, 220), DuRGBA(128, 96, 0, 220), (int)(pen * 255));
col = DuLerpCol(col, DuRGBA(128, 0, 0, 220), (int)(pen2 * 128));
dd.Vertex(dx + p.x - sr, dy, dz + p.z - sr, col);
dd.Vertex(dx + p.x - sr, dy, dz + p.z + sr, col);
dd.Vertex(dx + p.x + sr, dy, dz + p.z + sr, col);
dd.Vertex(dx + p.x + sr, dy, dz + p.z - sr, col);
}
dd.End();
}
}
// Velocity stuff.
foreach (DtCrowdAgent ag in crowd.GetActiveAgents())
{
float radius = ag.option.radius;
float height = ag.option.height;
RcVec3f pos = ag.npos;
RcVec3f vel = ag.vel;
RcVec3f dvel = ag.dvel;
int col = DuRGBA(220, 220, 220, 192);
if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_REQUESTING
|| ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE)
col = DuLerpCol(col, DuRGBA(128, 0, 255, 192), 48);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_WAITING_FOR_PATH)
col = DuLerpCol(col, DuRGBA(128, 0, 255, 192), 128);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_FAILED)
col = DuRGBA(255, 32, 16, 192);
else if (ag.targetState == DtMoveRequestState.DT_CROWDAGENT_TARGET_VELOCITY)
col = DuLerpCol(col, DuRGBA(64, 255, 0, 192), 128);
dd.DebugDrawCircle(pos.x, pos.y + height, pos.z, radius, col, 2.0f);
dd.DebugDrawArrow(pos.x, pos.y + height, pos.z, pos.x + dvel.x, pos.y + height + dvel.y, pos.z + dvel.z,
0.0f, 0.4f, DuRGBA(0, 192, 255, 192), m_agentDebug.agent == ag ? 2.0f : 1.0f);
dd.DebugDrawArrow(pos.x, pos.y + height, pos.z, pos.x + vel.x, pos.y + height + vel.y, pos.z + vel.z, 0.0f,
0.4f, DuRGBA(0, 0, 0, 160), 2.0f);
}
dd.DepthMask(true);
}
public void HandleUpdate(float dt) public void HandleUpdate(float dt)
{
UpdateTick(dt);
}
private void UpdateTick(float dt)
{ {
if (crowd == null) if (crowd == null)
return; return;
@ -649,7 +456,7 @@ public class CrowdSampleTool : ISampleTool
return; return;
long startTime = RcFrequency.Ticks; long startTime = RcFrequency.Ticks;
crowd.Update(dt, m_agentDebug); crowd.Update(dt, _agentDebug);
long endTime = RcFrequency.Ticks; long endTime = RcFrequency.Ticks;
// Update agent trails // Update agent trails
@ -663,77 +470,17 @@ public class CrowdSampleTool : ISampleTool
trail.trail[trail.htrail * 3 + 2] = ag.npos.z; trail.trail[trail.htrail * 3 + 2] = ag.npos.z;
} }
m_agentDebug.vod.NormalizeSamples(); _agentDebug.vod.NormalizeSamples();
// m_crowdSampleCount.addSample((float) crowd.GetVelocitySampleCount()); // m_crowdSampleCount.addSample((float) crowd.GetVelocitySampleCount());
crowdUpdateTime = (endTime - startTime) / TimeSpan.TicksPerMillisecond; crowdUpdateTime = (endTime - startTime) / TimeSpan.TicksPerMillisecond;
} }
private void HilightAgent(DtCrowdAgent agent) private void HighlightAgent(DtCrowdAgent agent)
{ {
m_agentDebug.agent = agent; _agentDebug.agent = agent;
} }
public void Layout()
{
ImGui.Text($"Crowd Tool Mode");
ImGui.Separator();
CrowdToolMode previousToolMode = m_mode;
ImGui.RadioButton(CrowdToolMode.CREATE.Label, ref m_modeIdx, CrowdToolMode.CREATE.Idx);
ImGui.RadioButton(CrowdToolMode.MOVE_TARGET.Label, ref m_modeIdx, CrowdToolMode.MOVE_TARGET.Idx);
ImGui.RadioButton(CrowdToolMode.SELECT.Label, ref m_modeIdx, CrowdToolMode.SELECT.Idx);
ImGui.RadioButton(CrowdToolMode.TOGGLE_POLYS.Label, ref m_modeIdx, CrowdToolMode.TOGGLE_POLYS.Idx);
ImGui.NewLine();
if (previousToolMode.Idx != m_modeIdx)
{
m_mode = CrowdToolMode.Values[m_modeIdx];
}
ImGui.Text("Options");
ImGui.Separator();
bool m_optimizeVis = _option.optimizeVis;
bool m_optimizeTopo = _option.optimizeTopo;
bool m_anticipateTurns = _option.anticipateTurns;
bool m_obstacleAvoidance = _option.obstacleAvoidance;
bool m_separation = _option.separation;
int m_obstacleAvoidanceType = _option.obstacleAvoidanceType;
float m_separationWeight = _option.separationWeight;
ImGui.Checkbox("Optimize Visibility", ref _option.optimizeVis);
ImGui.Checkbox("Optimize Topology", ref _option.optimizeTopo);
ImGui.Checkbox("Anticipate Turns", ref _option.anticipateTurns);
ImGui.Checkbox("Obstacle Avoidance", ref _option.obstacleAvoidance);
ImGui.SliderInt("Avoidance Quality", ref _option.obstacleAvoidanceType, 0, 3);
ImGui.Checkbox("Separation", ref _option.separation);
ImGui.SliderFloat("Separation Weight", ref _option.separationWeight, 0f, 20f, "%.2f");
ImGui.NewLine();
if (m_optimizeVis != _option.optimizeVis || m_optimizeTopo != _option.optimizeTopo
|| m_anticipateTurns != _option.anticipateTurns || m_obstacleAvoidance != _option.obstacleAvoidance
|| m_separation != _option.separation
|| m_obstacleAvoidanceType != _option.obstacleAvoidanceType
|| m_separationWeight != _option.separationWeight)
{
UpdateAgentParams();
}
ImGui.Text("Selected Debug Draw");
ImGui.Separator();
ImGui.Checkbox("Show Corners", ref m_showCorners);
ImGui.Checkbox("Show Collision Segs", ref m_showCollisionSegments);
ImGui.Checkbox("Show Path", ref m_showPath);
ImGui.Checkbox("Show VO", ref m_showVO);
ImGui.Checkbox("Show Path Optimization", ref m_showOpt);
ImGui.Checkbox("Show Neighbours", ref m_showNeis);
ImGui.NewLine();
ImGui.Text("Debug Draw");
ImGui.Separator();
ImGui.Checkbox("Show Proximity Grid", ref m_showGrid);
ImGui.Checkbox("Show Nodes", ref m_showNodes);
ImGui.Text($"Update Time: {crowdUpdateTime} ms");
}
private void UpdateAgentParams() private void UpdateAgentParams()
{ {

View File

@ -98,6 +98,243 @@ public class DynamicUpdateSampleTool : ISampleTool
convexGeom = DemoObjImporter.Load(Loader.ToBytes("convex.obj")); convexGeom = DemoObjImporter.Load(Loader.ToBytes("convex.obj"));
} }
public void Layout()
{
ImGui.Text($"Dynamic Update Tool Modes");
ImGui.Separator();
var prevMode = mode;
ImGui.RadioButton(DynamicUpdateToolMode.BUILD.Label, ref toolModeIdx, DynamicUpdateToolMode.BUILD.Idx);
ImGui.RadioButton(DynamicUpdateToolMode.COLLIDERS.Label, ref toolModeIdx, DynamicUpdateToolMode.COLLIDERS.Idx);
ImGui.RadioButton(DynamicUpdateToolMode.RAYCAST.Label, ref toolModeIdx, DynamicUpdateToolMode.RAYCAST.Idx);
ImGui.NewLine();
if (prevMode.Idx != toolModeIdx)
{
mode = DynamicUpdateToolMode.Values[toolModeIdx];
}
ImGui.Text($"Selected mode - {mode.Label}");
ImGui.Separator();
if (mode == DynamicUpdateToolMode.BUILD)
{
var loadVoxelPopupStrId = "Load Voxels Popup";
bool isLoadVoxelPopup = true;
if (ImGui.Button("Load Voxels..."))
{
ImGui.OpenPopup(loadVoxelPopupStrId);
}
if (ImGui.BeginPopupModal(loadVoxelPopupStrId, ref isLoadVoxelPopup, ImGuiWindowFlags.NoTitleBar))
{
var picker = ImFilePicker.GetFilePicker(loadVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels");
if (picker.Draw())
{
Load(picker.SelectedFile);
ImFilePicker.RemoveFilePicker(loadVoxelPopupStrId);
}
ImGui.EndPopup();
}
var saveVoxelPopupStrId = "Save Voxels Popup";
bool isSaveVoxelPopup = true;
if (dynaMesh != null)
{
ImGui.Checkbox("Compression", ref compression);
if (ImGui.Button("Save Voxels..."))
{
ImGui.BeginPopup(saveVoxelPopupStrId);
}
if (ImGui.BeginPopupModal(saveVoxelPopupStrId, ref isSaveVoxelPopup, ImGuiWindowFlags.NoTitleBar))
{
var picker = ImFilePicker.GetFilePicker(saveVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels");
if (picker.Draw())
{
if (string.IsNullOrEmpty(picker.SelectedFile))
Save(picker.SelectedFile);
ImFilePicker.RemoveFilePicker(saveVoxelPopupStrId);
}
ImGui.EndPopup();
}
}
ImGui.NewLine();
ImGui.Text("Rasterization");
ImGui.Separator();
ImGui.Text($"Cell Size - {cellSize}");
ImGui.NewLine();
ImGui.Text("Agent");
ImGui.Separator();
ImGui.SliderFloat("Height", ref walkableHeight, 0f, 5f, "%.2f");
ImGui.SliderFloat("Radius", ref walkableRadius, 0f, 10f, "%.2f");
ImGui.SliderFloat("Max Climb", ref walkableClimb, 0f, 10f, "%.2f");
ImGui.Text($"Max Slope : {walkableSlopeAngle}");
ImGui.NewLine();
ImGui.Text("Partitioning");
ImGui.Separator();
RcPartitionType.Values.ForEach(partition =>
{
var label = partition.Name.Substring(0, 1).ToUpper()
+ partition.Name.Substring(1).ToLower();
ImGui.RadioButton(label, ref partitioning, partition.Value);
});
ImGui.NewLine();
ImGui.Text("Filtering");
ImGui.Separator();
ImGui.Checkbox("Low Hanging Obstacles", ref filterLowHangingObstacles);
ImGui.Checkbox("Ledge Spans", ref filterLedgeSpans);
ImGui.Checkbox("Walkable Low Height Spans", ref filterWalkableLowHeightSpans);
ImGui.NewLine();
ImGui.Text("Region");
ImGui.Separator();
ImGui.SliderFloat("Min Region Size", ref minRegionArea, 0, 150, "%.1f");
ImGui.SliderFloat("Merged Region Size", ref regionMergeSize, 0, 400, "%.1f");
ImGui.NewLine();
ImGui.Text("Polygonization");
ImGui.Separator();
ImGui.SliderFloat("Max Edge Length", ref maxEdgeLen, 0f, 50f, "%.1f");
ImGui.SliderFloat("Max Edge Error", ref maxSimplificationError, 0.1f, 10f, "%.1f");
ImGui.SliderInt("Verts Per Poly", ref vertsPerPoly, 3, 12);
ImGui.NewLine();
ImGui.Text("Detail Mesh");
ImGui.Separator();
ImGui.Checkbox("Enable", ref buildDetailMesh);
ImGui.SliderFloat("Sample Distance", ref detailSampleDist, 0f, 16f, "%.1f");
ImGui.SliderFloat("Max Sample Error", ref detailSampleMaxError, 0f, 16f, "%.1f");
ImGui.NewLine();
if (ImGui.Button("Build Dynamic mesh"))
{
if (dynaMesh != null)
{
BuildDynaMesh();
_sample.SetChanged(false);
}
}
}
if (mode == DynamicUpdateToolMode.COLLIDERS)
{
ImGui.Text("Colliders");
ImGui.Separator();
var prev = colliderShape;
ImGui.Checkbox("Show", ref showColliders);
ImGui.RadioButton("Sphere", ref colliderShapeIdx, (int)DynamicColliderShape.SPHERE);
ImGui.RadioButton("Capsule", ref colliderShapeIdx, (int)DynamicColliderShape.CAPSULE);
ImGui.RadioButton("Box", ref colliderShapeIdx, (int)DynamicColliderShape.BOX);
ImGui.RadioButton("Cylinder", ref colliderShapeIdx, (int)DynamicColliderShape.CYLINDER);
ImGui.RadioButton("Composite", ref colliderShapeIdx, (int)DynamicColliderShape.COMPOSITE);
ImGui.RadioButton("Convex Trimesh", ref colliderShapeIdx, (int)DynamicColliderShape.CONVEX);
ImGui.RadioButton("Trimesh Bridge", ref colliderShapeIdx, (int)DynamicColliderShape.TRIMESH_BRIDGE);
ImGui.RadioButton("Trimesh House", ref colliderShapeIdx, (int)DynamicColliderShape.TRIMESH_HOUSE);
ImGui.NewLine();
if ((int)prev != colliderShapeIdx)
{
colliderShape = (DynamicColliderShape)colliderShapeIdx;
}
}
if (mode == DynamicUpdateToolMode.RAYCAST)
{
ImGui.Text($"Raycast Time: {raycastTime} ms");
ImGui.Separator();
if (sposSet)
{
ImGui.Text($"Start: {spos.x}, {spos.y + 1.3f}, {spos.z}");
}
if (eposSet)
{
ImGui.Text($"End: {epos.x}, {epos.y + 1.3f}, {epos.z}");
}
if (raycastHit)
{
ImGui.Text($"Hit: {raycastHitPos.x}, {raycastHitPos.y}, {raycastHitPos.z}");
}
ImGui.NewLine();
}
else
{
ImGui.Text($"Build Time: {buildTime} ms");
}
}
public void HandleRender(NavMeshRenderer renderer)
{
if (mode == DynamicUpdateToolMode.COLLIDERS)
{
if (showColliders)
{
colliderGizmos.Values.ForEach(g => g.Render(renderer.GetDebugDraw()));
}
}
if (mode == DynamicUpdateToolMode.RAYCAST)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
int startCol = DuRGBA(128, 25, 0, 192);
int endCol = DuRGBA(51, 102, 0, 129);
if (sposSet)
{
DrawAgent(dd, spos, startCol);
}
if (eposSet)
{
DrawAgent(dd, epos, endCol);
}
dd.DepthMask(false);
if (raycastHitPos != RcVec3f.Zero)
{
int spathCol = raycastHit ? DuRGBA(128, 32, 16, 220) : DuRGBA(64, 128, 240, 220);
dd.Begin(LINES, 2.0f);
dd.Vertex(spos.x, spos.y + 1.3f, spos.z, spathCol);
dd.Vertex(raycastHitPos.x, raycastHitPos.y, raycastHitPos.z, spathCol);
dd.End();
}
dd.DepthMask(true);
}
}
private void DrawAgent(RecastDebugDraw dd, RcVec3f pos, int col)
{
var settings = _sample.GetSettings();
float r = settings.agentRadius;
float h = settings.agentHeight;
float c = settings.agentMaxClimb;
dd.DepthMask(false);
// Agent dimensions.
dd.DebugDrawCylinderWire(pos.x - r, pos.y + 0.02f, pos.z - r, pos.x + r, pos.y + h, pos.z + r, col, 2.0f);
dd.DebugDrawCircle(pos.x, pos.y + c, pos.z, r, DuRGBA(0, 0, 0, 64), 1.0f);
int colb = DuRGBA(0, 0, 0, 196);
dd.Begin(LINES);
dd.Vertex(pos.x, pos.y - c, pos.z, colb);
dd.Vertex(pos.x, pos.y + c, pos.z, colb);
dd.Vertex(pos.x - r / 2, pos.y + 0.02f, pos.z, colb);
dd.Vertex(pos.x + r / 2, pos.y + 0.02f, pos.z, colb);
dd.Vertex(pos.x, pos.y + 0.02f, pos.z - r / 2, colb);
dd.Vertex(pos.x, pos.y + 0.02f, pos.z + r / 2, colb);
dd.End();
dd.DepthMask(true);
}
public IRcToolable GetTool() public IRcToolable GetTool()
{ {
return _tool; return _tool;
@ -415,66 +652,6 @@ public class DynamicUpdateSampleTool : ISampleTool
return disc >= 0.0f; return disc >= 0.0f;
} }
public void HandleRender(NavMeshRenderer renderer)
{
if (mode == DynamicUpdateToolMode.COLLIDERS)
{
if (showColliders)
{
colliderGizmos.Values.ForEach(g => g.Render(renderer.GetDebugDraw()));
}
}
if (mode == DynamicUpdateToolMode.RAYCAST)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
int startCol = DuRGBA(128, 25, 0, 192);
int endCol = DuRGBA(51, 102, 0, 129);
if (sposSet)
{
DrawAgent(dd, spos, startCol);
}
if (eposSet)
{
DrawAgent(dd, epos, endCol);
}
dd.DepthMask(false);
if (raycastHitPos != RcVec3f.Zero)
{
int spathCol = raycastHit ? DuRGBA(128, 32, 16, 220) : DuRGBA(64, 128, 240, 220);
dd.Begin(LINES, 2.0f);
dd.Vertex(spos.x, spos.y + 1.3f, spos.z, spathCol);
dd.Vertex(raycastHitPos.x, raycastHitPos.y, raycastHitPos.z, spathCol);
dd.End();
}
dd.DepthMask(true);
}
}
private void DrawAgent(RecastDebugDraw dd, RcVec3f pos, int col)
{
var settings = _sample.GetSettings();
float r = settings.agentRadius;
float h = settings.agentHeight;
float c = settings.agentMaxClimb;
dd.DepthMask(false);
// Agent dimensions.
dd.DebugDrawCylinderWire(pos.x - r, pos.y + 0.02f, pos.z - r, pos.x + r, pos.y + h, pos.z + r, col, 2.0f);
dd.DebugDrawCircle(pos.x, pos.y + c, pos.z, r, DuRGBA(0, 0, 0, 64), 1.0f);
int colb = DuRGBA(0, 0, 0, 196);
dd.Begin(LINES);
dd.Vertex(pos.x, pos.y - c, pos.z, colb);
dd.Vertex(pos.x, pos.y + c, pos.z, colb);
dd.Vertex(pos.x - r / 2, pos.y + 0.02f, pos.z, colb);
dd.Vertex(pos.x + r / 2, pos.y + 0.02f, pos.z, colb);
dd.Vertex(pos.x, pos.y + 0.02f, pos.z - r / 2, colb);
dd.Vertex(pos.x, pos.y + 0.02f, pos.z + r / 2, colb);
dd.End();
dd.DepthMask(true);
}
public void HandleUpdate(float dt) public void HandleUpdate(float dt)
{ {
@ -503,182 +680,6 @@ public class DynamicUpdateSampleTool : ISampleTool
} }
} }
public void Layout()
{
ImGui.Text($"Dynamic Update Tool Modes");
ImGui.Separator();
var prevMode = mode;
ImGui.RadioButton(DynamicUpdateToolMode.BUILD.Label, ref toolModeIdx, DynamicUpdateToolMode.BUILD.Idx);
ImGui.RadioButton(DynamicUpdateToolMode.COLLIDERS.Label, ref toolModeIdx, DynamicUpdateToolMode.COLLIDERS.Idx);
ImGui.RadioButton(DynamicUpdateToolMode.RAYCAST.Label, ref toolModeIdx, DynamicUpdateToolMode.RAYCAST.Idx);
ImGui.NewLine();
if (prevMode.Idx != toolModeIdx)
{
mode = DynamicUpdateToolMode.Values[toolModeIdx];
}
ImGui.Text($"Selected mode - {mode.Label}");
ImGui.Separator();
if (mode == DynamicUpdateToolMode.BUILD)
{
var loadVoxelPopupStrId = "Load Voxels Popup";
bool isLoadVoxelPopup = true;
if (ImGui.Button("Load Voxels..."))
{
ImGui.OpenPopup(loadVoxelPopupStrId);
}
if (ImGui.BeginPopupModal(loadVoxelPopupStrId, ref isLoadVoxelPopup, ImGuiWindowFlags.NoTitleBar))
{
var picker = ImFilePicker.GetFilePicker(loadVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels");
if (picker.Draw())
{
Load(picker.SelectedFile);
ImFilePicker.RemoveFilePicker(loadVoxelPopupStrId);
}
ImGui.EndPopup();
}
var saveVoxelPopupStrId = "Save Voxels Popup";
bool isSaveVoxelPopup = true;
if (dynaMesh != null)
{
ImGui.Checkbox("Compression", ref compression);
if (ImGui.Button("Save Voxels..."))
{
ImGui.BeginPopup(saveVoxelPopupStrId);
}
if (ImGui.BeginPopupModal(saveVoxelPopupStrId, ref isSaveVoxelPopup, ImGuiWindowFlags.NoTitleBar))
{
var picker = ImFilePicker.GetFilePicker(saveVoxelPopupStrId, Path.Combine(Environment.CurrentDirectory), ".voxels");
if (picker.Draw())
{
if (string.IsNullOrEmpty(picker.SelectedFile))
Save(picker.SelectedFile);
ImFilePicker.RemoveFilePicker(saveVoxelPopupStrId);
}
ImGui.EndPopup();
}
}
ImGui.NewLine();
ImGui.Text("Rasterization");
ImGui.Separator();
ImGui.Text($"Cell Size - {cellSize}");
ImGui.NewLine();
ImGui.Text("Agent");
ImGui.Separator();
ImGui.SliderFloat("Height", ref walkableHeight, 0f, 5f, "%.2f");
ImGui.SliderFloat("Radius", ref walkableRadius, 0f, 10f, "%.2f");
ImGui.SliderFloat("Max Climb", ref walkableClimb, 0f, 10f, "%.2f");
ImGui.Text($"Max Slope : {walkableSlopeAngle}");
ImGui.NewLine();
ImGui.Text("Partitioning");
ImGui.Separator();
RcPartitionType.Values.ForEach(partition =>
{
var label = partition.Name.Substring(0, 1).ToUpper()
+ partition.Name.Substring(1).ToLower();
ImGui.RadioButton(label, ref partitioning, partition.Value);
});
ImGui.NewLine();
ImGui.Text("Filtering");
ImGui.Separator();
ImGui.Checkbox("Low Hanging Obstacles", ref filterLowHangingObstacles);
ImGui.Checkbox("Ledge Spans", ref filterLedgeSpans);
ImGui.Checkbox("Walkable Low Height Spans", ref filterWalkableLowHeightSpans);
ImGui.NewLine();
ImGui.Text("Region");
ImGui.Separator();
ImGui.SliderFloat("Min Region Size", ref minRegionArea, 0, 150, "%.1f");
ImGui.SliderFloat("Merged Region Size", ref regionMergeSize, 0, 400, "%.1f");
ImGui.NewLine();
ImGui.Text("Polygonization");
ImGui.Separator();
ImGui.SliderFloat("Max Edge Length", ref maxEdgeLen, 0f, 50f, "%.1f");
ImGui.SliderFloat("Max Edge Error", ref maxSimplificationError, 0.1f, 10f, "%.1f");
ImGui.SliderInt("Verts Per Poly", ref vertsPerPoly, 3, 12);
ImGui.NewLine();
ImGui.Text("Detail Mesh");
ImGui.Separator();
ImGui.Checkbox("Enable", ref buildDetailMesh);
ImGui.SliderFloat("Sample Distance", ref detailSampleDist, 0f, 16f, "%.1f");
ImGui.SliderFloat("Max Sample Error", ref detailSampleMaxError, 0f, 16f, "%.1f");
ImGui.NewLine();
if (ImGui.Button("Build Dynamic mesh"))
{
if (dynaMesh != null)
{
BuildDynaMesh();
_sample.SetChanged(false);
}
}
}
if (mode == DynamicUpdateToolMode.COLLIDERS)
{
ImGui.Text("Colliders");
ImGui.Separator();
var prev = colliderShape;
ImGui.Checkbox("Show", ref showColliders);
ImGui.RadioButton("Sphere", ref colliderShapeIdx, (int)DynamicColliderShape.SPHERE);
ImGui.RadioButton("Capsule", ref colliderShapeIdx, (int)DynamicColliderShape.CAPSULE);
ImGui.RadioButton("Box", ref colliderShapeIdx, (int)DynamicColliderShape.BOX);
ImGui.RadioButton("Cylinder", ref colliderShapeIdx, (int)DynamicColliderShape.CYLINDER);
ImGui.RadioButton("Composite", ref colliderShapeIdx, (int)DynamicColliderShape.COMPOSITE);
ImGui.RadioButton("Convex Trimesh", ref colliderShapeIdx, (int)DynamicColliderShape.CONVEX);
ImGui.RadioButton("Trimesh Bridge", ref colliderShapeIdx, (int)DynamicColliderShape.TRIMESH_BRIDGE);
ImGui.RadioButton("Trimesh House", ref colliderShapeIdx, (int)DynamicColliderShape.TRIMESH_HOUSE);
ImGui.NewLine();
if ((int)prev != colliderShapeIdx)
{
colliderShape = (DynamicColliderShape)colliderShapeIdx;
}
}
if (mode == DynamicUpdateToolMode.RAYCAST)
{
ImGui.Text($"Raycast Time: {raycastTime} ms");
ImGui.Separator();
if (sposSet)
{
ImGui.Text($"Start: {spos.x}, {spos.y + 1.3f}, {spos.z}");
}
if (eposSet)
{
ImGui.Text($"End: {epos.x}, {epos.y + 1.3f}, {epos.z}");
}
if (raycastHit)
{
ImGui.Text($"Hit: {raycastHitPos.x}, {raycastHitPos.y}, {raycastHitPos.z}");
}
ImGui.NewLine();
}
else
{
ImGui.Text($"Build Time: {buildTime} ms");
}
}
private void Load(string filename) private void Load(string filename)
{ {

View File

@ -42,24 +42,78 @@ public class JumpLinkBuilderSampleTool : ISampleTool
_option = new(); _option = new();
} }
public IRcToolable GetTool() public void Layout()
{ {
return _tool; if (0 >= _sample.GetRecastResults().Count)
} return;
public void SetSample(DemoSample sample) ImGui.Text("Options");
{ ImGui.Separator();
_sample = sample; ImGui.SliderFloat("Ground Tolerance", ref _option.groundTolerance, 0f, 2f, "%.2f");
} ImGui.NewLine();
public void OnSampleChanged() ImGui.Text("Climb Down");
{ ImGui.Separator();
_tool.Clear(); ImGui.SliderFloat("Distance", ref _option.climbDownDistance, 0f, 5f, "%.2f");
} ImGui.SliderFloat("Min Cliff Height", ref _option.climbDownMinHeight, 0f, 10f, "%.2f");
ImGui.SliderFloat("Max Cliff Height", ref _option.climbDownMaxHeight, 0f, 10f, "%.2f");
ImGui.NewLine();
ImGui.Text("Jump Down");
ImGui.Separator();
ImGui.SliderFloat("Max Distance", ref _option.edgeJumpEndDistance, 0f, 10f, "%.2f");
ImGui.SliderFloat("Jump Height", ref _option.edgeJumpHeight, 0f, 10f, "%.2f");
ImGui.SliderFloat("Max Jump Down", ref _option.edgeJumpDownMaxHeight, 0f, 10f, "%.2f");
ImGui.SliderFloat("Max Jump Up", ref _option.edgeJumpUpMaxHeight, 0f, 10f, "%.2f");
ImGui.NewLine();
public void HandleClick(RcVec3f s, RcVec3f p, bool shift) ImGui.Text("Mode");
{ ImGui.Separator();
//int buildTypes = 0;
ImGui.CheckboxFlags("Climb Down", ref _option.buildTypes, JumpLinkType.EDGE_CLIMB_DOWN.Bit);
ImGui.CheckboxFlags("Edge Jump", ref _option.buildTypes, JumpLinkType.EDGE_JUMP.Bit);
//option.buildTypes = buildTypes;
bool build = false;
bool buildOffMeshConnections = false;
if (ImGui.Button("Build Jump Link"))
{
build = true;
}
if (ImGui.Button("Build Off-Mesh Links"))
{
buildOffMeshConnections = true;
}
if (build || buildOffMeshConnections)
{
var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings();
_tool.Build(
geom, settings, _sample.GetRecastResults(),
buildOffMeshConnections,
_option.buildTypes,
_option.groundTolerance,
_option.climbDownDistance,
_option.climbDownMaxHeight,
_option.climbDownMinHeight,
_option.edgeJumpEndDistance,
_option.edgeJumpHeight,
_option.edgeJumpDownMaxHeight,
_option.edgeJumpUpMaxHeight
);
}
ImGui.Text("Debug Draw Options");
ImGui.Separator();
//int newFlags = 0;
ImGui.CheckboxFlags("Walkable Border", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_WALKABLE_BORDER);
ImGui.CheckboxFlags("Selected Edge", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_SELECTED_EDGE);
ImGui.CheckboxFlags("Anim Trajectory", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_ANIM_TRAJECTORY);
ImGui.CheckboxFlags("Land Samples", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_LAND_SAMPLES);
ImGui.CheckboxFlags("All Annotations", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_ANNOTATIONS);
//option.flags = newFlags;
} }
public void HandleRender(NavMeshRenderer renderer) public void HandleRender(NavMeshRenderer renderer)
@ -326,6 +380,28 @@ public class JumpLinkBuilderSampleTool : ISampleTool
dd.DepthMask(true); dd.DepthMask(true);
} }
public IRcToolable GetTool()
{
return _tool;
}
public void SetSample(DemoSample sample)
{
_sample = sample;
}
public void OnSampleChanged()
{
_tool.Clear();
}
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
{
}
private void DrawTrajectory(RecastDebugDraw dd, JumpLink link, RcVec3f pa, RcVec3f pb, Trajectory tra, int cola) private void DrawTrajectory(RecastDebugDraw dd, JumpLink link, RcVec3f pa, RcVec3f pb, Trajectory tra, int cola)
{ {
} }
@ -334,80 +410,6 @@ public class JumpLinkBuilderSampleTool : ISampleTool
{ {
} }
public void Layout()
{
if (0 >= _sample.GetRecastResults().Count)
return;
ImGui.Text("Options");
ImGui.Separator();
ImGui.SliderFloat("Ground Tolerance", ref _option.groundTolerance, 0f, 2f, "%.2f");
ImGui.NewLine();
ImGui.Text("Climb Down");
ImGui.Separator();
ImGui.SliderFloat("Distance", ref _option.climbDownDistance, 0f, 5f, "%.2f");
ImGui.SliderFloat("Min Cliff Height", ref _option.climbDownMinHeight, 0f, 10f, "%.2f");
ImGui.SliderFloat("Max Cliff Height", ref _option.climbDownMaxHeight, 0f, 10f, "%.2f");
ImGui.NewLine();
ImGui.Text("Jump Down");
ImGui.Separator();
ImGui.SliderFloat("Max Distance", ref _option.edgeJumpEndDistance, 0f, 10f, "%.2f");
ImGui.SliderFloat("Jump Height", ref _option.edgeJumpHeight, 0f, 10f, "%.2f");
ImGui.SliderFloat("Max Jump Down", ref _option.edgeJumpDownMaxHeight, 0f, 10f, "%.2f");
ImGui.SliderFloat("Max Jump Up", ref _option.edgeJumpUpMaxHeight, 0f, 10f, "%.2f");
ImGui.NewLine();
ImGui.Text("Mode");
ImGui.Separator();
//int buildTypes = 0;
ImGui.CheckboxFlags("Climb Down", ref _option.buildTypes, JumpLinkType.EDGE_CLIMB_DOWN.Bit);
ImGui.CheckboxFlags("Edge Jump", ref _option.buildTypes, JumpLinkType.EDGE_JUMP.Bit);
//option.buildTypes = buildTypes;
bool build = false;
bool buildOffMeshConnections = false;
if (ImGui.Button("Build Jump Link"))
{
build = true;
}
if (ImGui.Button("Build Off-Mesh Links"))
{
buildOffMeshConnections = true;
}
if (build || buildOffMeshConnections)
{
var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings();
_tool.Build(
geom, settings, _sample.GetRecastResults(),
buildOffMeshConnections,
_option.buildTypes,
_option.groundTolerance,
_option.climbDownDistance,
_option.climbDownMaxHeight,
_option.climbDownMinHeight,
_option.edgeJumpEndDistance,
_option.edgeJumpHeight,
_option.edgeJumpDownMaxHeight,
_option.edgeJumpUpMaxHeight
);
}
ImGui.Text("Debug Draw Options");
ImGui.Separator();
//int newFlags = 0;
ImGui.CheckboxFlags("Walkable Border", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_WALKABLE_BORDER);
ImGui.CheckboxFlags("Selected Edge", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_SELECTED_EDGE);
ImGui.CheckboxFlags("Anim Trajectory", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_ANIM_TRAJECTORY);
ImGui.CheckboxFlags("Land Samples", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_LAND_SAMPLES);
ImGui.CheckboxFlags("All Annotations", ref _option.flags, RcJumpLinkBuilderToolOption.DRAW_ANNOTATIONS);
//option.flags = newFlags;
}
public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift) public void HandleClickRay(RcVec3f start, RcVec3f direction, bool shift)
{ {

View File

@ -24,20 +24,6 @@ public class ObstacleSampleTool : ISampleTool
_tool = new(DtTileCacheCompressorFactory.Shared); _tool = new(DtTileCacheCompressorFactory.Shared);
} }
public IRcToolable GetTool()
{
return _tool;
}
public void SetSample(DemoSample sample)
{
_sample = sample;
}
public void OnSampleChanged()
{
}
public void Layout() public void Layout()
{ {
if (ImGui.Button("Build Tile Cache")) if (ImGui.Button("Build Tile Cache"))
@ -45,13 +31,12 @@ public class ObstacleSampleTool : ISampleTool
var geom = _sample.GetInputGeom(); var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings(); var settings = _sample.GetSettings();
var buildResult =_tool.Build(geom, settings, RcByteOrder.LITTLE_ENDIAN, true); var buildResult = _tool.Build(geom, settings, RcByteOrder.LITTLE_ENDIAN, true);
if (buildResult.Success) if (buildResult.Success)
{ {
_sample.Update(_sample.GetInputGeom(), buildResult.RecastBuilderResults, buildResult.NavMesh); _sample.Update(_sample.GetInputGeom(), buildResult.RecastBuilderResults, buildResult.NavMesh);
_sample.SetChanged(false); _sample.SetChanged(false);
} }
} }
if (ImGui.Button("Remove All Temp Obstacles")) if (ImGui.Button("Remove All Temp Obstacles"))
@ -65,21 +50,6 @@ public class ObstacleSampleTool : ISampleTool
ImGui.Text("Shift+LMB to remove an obstacle."); ImGui.Text("Shift+LMB to remove an obstacle.");
} }
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
{
_hitPosSet = true;
_hitPos = p;
if (shift)
{
_tool.RemoveTempObstacle(s, p);
}
else
{
_tool.AddTempObstacle(_hitPos);
}
}
public void HandleRender(NavMeshRenderer renderer) public void HandleRender(NavMeshRenderer renderer)
{ {
DrawObstacles(renderer.GetDebugDraw()); DrawObstacles(renderer.GetDebugDraw());
@ -116,6 +86,37 @@ public class ObstacleSampleTool : ISampleTool
} }
} }
public IRcToolable GetTool()
{
return _tool;
}
public void SetSample(DemoSample sample)
{
_sample = sample;
}
public void OnSampleChanged()
{
}
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
{
_hitPosSet = true;
_hitPos = p;
if (shift)
{
_tool.RemoveTempObstacle(s, p);
}
else
{
_tool.AddTempObstacle(_hitPos);
}
}
public void HandleUpdate(float dt) public void HandleUpdate(float dt)
{ {
var tc = _tool.GetTileCache(); var tc = _tool.GetTileCache();

View File

@ -45,6 +45,33 @@ public class OffMeshConnectionSampleTool : ISampleTool
_tool = new(); _tool = new();
} }
public void Layout()
{
var options = _tool.GetOption();
ImGui.RadioButton("One Way", ref options.bidir, 0);
ImGui.RadioButton("Bidirectional", ref options.bidir, 1);
}
public void HandleRender(NavMeshRenderer renderer)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
var settings = _sample.GetSettings();
float s = settings.agentRadius;
if (hitPosSet)
{
dd.DebugDrawCross(hitPos.x, hitPos.y + 0.1f, hitPos.z, s, DuRGBA(0, 0, 0, 128), 2.0f);
}
DemoInputGeomProvider geom = _sample.GetInputGeom();
if (geom != null)
{
renderer.DrawOffMeshConnections(geom, true);
}
}
public IRcToolable GetTool() public IRcToolable GetTool()
{ {
return _tool; return _tool;
@ -90,32 +117,6 @@ public class OffMeshConnectionSampleTool : ISampleTool
} }
} }
public void HandleRender(NavMeshRenderer renderer)
{
RecastDebugDraw dd = renderer.GetDebugDraw();
var settings = _sample.GetSettings();
float s = settings.agentRadius;
if (hitPosSet)
{
dd.DebugDrawCross(hitPos.x, hitPos.y + 0.1f, hitPos.z, s, DuRGBA(0, 0, 0, 128), 2.0f);
}
DemoInputGeomProvider geom = _sample.GetInputGeom();
if (geom != null)
{
renderer.DrawOffMeshConnections(geom, true);
}
}
public void Layout()
{
var options = _tool.GetOption();
ImGui.RadioButton("One Way", ref options.bidir, 0);
ImGui.RadioButton("Bidirectional", ref options.bidir, 1);
}
public void HandleUpdate(float dt) public void HandleUpdate(float dt)
{ {

View File

@ -60,38 +60,6 @@ public class TestNavmeshSampleTool : ISampleTool
); );
} }
public IRcToolable GetTool()
{
return _tool;
}
public void SetSample(DemoSample sample)
{
_sample = sample;
}
public void OnSampleChanged()
{
// ..
}
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
{
if (shift)
{
m_sposSet = true;
m_spos = p;
}
else
{
m_eposSet = true;
m_epos = p;
}
Recalc();
}
public void Layout() public void Layout()
{ {
var previousToolMode = _option.mode; var previousToolMode = _option.mode;
@ -163,186 +131,13 @@ public class TestNavmeshSampleTool : ISampleTool
ImGui.Checkbox("Raycast shortcuts", ref _option.enableRaycast); ImGui.Checkbox("Raycast shortcuts", ref _option.enableRaycast);
if (previousToolMode != _option.mode || _option.straightPathOptions != previousStraightPathOptions if (previousToolMode != _option.mode || _option.straightPathOptions != previousStraightPathOptions
|| previousIncludeFlags != _option.includeFlags || previousExcludeFlags != _option.excludeFlags || previousIncludeFlags != _option.includeFlags || previousExcludeFlags != _option.excludeFlags
|| previousEnableRaycast != _option.enableRaycast || previousConstrainByCircle != _option.constrainByCircle) || previousEnableRaycast != _option.enableRaycast || previousConstrainByCircle != _option.constrainByCircle)
{ {
Recalc(); Recalc();
} }
} }
private void Recalc()
{
var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings();
var navMesh = _sample.GetNavMesh();
var navQuery = _sample.GetNavMeshQuery();
if (null == geom || null == navQuery)
return;
if (m_sposSet)
{
navQuery.FindNearestPoly(m_spos, m_polyPickExt, m_filter, out m_startRef, out var _, out var _);
}
else
{
m_startRef = 0;
}
if (m_eposSet)
{
navQuery.FindNearestPoly(m_epos, m_polyPickExt, m_filter, out m_endRef, out var _, out var _);
}
else
{
m_endRef = 0;
}
if (_option.mode == RcTestNavmeshToolMode.PATHFIND_FOLLOW)
{
if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0)
{
var polys = new List<long>();
var smoothPath = new List<RcVec3f>();
var status = _tool.FindFollowPath(navMesh, navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast,
ref polys, ref smoothPath);
if (status.Succeeded())
{
m_polys = polys;
m_smoothPath = smoothPath;
}
}
else
{
m_polys = null;
m_smoothPath = null;
}
}
else if (_option.mode == RcTestNavmeshToolMode.PATHFIND_STRAIGHT)
{
if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0)
{
var polys = new List<long>();
var straightPath = new List<StraightPathItem>();
var status = _tool.FindStraightPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast,
ref polys, ref straightPath, _option.straightPathOptions);
if (status.Succeeded())
{
m_polys = polys;
m_straightPath = straightPath;
}
}
else
{
m_straightPath = null;
}
}
else if (_option.mode == RcTestNavmeshToolMode.PATHFIND_SLICED)
{
m_polys = null;
m_straightPath = null;
if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0)
{
m_pathFindStatus = _tool.InitSlicedFindPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast);
}
}
else if (_option.mode == RcTestNavmeshToolMode.RAYCAST)
{
m_straightPath = null;
if (m_sposSet && m_eposSet && m_startRef != 0)
{
var polys = new List<long>();
var straightPath = new List<StraightPathItem>();
var status = _tool.Raycast(navQuery, m_startRef, m_spos, m_epos, m_filter,
ref polys, ref straightPath, out var hitPos, out var hitNormal, out var hitResult);
if (status.Succeeded())
{
m_polys = polys;
m_straightPath = straightPath;
m_hitPos = hitPos;
m_hitNormal = hitNormal;
m_hitResult = hitResult;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.DISTANCE_TO_WALL)
{
m_distanceToWall = 0;
if (m_sposSet && m_startRef != 0)
{
var result = navQuery.FindDistanceToWall(m_startRef, m_spos, 100.0f, m_filter, out var hitDist, out var hitPos, out var hitNormal);
if (result.Succeeded())
{
m_distanceToWall = hitDist;
m_hitPos = hitPos;
m_hitNormal = hitNormal;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.FIND_POLYS_IN_CIRCLE)
{
if (m_sposSet && m_startRef != 0 && m_eposSet)
{
List<long> refs = new();
List<long> parentRefs = new();
var status = _tool.FindPolysAroundCircle(navQuery, m_startRef, m_spos, m_epos, m_filter, ref refs, ref parentRefs);
if (status.Succeeded())
{
m_polys = refs;
m_parent = parentRefs;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.FIND_POLYS_IN_SHAPE)
{
if (m_sposSet && m_startRef != 0 && m_eposSet)
{
var refs = new List<long>();
var parentRefs = new List<long>();
var status = _tool.FindPolysAroundShape(navQuery, settings, m_startRef, m_spos, m_epos, m_filter, ref refs, ref parentRefs, out var queryPoly);
if (status.Succeeded())
{
m_queryPoly = queryPoly;
m_polys = refs;
m_parent = parentRefs;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.FIND_LOCAL_NEIGHBOURHOOD)
{
if (m_sposSet && m_startRef != 0)
{
m_neighbourhoodRadius = settings.agentRadius * 20.0f;
List<long> resultRef = new();
List<long> resultParent = new();
var status = navQuery.FindLocalNeighbourhood(m_startRef, m_spos, m_neighbourhoodRadius, m_filter, ref resultRef, ref resultParent);
if (status.Succeeded())
{
m_polys = resultRef;
m_parent = resultParent;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.RANDOM_POINTS_IN_CIRCLE)
{
randomPoints.Clear();
if (m_sposSet && m_startRef != 0 && m_eposSet)
{
var points = new List<RcVec3f>();
_tool.FindRandomPointAroundCircle(navQuery, m_startRef, m_spos, m_epos, m_filter, _option.constrainByCircle, 500, ref points);
randomPoints.AddRange(points);
}
}
}
public void HandleRender(NavMeshRenderer renderer) public void HandleRender(NavMeshRenderer renderer)
{ {
RecastDebugDraw dd = renderer.GetDebugDraw(); RecastDebugDraw dd = renderer.GetDebugDraw();
@ -783,6 +578,211 @@ public class TestNavmeshSampleTool : ISampleTool
dd.DepthMask(true); dd.DepthMask(true);
} }
public IRcToolable GetTool()
{
return _tool;
}
public void SetSample(DemoSample sample)
{
_sample = sample;
}
public void OnSampleChanged()
{
// ..
}
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
{
if (shift)
{
m_sposSet = true;
m_spos = p;
}
else
{
m_eposSet = true;
m_epos = p;
}
Recalc();
}
private void Recalc()
{
var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings();
var navMesh = _sample.GetNavMesh();
var navQuery = _sample.GetNavMeshQuery();
if (null == geom || null == navQuery)
return;
if (m_sposSet)
{
navQuery.FindNearestPoly(m_spos, m_polyPickExt, m_filter, out m_startRef, out var _, out var _);
}
else
{
m_startRef = 0;
}
if (m_eposSet)
{
navQuery.FindNearestPoly(m_epos, m_polyPickExt, m_filter, out m_endRef, out var _, out var _);
}
else
{
m_endRef = 0;
}
if (_option.mode == RcTestNavmeshToolMode.PATHFIND_FOLLOW)
{
if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0)
{
var polys = new List<long>();
var smoothPath = new List<RcVec3f>();
var status = _tool.FindFollowPath(navMesh, navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast,
ref polys, ref smoothPath);
if (status.Succeeded())
{
m_polys = polys;
m_smoothPath = smoothPath;
}
}
else
{
m_polys = null;
m_smoothPath = null;
}
}
else if (_option.mode == RcTestNavmeshToolMode.PATHFIND_STRAIGHT)
{
if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0)
{
var polys = new List<long>();
var straightPath = new List<StraightPathItem>();
var status = _tool.FindStraightPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast,
ref polys, ref straightPath, _option.straightPathOptions);
if (status.Succeeded())
{
m_polys = polys;
m_straightPath = straightPath;
}
}
else
{
m_straightPath = null;
}
}
else if (_option.mode == RcTestNavmeshToolMode.PATHFIND_SLICED)
{
m_polys = null;
m_straightPath = null;
if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0)
{
m_pathFindStatus = _tool.InitSlicedFindPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _option.enableRaycast);
}
}
else if (_option.mode == RcTestNavmeshToolMode.RAYCAST)
{
m_straightPath = null;
if (m_sposSet && m_eposSet && m_startRef != 0)
{
var polys = new List<long>();
var straightPath = new List<StraightPathItem>();
var status = _tool.Raycast(navQuery, m_startRef, m_spos, m_epos, m_filter,
ref polys, ref straightPath, out var hitPos, out var hitNormal, out var hitResult);
if (status.Succeeded())
{
m_polys = polys;
m_straightPath = straightPath;
m_hitPos = hitPos;
m_hitNormal = hitNormal;
m_hitResult = hitResult;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.DISTANCE_TO_WALL)
{
m_distanceToWall = 0;
if (m_sposSet && m_startRef != 0)
{
var result = navQuery.FindDistanceToWall(m_startRef, m_spos, 100.0f, m_filter, out var hitDist, out var hitPos, out var hitNormal);
if (result.Succeeded())
{
m_distanceToWall = hitDist;
m_hitPos = hitPos;
m_hitNormal = hitNormal;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.FIND_POLYS_IN_CIRCLE)
{
if (m_sposSet && m_startRef != 0 && m_eposSet)
{
List<long> refs = new();
List<long> parentRefs = new();
var status = _tool.FindPolysAroundCircle(navQuery, m_startRef, m_spos, m_epos, m_filter, ref refs, ref parentRefs);
if (status.Succeeded())
{
m_polys = refs;
m_parent = parentRefs;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.FIND_POLYS_IN_SHAPE)
{
if (m_sposSet && m_startRef != 0 && m_eposSet)
{
var refs = new List<long>();
var parentRefs = new List<long>();
var status = _tool.FindPolysAroundShape(navQuery, settings, m_startRef, m_spos, m_epos, m_filter, ref refs, ref parentRefs, out var queryPoly);
if (status.Succeeded())
{
m_queryPoly = queryPoly;
m_polys = refs;
m_parent = parentRefs;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.FIND_LOCAL_NEIGHBOURHOOD)
{
if (m_sposSet && m_startRef != 0)
{
m_neighbourhoodRadius = settings.agentRadius * 20.0f;
List<long> resultRef = new();
List<long> resultParent = new();
var status = navQuery.FindLocalNeighbourhood(m_startRef, m_spos, m_neighbourhoodRadius, m_filter, ref resultRef, ref resultParent);
if (status.Succeeded())
{
m_polys = resultRef;
m_parent = resultParent;
}
}
}
else if (_option.mode == RcTestNavmeshToolMode.RANDOM_POINTS_IN_CIRCLE)
{
randomPoints.Clear();
if (m_sposSet && m_startRef != 0 && m_eposSet)
{
var points = new List<RcVec3f>();
_tool.FindRandomPointAroundCircle(navQuery, m_startRef, m_spos, m_epos, m_filter, _option.constrainByCircle, 500, ref points);
randomPoints.AddRange(points);
}
}
}
public void HandleUpdate(float dt) public void HandleUpdate(float dt)
{ {

View File

@ -25,20 +25,6 @@ public class TileSampleTool : ISampleTool
_tool = new(); _tool = new();
} }
public IRcToolable GetTool()
{
return _tool;
}
public void SetSample(DemoSample sample)
{
_sample = sample;
}
public void OnSampleChanged()
{
}
public void Layout() public void Layout()
{ {
var geom = _sample.GetInputGeom(); var geom = _sample.GetInputGeom();
@ -56,33 +42,6 @@ public class TileSampleTool : ISampleTool
} }
} }
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
{
_hitPosSet = true;
_hitPos = p;
var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings();
var navMesh = _sample.GetNavMesh();
if (shift)
{
_tool.RemoveTile(geom, settings, navMesh, _hitPos);
}
else
{
bool built = _tool.BuildTile(geom, settings, navMesh, _hitPos, out var tileBuildTicks, out var tileTriCount, out var tileMemUsage);
if (!built)
{
Logger.Error($"failed to build tile - check!");
}
else
{
Logger.Information($"{tileBuildTicks / (float)TimeSpan.TicksPerMillisecond}ms / {tileTriCount}Tris / {tileMemUsage}kB ");
}
}
}
public void HandleRender(NavMeshRenderer renderer) public void HandleRender(NavMeshRenderer renderer)
{ {
var geom = _sample.GetInputGeom(); var geom = _sample.GetInputGeom();
@ -124,6 +83,49 @@ public class TileSampleTool : ISampleTool
} }
} }
public IRcToolable GetTool()
{
return _tool;
}
public void SetSample(DemoSample sample)
{
_sample = sample;
}
public void OnSampleChanged()
{
}
public void HandleClick(RcVec3f s, RcVec3f p, bool shift)
{
_hitPosSet = true;
_hitPos = p;
var geom = _sample.GetInputGeom();
var settings = _sample.GetSettings();
var navMesh = _sample.GetNavMesh();
if (shift)
{
_tool.RemoveTile(geom, settings, navMesh, _hitPos);
}
else
{
bool built = _tool.BuildTile(geom, settings, navMesh, _hitPos, out var tileBuildTicks, out var tileTriCount, out var tileMemUsage);
if (!built)
{
Logger.Error($"failed to build tile - check!");
}
else
{
Logger.Information($"{tileBuildTicks / (float)TimeSpan.TicksPerMillisecond}ms / {tileTriCount}Tris / {tileMemUsage}kB ");
}
}
}
public void HandleUpdate(float dt) public void HandleUpdate(float dt)
{ {
} }