forked from mirror/DotRecast
typo
This commit is contained in:
parent
db13598295
commit
303f194fe7
|
@ -54,6 +54,91 @@ public class ConvexVolumeSampleTool : ISampleTool
|
|||
_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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
namespace DotRecast.Recast.Demo.Tools;
|
||||
|
||||
public class CrowdFlowTool
|
||||
{
|
||||
// ...
|
||||
}
|
|
@ -65,6 +65,124 @@ public class CrowdProfilingSampleTool : ISampleTool
|
|||
_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)
|
||||
{
|
||||
_sample = sample;
|
||||
|
@ -105,81 +223,6 @@ public class CrowdProfilingSampleTool : ISampleTool
|
|||
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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ public class CrowdSampleTool : ISampleTool
|
|||
private readonly CrowdOption _option = new CrowdOption();
|
||||
private DtNavMesh m_nav;
|
||||
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 RcVec3f m_targetPos;
|
||||
|
@ -53,28 +53,140 @@ public class CrowdSampleTool : ISampleTool
|
|||
private int m_modeIdx = CrowdToolMode.CREATE.Idx;
|
||||
private long crowdUpdateTime;
|
||||
|
||||
private int m_expandSelectedDebugDraw = 1;
|
||||
private bool m_showCorners;
|
||||
private bool m_showCollisionSegments;
|
||||
private bool m_showPath;
|
||||
private bool m_showVO;
|
||||
private bool m_showOpt;
|
||||
private bool m_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 _expandSelectedDebugDraw = 1;
|
||||
private bool _showCorners;
|
||||
private bool _showCollisionSegments;
|
||||
private bool _showPath;
|
||||
private bool _showVO;
|
||||
private bool _showOpt;
|
||||
private bool _showNeis;
|
||||
|
||||
private int _expandDebugDraw = 0;
|
||||
private bool _showLabels;
|
||||
private bool _showGrid;
|
||||
private bool _showNodes;
|
||||
private bool _showPerfGraph;
|
||||
private bool _showDetailAll;
|
||||
|
||||
public CrowdSampleTool()
|
||||
{
|
||||
m_agentDebug.vod = new DtObstacleAvoidanceDebugData(2048);
|
||||
_agentDebug.vod = new DtObstacleAvoidanceDebugData(2048);
|
||||
_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()
|
||||
{
|
||||
return _tool;
|
||||
|
@ -96,9 +208,11 @@ public class CrowdSampleTool : ISampleTool
|
|||
m_nav = navMesh;
|
||||
|
||||
DtCrowdConfig config = new DtCrowdConfig(settings.agentRadius);
|
||||
|
||||
crowd = new DtCrowd(config, navMesh, __ => new DtQueryDefaultFilter(SampleAreaModifications.SAMPLE_POLYFLAGS_ALL,
|
||||
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED, new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f }));
|
||||
crowd = new DtCrowd(config, navMesh, __ => new DtQueryDefaultFilter(
|
||||
SampleAreaModifications.SAMPLE_POLYFLAGS_ALL,
|
||||
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
|
||||
new float[] { 1f, 10f, 1f, 1f, 2f, 1.5f })
|
||||
);
|
||||
|
||||
// Setup local avoidance option to different qualities.
|
||||
// Use mostly default settings, copy from dtCrowd.
|
||||
|
@ -167,7 +281,7 @@ public class CrowdSampleTool : ISampleTool
|
|||
{
|
||||
// Highlight
|
||||
DtCrowdAgent ahit = HitTestAgents(s, p);
|
||||
HilightAgent(ahit);
|
||||
HighlightAgent(ahit);
|
||||
}
|
||||
else if (m_mode == CrowdToolMode.TOGGLE_POLYS)
|
||||
{
|
||||
|
@ -193,9 +307,9 @@ public class CrowdSampleTool : ISampleTool
|
|||
private void RemoveAgent(DtCrowdAgent 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)
|
||||
{
|
||||
// Request velocity
|
||||
if (m_agentDebug.agent != null)
|
||||
if (_agentDebug.agent != null)
|
||||
{
|
||||
RcVec3f vel = CalcVel(m_agentDebug.agent.npos, p, m_agentDebug.agent.option.maxSpeed);
|
||||
crowd.RequestMoveVelocity(m_agentDebug.agent, vel);
|
||||
RcVec3f vel = CalcVel(_agentDebug.agent.npos, p, _agentDebug.agent.option.maxSpeed);
|
||||
crowd.RequestMoveVelocity(_agentDebug.agent, vel);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -309,9 +423,9 @@ public class CrowdSampleTool : ISampleTool
|
|||
else
|
||||
{
|
||||
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
|
||||
{
|
||||
|
@ -331,315 +445,8 @@ public class CrowdSampleTool : ISampleTool
|
|||
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)
|
||||
{
|
||||
UpdateTick(dt);
|
||||
}
|
||||
|
||||
private void UpdateTick(float dt)
|
||||
{
|
||||
if (crowd == null)
|
||||
return;
|
||||
|
@ -649,7 +456,7 @@ public class CrowdSampleTool : ISampleTool
|
|||
return;
|
||||
|
||||
long startTime = RcFrequency.Ticks;
|
||||
crowd.Update(dt, m_agentDebug);
|
||||
crowd.Update(dt, _agentDebug);
|
||||
long endTime = RcFrequency.Ticks;
|
||||
|
||||
// Update agent trails
|
||||
|
@ -663,77 +470,17 @@ public class CrowdSampleTool : ISampleTool
|
|||
trail.trail[trail.htrail * 3 + 2] = ag.npos.z;
|
||||
}
|
||||
|
||||
m_agentDebug.vod.NormalizeSamples();
|
||||
_agentDebug.vod.NormalizeSamples();
|
||||
|
||||
// m_crowdSampleCount.addSample((float) crowd.GetVelocitySampleCount());
|
||||
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()
|
||||
{
|
||||
|
|
|
@ -98,6 +98,243 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
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()
|
||||
{
|
||||
return _tool;
|
||||
|
@ -415,66 +652,6 @@ public class DynamicUpdateSampleTool : ISampleTool
|
|||
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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -42,24 +42,78 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
|||
_option = new();
|
||||
}
|
||||
|
||||
public IRcToolable GetTool()
|
||||
public void Layout()
|
||||
{
|
||||
return _tool;
|
||||
}
|
||||
if (0 >= _sample.GetRecastResults().Count)
|
||||
return;
|
||||
|
||||
public void SetSample(DemoSample sample)
|
||||
{
|
||||
_sample = sample;
|
||||
}
|
||||
ImGui.Text("Options");
|
||||
ImGui.Separator();
|
||||
ImGui.SliderFloat("Ground Tolerance", ref _option.groundTolerance, 0f, 2f, "%.2f");
|
||||
ImGui.NewLine();
|
||||
|
||||
public void OnSampleChanged()
|
||||
{
|
||||
_tool.Clear();
|
||||
}
|
||||
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();
|
||||
|
||||
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)
|
||||
|
@ -326,6 +380,28 @@ public class JumpLinkBuilderSampleTool : ISampleTool
|
|||
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)
|
||||
{
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -24,20 +24,6 @@ public class ObstacleSampleTool : ISampleTool
|
|||
_tool = new(DtTileCacheCompressorFactory.Shared);
|
||||
}
|
||||
|
||||
public IRcToolable GetTool()
|
||||
{
|
||||
return _tool;
|
||||
}
|
||||
|
||||
public void SetSample(DemoSample sample)
|
||||
{
|
||||
_sample = sample;
|
||||
}
|
||||
|
||||
public void OnSampleChanged()
|
||||
{
|
||||
}
|
||||
|
||||
public void Layout()
|
||||
{
|
||||
if (ImGui.Button("Build Tile Cache"))
|
||||
|
@ -45,13 +31,12 @@ public class ObstacleSampleTool : ISampleTool
|
|||
var geom = _sample.GetInputGeom();
|
||||
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)
|
||||
{
|
||||
_sample.Update(_sample.GetInputGeom(), buildResult.RecastBuilderResults, buildResult.NavMesh);
|
||||
_sample.SetChanged(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ImGui.Button("Remove All Temp Obstacles"))
|
||||
|
@ -65,21 +50,6 @@ public class ObstacleSampleTool : ISampleTool
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var tc = _tool.GetTileCache();
|
||||
|
|
|
@ -45,6 +45,33 @@ public class OffMeshConnectionSampleTool : ISampleTool
|
|||
_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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
{
|
||||
_tool = new();
|
||||
_option = new RcTestNavmeshToolOption();
|
||||
|
||||
|
||||
m_filter = new DtQueryDefaultFilter(
|
||||
SampleAreaModifications.SAMPLE_POLYFLAGS_ALL,
|
||||
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
|
||||
|
@ -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()
|
||||
{
|
||||
var previousToolMode = _option.mode;
|
||||
|
@ -163,186 +131,13 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
ImGui.Checkbox("Raycast shortcuts", ref _option.enableRaycast);
|
||||
|
||||
if (previousToolMode != _option.mode || _option.straightPathOptions != previousStraightPathOptions
|
||||
|| previousIncludeFlags != _option.includeFlags || previousExcludeFlags != _option.excludeFlags
|
||||
|| previousEnableRaycast != _option.enableRaycast || previousConstrainByCircle != _option.constrainByCircle)
|
||||
|| previousIncludeFlags != _option.includeFlags || previousExcludeFlags != _option.excludeFlags
|
||||
|| previousEnableRaycast != _option.enableRaycast || previousConstrainByCircle != _option.constrainByCircle)
|
||||
{
|
||||
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)
|
||||
{
|
||||
RecastDebugDraw dd = renderer.GetDebugDraw();
|
||||
|
@ -783,6 +578,211 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
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)
|
||||
{
|
||||
|
@ -790,7 +790,7 @@ public class TestNavmeshSampleTool : ISampleTool
|
|||
if (_option.mode == RcTestNavmeshToolMode.PATHFIND_SLICED)
|
||||
{
|
||||
DtNavMeshQuery navQuery = _sample.GetNavMeshQuery();
|
||||
|
||||
|
||||
if (m_pathFindStatus.InProgress())
|
||||
{
|
||||
m_pathFindStatus = _tool.UpdateSlicedFindPath(navQuery, 1, m_endRef, m_spos, m_epos, ref m_polys, ref m_straightPath);
|
||||
|
|
|
@ -25,26 +25,12 @@ public class TileSampleTool : ISampleTool
|
|||
_tool = new();
|
||||
}
|
||||
|
||||
public IRcToolable GetTool()
|
||||
{
|
||||
return _tool;
|
||||
}
|
||||
|
||||
public void SetSample(DemoSample sample)
|
||||
{
|
||||
_sample = sample;
|
||||
}
|
||||
|
||||
public void OnSampleChanged()
|
||||
{
|
||||
}
|
||||
|
||||
public void Layout()
|
||||
{
|
||||
var geom = _sample.GetInputGeom();
|
||||
var settings = _sample.GetSettings();
|
||||
var navMesh = _sample.GetNavMesh();
|
||||
|
||||
|
||||
if (ImGui.Button("Create All Tile"))
|
||||
{
|
||||
_tool.BuildAllTiles(geom, settings, navMesh);
|
||||
|
@ -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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue