- added finalizeSlicedFindPathPartial()

- added handleStep()/handleToggle() to samples
- changed how crowds are rendered
- added path topology optimization step
This commit is contained in:
Mikko Mononen 2010-11-07 10:56:48 +00:00
parent e5d603ac92
commit ccf401d3da
26 changed files with 2619 additions and 1964 deletions

View File

@ -140,6 +140,9 @@ void duDebugDrawCross(struct duDebugDraw* dd, const float x, const float y, cons
void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, const unsigned int* fcol);
void duDebugDrawCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, unsigned int col);
void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz,
const int w, const int h, const float size,
const unsigned int col, const float lineWidth);
@ -172,6 +175,9 @@ void duAppendCross(struct duDebugDraw* dd, const float x, const float y, const f
void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, const unsigned int* fcol);
void duAppendCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, unsigned int col);
class duDisplayList : public duDebugDraw
{

View File

@ -135,6 +135,16 @@ void duDebugDrawBox(struct duDebugDraw* dd, float minx, float miny, float minz,
dd->end();
}
void duDebugDrawCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, unsigned int col)
{
if (!dd) return;
dd->begin(DU_DRAW_TRIS);
duAppendCylinder(dd, minx,miny,minz, maxx,maxy,maxz, col);
dd->end();
}
void duDebugDrawGridXZ(struct duDebugDraw* dd, const float ox, const float oy, const float oz,
const int w, const int h, const float size,
const unsigned int col, const float lineWidth)
@ -289,6 +299,58 @@ void duAppendBox(struct duDebugDraw* dd, float minx, float miny, float minz,
}
}
void duAppendCylinder(struct duDebugDraw* dd, float minx, float miny, float minz,
float maxx, float maxy, float maxz, unsigned int col)
{
if (!dd) return;
static const int NUM_SEG = 16;
static float dir[NUM_SEG*2];
static bool init = false;
if (!init)
{
init = true;
for (int i = 0; i < NUM_SEG; ++i)
{
const float a = (float)i/(float)NUM_SEG*DU_PI*2;
dir[i*2] = cosf(a);
dir[i*2+1] = sinf(a);
}
}
unsigned int col2 = duMultCol(col, 160);
const float cx = (maxx + minx)/2;
const float cz = (maxz + minz)/2;
const float rx = (maxx - minx)/2;
const float rz = (maxz - minz)/2;
for (int i = 2; i < NUM_SEG; ++i)
{
const int a = 0, b = i-1, c = i;
dd->vertex(cx+dir[a*2+0]*rx, miny, cz+dir[a*2+1]*rz, col2);
dd->vertex(cx+dir[b*2+0]*rx, miny, cz+dir[b*2+1]*rz, col2);
dd->vertex(cx+dir[c*2+0]*rx, miny, cz+dir[c*2+1]*rz, col2);
}
for (int i = 2; i < NUM_SEG; ++i)
{
const int a = 0, b = i, c = i-1;
dd->vertex(cx+dir[a*2+0]*rx, maxy, cz+dir[a*2+1]*rz, col);
dd->vertex(cx+dir[b*2+0]*rx, maxy, cz+dir[b*2+1]*rz, col);
dd->vertex(cx+dir[c*2+0]*rx, maxy, cz+dir[c*2+1]*rz, col);
}
for (int i = 0, j = NUM_SEG-1; i < NUM_SEG; j = i++)
{
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
dd->vertex(cx+dir[j*2+0]*rx, miny, cz+dir[j*2+1]*rz, col2);
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
dd->vertex(cx+dir[i*2+0]*rx, miny, cz+dir[i*2+1]*rz, col2);
dd->vertex(cx+dir[j*2+0]*rx, maxy, cz+dir[j*2+1]*rz, col);
dd->vertex(cx+dir[i*2+0]*rx, maxy, cz+dir[i*2+1]*rz, col);
}
}
inline void evalArc(const float x0, const float y0, const float z0,
const float dx, const float dy, const float dz,

View File

@ -72,9 +72,9 @@ static void drawPolyBoundaries(duDebugDraw* dd, const dtMeshTile* tile,
}
}
if (con)
c = duRGBA(255,255,255,64);
c = duRGBA(255,255,255,24);
else
c = duRGBA(0,0,0,128);
c = duRGBA(0,0,0,48);
}
else
c = duRGBA(0,48,64,32);

View File

@ -173,12 +173,22 @@ public:
// Returns: Path query state.
dtStatus updateSlicedFindPath(const int maxIter);
// Finalizes sliced path find query.
// Finalizes sliced path find query and returns found path.
// path - (out) array holding the search result.
// pathCount - (out) Number of polygons in search result array.
// maxPath - (in) The max number of polygons the path array can hold.
dtStatus finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath);
// Finalizes partial sliced path find query and returns path to the furthest
// polygon on the existing path that was visited during the search.
// existing - (out) Array of polygons in the existing path.
// existingSize - (out) Number of polygons in existing path array.
// path - (out) array holding the search result.
// pathCount - (out) Number of polygons in search result array.
// maxPath - (in) The max number of polygons the path array can hold.
dtStatus finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
dtPolyRef* path, int* pathCount, const int maxPath);
// Finds a straight path from start to end locations within the corridor
// described by the path polygons.
// Start and end locations will be clamped on the corridor.

View File

@ -47,7 +47,7 @@ public:
inline void operator=(const dtNodePool&) {}
void clear();
dtNode* getNode(dtPolyRef id);
const dtNode* findNode(dtPolyRef id) const;
dtNode* findNode(dtPolyRef id);
inline unsigned int getNodeIdx(const dtNode* node) const
{

View File

@ -1015,6 +1015,75 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount,
return DT_SUCCESS;
}
dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize,
dtPolyRef* path, int* pathCount, const int maxPath)
{
*pathCount = 0;
if (existingSize == 0)
{
return DT_FAILURE;
}
if (m_query.status != DT_SUCCESS && m_query.status != DT_IN_PROGRESS)
{
// Reset query.
memset(&m_query, 0, sizeof(dtQueryData));
return DT_FAILURE;
}
int n = 0;
if (m_query.startRef == m_query.endRef)
{
// Special case: the search starts and ends at same poly.
path[n++] = m_query.startRef;
}
else
{
// Find furthest existing node that was visited.
dtNode* prev = 0;
dtNode* node = 0;
for (int i = existingSize-1; i >= 0; --i)
{
node = m_nodePool->findNode(existing[i]);
if (node)
break;
}
if (!node)
{
return DT_FAILURE;
}
// Reverse the path.
do
{
dtNode* next = m_nodePool->getNodeAtIdx(node->pidx);
node->pidx = m_nodePool->getNodeIdx(prev);
prev = node;
node = next;
}
while (node);
// Store path
node = prev;
do
{
path[n++] = node->id;
node = m_nodePool->getNodeAtIdx(node->pidx);
}
while (node && n < maxPath);
}
// Reset query.
memset(&m_query, 0, sizeof(dtQueryData));
*pathCount = n;
return DT_SUCCESS;
}
dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* endPos,
const dtPolyRef* path, const int pathSize,

View File

@ -70,7 +70,7 @@ void dtNodePool::clear()
m_nodeCount = 0;
}
const dtNode* dtNodePool::findNode(dtPolyRef id) const
dtNode* dtNodePool::findNode(dtPolyRef id)
{
unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
unsigned short i = m_first[bucket];

File diff suppressed because it is too large Load Diff

View File

@ -284,14 +284,14 @@
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array>
<array>
<integer>59</integer>
<integer>52</integer>
<integer>51</integer>
<integer>1</integer>
<integer>0</integer>
</array>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
<string>{{0, 590}, {264, 660}}</string>
<string>{{0, 577}, {264, 622}}</string>
</dict>
<key>PBXTopSmartGroupGIDs</key>
<array/>
@ -301,14 +301,14 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {281, 678}}</string>
<string>{{0, 0}, {281, 640}}</string>
<key>GroupTreeTableConfiguration</key>
<array>
<string>MainColumn</string>
<real>264</real>
</array>
<key>RubberWindowFrame</key>
<string>0 59 1278 719 0 0 1280 778 </string>
<string>47 97 1200 681 0 0 1280 778 </string>
</dict>
<key>Module</key>
<string>PBXSmartGroupTreeModule</string>
@ -326,7 +326,7 @@
<key>PBXProjectModuleGUID</key>
<string>6B8632A30F78115100E2684A</string>
<key>PBXProjectModuleLabel</key>
<string>NavMeshTesterTool.cpp</string>
<string>CrowdTool.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
@ -334,29 +334,46 @@
<key>PBXProjectModuleGUID</key>
<string>6B8632A40F78115100E2684A</string>
<key>PBXProjectModuleLabel</key>
<string>NavMeshTesterTool.cpp</string>
<string>CrowdTool.cpp</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>6B8D56DA127AEC580077C699</string>
<string>6B74B7631286BB6900262888</string>
<key>history</key>
<array>
<string>6B8D565F127ADB0D0077C699</string>
<string>6B8D566D127ADB7D0077C699</string>
<string>6B8D566F127ADB7D0077C699</string>
<string>6B8D56C7127AEC100077C699</string>
<string>6B8D56C8127AEC100077C699</string>
<string>6B8D56C9127AEC100077C699</string>
<string>6B8D56CA127AEC100077C699</string>
<string>6B8D56CB127AEC100077C699</string>
<string>6B8D56CC127AEC100077C699</string>
<string>6B8D56CD127AEC100077C699</string>
<string>6B8D56CE127AEC100077C699</string>
<string>6B8D56CF127AEC100077C699</string>
<string>6B8D56D0127AEC100077C699</string>
<string>6B8D56D2127AEC100077C699</string>
<string>6B8D56D8127AEC580077C699</string>
<string>6B8D56D9127AEC580077C699</string>
<string>6B4DE62F12807542001CFDF4</string>
<string>6B4DE647128079E0001CFDF4</string>
<string>6B4DE649128079E0001CFDF4</string>
<string>6B4DE64A128079E0001CFDF4</string>
<string>6B74B5F3128312AC00262888</string>
<string>6B74B5F4128312AC00262888</string>
<string>6B74B60F128312E900262888</string>
<string>6B74B623128314A500262888</string>
<string>6B74B624128314A500262888</string>
<string>6B74B626128314A500262888</string>
<string>6B74B627128314A500262888</string>
<string>6B74B628128314A500262888</string>
<string>6B74B629128314A500262888</string>
<string>6B74B62A128314A500262888</string>
<string>6B74B62B128314A500262888</string>
<string>6B74B62C128314A500262888</string>
<string>6B74B66412869CE100262888</string>
<string>6B74B66712869CE100262888</string>
<string>6B74B66F12869E3000262888</string>
<string>6B74B6BF1286AA0C00262888</string>
<string>6B74B6D81286ABC000262888</string>
<string>6B74B6FC1286AE0B00262888</string>
<string>6B74B7061286AEBD00262888</string>
<string>6B74B7071286AEBD00262888</string>
<string>6B74B7401286B7C400262888</string>
<string>6B74B75F1286BB6900262888</string>
<string>6B74B7601286BB6900262888</string>
<string>6B74B7611286BB6900262888</string>
<string>6B74B7621286BB6900262888</string>
</array>
</dict>
<key>SplitCount</key>
@ -370,18 +387,18 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {992, 434}}</string>
<string>{{0, 0}, {914, 472}}</string>
<key>RubberWindowFrame</key>
<string>0 59 1278 719 0 0 1280 778 </string>
<string>47 97 1200 681 0 0 1280 778 </string>
</dict>
<key>Module</key>
<string>PBXNavigatorGroup</string>
<key>Proportion</key>
<string>434pt</string>
<string>472pt</string>
</dict>
<dict>
<key>Proportion</key>
<string>239pt</string>
<string>164pt</string>
<key>Tabs</key>
<array>
<dict>
@ -395,7 +412,7 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {992, -27}}</string>
<string>{{10, 27}, {992, 49}}</string>
</dict>
<key>Module</key>
<string>XCDetailModule</string>
@ -411,7 +428,7 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {992, 212}}</string>
<string>{{10, 27}, {992, 169}}</string>
</dict>
<key>Module</key>
<string>PBXProjectFindModule</string>
@ -449,9 +466,9 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {992, 212}}</string>
<string>{{10, 27}, {914, 137}}</string>
<key>RubberWindowFrame</key>
<string>0 59 1278 719 0 0 1280 778 </string>
<string>47 97 1200 681 0 0 1280 778 </string>
</dict>
<key>Module</key>
<string>PBXBuildResultsModule</string>
@ -460,7 +477,7 @@
</dict>
</array>
<key>Proportion</key>
<string>992pt</string>
<string>914pt</string>
</dict>
</array>
<key>Name</key>
@ -479,11 +496,11 @@
</array>
<key>TableOfContents</key>
<array>
<string>6B8D5625127AD44A0077C699</string>
<string>6B74B5DD1283104100262888</string>
<string>1CA23ED40692098700951B8B</string>
<string>6B8D5626127AD44A0077C699</string>
<string>6B74B5DE1283104100262888</string>
<string>6B8632A30F78115100E2684A</string>
<string>6B8D5627127AD44A0077C699</string>
<string>6B74B5DF1283104100262888</string>
<string>1CA23EDF0692099D00951B8B</string>
<string>1CA23EE00692099D00951B8B</string>
<string>1CA23EE10692099D00951B8B</string>
@ -631,14 +648,14 @@
</array>
<key>TableOfContents</key>
<array>
<string>6B8D563A127AD6CA0077C699</string>
<string>6B74B5FD128312AC00262888</string>
<string>1CCC7628064C1048000F2A68</string>
<string>1CCC7629064C1048000F2A68</string>
<string>6B8D563B127AD6CA0077C699</string>
<string>6B8D563C127AD6CA0077C699</string>
<string>6B8D563D127AD6CA0077C699</string>
<string>6B8D563E127AD6CA0077C699</string>
<string>6B8D563F127AD6CA0077C699</string>
<string>6B74B5FE128312AC00262888</string>
<string>6B74B5FF128312AC00262888</string>
<string>6B74B600128312AC00262888</string>
<string>6B74B601128312AC00262888</string>
<string>6B74B602128312AC00262888</string>
</array>
<key>ToolbarConfigUserDefaultsMinorVersion</key>
<string>2</string>
@ -670,13 +687,12 @@
<integer>5</integer>
<key>WindowOrderList</key>
<array>
<string>6B8D56D5127AEC100077C699</string>
<string>6B8D56D6127AEC100077C699</string>
<string>6B8D56D7127AEC100077C699</string>
<string>6B74B604128312AC00262888</string>
<string>6B74B605128312AC00262888</string>
<string>/Users/memon/Code/recastnavigation/RecastDemo/Build/Xcode/Recast.xcodeproj</string>
</array>
<key>WindowString</key>
<string>0 59 1278 719 0 0 1280 778 </string>
<string>47 97 1200 681 0 0 1280 778 </string>
<key>WindowToolsV3</key>
<array>
<dict>

View File

@ -45,6 +45,7 @@ public:
virtual void reset();
virtual void handleMenu();
virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep();
virtual void handleUpdate(const float dt);
virtual void handleRender();

View File

@ -138,9 +138,11 @@ public:
dtPolyRef* cornerPolys, const int maxCorners,
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void optimizePath(const float* next, const float pathOptimizationRange,
void optimizePathVisibility(const float* next, const float pathOptimizationRange,
dtNavMeshQuery* navquery, const dtQueryFilter* filter);
bool optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void moveTargetPosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
@ -216,6 +218,8 @@ struct Agent
float collisionQueryRange;
float pathOptimizationRange;
float topologyOptTime;
Neighbour neis[AGENT_MAX_NEIGHBOURS];
int nneis;
@ -243,6 +247,8 @@ enum UpdateFlags
CROWDMAN_ANTICIPATE_TURNS = 1,
CROWDMAN_USE_VO = 2,
CROWDMAN_DRUNK = 4,
CROWDMAN_OPTIMIZE_VIS = 8,
CROWDMAN_OPTIMIZE_TOPO = 16,
};
@ -295,6 +301,9 @@ class CrowdManager
int getNeighbours(const float* pos, const float height, const float range,
const Agent* skip, Neighbour* result, const int maxResult);
void updateTopologyOptimization(const float dt, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void updateMoveRequest(const float dt, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
public:
CrowdManager();
~CrowdManager();
@ -309,7 +318,6 @@ public:
bool adjustMoveTarget(const int idx, dtPolyRef ref, const float* pos);
int getActiveAgents(Agent** agents, const int maxAgents);
void updateMoveRequest(const float dt, dtNavMeshQuery* navquery, const dtQueryFilter* filter);
void update(const float dt, unsigned int flags, dtNavMeshQuery* navquery);
const dtQueryFilter* getFilter() const { return &m_filter; }

View File

@ -44,9 +44,13 @@ class CrowdTool : public SampleTool
bool m_showVO;
bool m_showOpt;
bool m_showGrid;
bool m_showNodes;
bool m_showPerfGraph;
bool m_expandOptions;
bool m_anticipateTurns;
bool m_optimizeVis;
bool m_optimizeTopo;
bool m_useVO;
bool m_drunkMove;
@ -74,6 +78,7 @@ public:
virtual void reset();
virtual void handleMenu();
virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep();
virtual void handleUpdate(const float dt);
virtual void handleRender();

View File

@ -93,6 +93,7 @@ public:
virtual void reset();
virtual void handleMenu();
virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep();
virtual void handleUpdate(const float dt);
virtual void handleRender();

View File

@ -40,6 +40,7 @@ public:
virtual void reset();
virtual void handleMenu();
virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep();
virtual void handleUpdate(const float dt);
virtual void handleRender();

View File

@ -65,6 +65,7 @@ struct SampleTool
virtual void handleClick(const float* s, const float* p, bool shift) = 0;
virtual void handleRender() = 0;
virtual void handleRenderOverlay(double* proj, double* model, int* view) = 0;
virtual void handleToggle() = 0;
virtual void handleStep() = 0;
virtual void handleUpdate(const float dt) = 0;
};
@ -108,6 +109,7 @@ public:
virtual void handleTools();
virtual void handleDebugMode();
virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleToggle();
virtual void handleStep();
virtual void handleRender();
virtual void handleRenderOverlay(double* proj, double* model, int* view);

View File

@ -44,7 +44,7 @@ public:
virtual void handleTools();
virtual void handleDebugMode();
virtual void handleClick(const float* s, const float* p, bool shift);
virtual void handleStep();
virtual void handleToggle();
virtual void handleRender();
virtual void handleRenderOverlay(double* proj, double* model, int* view);
virtual void handleMeshChanged(class InputGeom* geom);

View File

@ -230,6 +230,10 @@ void ConvexVolumeTool::handleClick(const float* /*s*/, const float* p, bool shif
}
void ConvexVolumeTool::handleToggle()
{
}
void ConvexVolumeTool::handleStep()
{
}

View File

@ -506,7 +506,7 @@ int PathCorridor::findCorners(float* cornerVerts, unsigned char* cornerFlags,
return ncorners;
}
void PathCorridor::optimizePath(const float* next, const float pathOptimizationRange,
void PathCorridor::optimizePathVisibility(const float* next, const float pathOptimizationRange,
dtNavMeshQuery* navquery, const dtQueryFilter* filter)
{
dtAssert(m_path);
@ -539,6 +539,31 @@ void PathCorridor::optimizePath(const float* next, const float pathOptimizationR
}
}
bool PathCorridor::optimizePathTopology(dtNavMeshQuery* navquery, const dtQueryFilter* filter)
{
dtAssert(m_path);
if (m_npath < 3)
return false;
static const int MAX_ITER = 32;
static const int MAX_RES = 32;
dtPolyRef res[MAX_RES];
int nres = 0;
navquery->initSlicedFindPath(m_path[0], m_path[m_npath-1], m_pos, m_target, filter);
navquery->updateSlicedFindPath(MAX_ITER);
dtStatus status = navquery->finalizeSlicedFindPathPartial(m_path, m_npath, res, &nres, MAX_RES);
if (status == DT_SUCCESS && nres > 0)
{
m_npath = mergeCorridor(m_path, m_npath, m_maxPath, res, nres);
return true;
}
return false;
}
void PathCorridor::movePosition(const float* npos, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
{
dtAssert(m_path);
@ -876,6 +901,7 @@ int CrowdManager::addAgent(const float* pos, const float radius, const float hei
ag->height = height;
ag->collisionQueryRange = radius * 8;
ag->pathOptimizationRange = radius * 30;
ag->topologyOptTime = 0;
ag->nneis = 0;
dtVset(ag->dvel, 0,0,0);
@ -901,7 +927,9 @@ int CrowdManager::addAgent(const float* pos, const float radius, const float hei
void CrowdManager::removeAgent(const int idx)
{
if (idx >= 0 && idx < MAX_AGENTS)
memset(&m_agents[idx], 0, sizeof(Agent));
{
m_agents[idx].active = 0;
}
}
bool CrowdManager::requestMoveTarget(const int idx, dtPolyRef ref, const float* pos)
@ -1231,6 +1259,76 @@ void CrowdManager::updateMoveRequest(const float dt, dtNavMeshQuery* navquery, c
}
static int addToOptQueue(Agent* newag, Agent** agents, const int nagents, const int maxAgents)
{
// Insert neighbour based on greatest time.
int slot = 0;
if (!nagents)
{
slot = nagents;
}
else if (newag->topologyOptTime <= agents[nagents-1]->topologyOptTime)
{
if (nagents >= maxAgents)
return nagents;
slot = nagents;
}
else
{
int i;
for (i = 0; i < nagents; ++i)
if (newag->topologyOptTime >= agents[i]->topologyOptTime)
break;
const int tgt = i+1;
const int n = dtMin(nagents-i, maxAgents-tgt);
dtAssert(tgt+n <= maxAgents);
if (n > 0)
memmove(&agents[tgt], &agents[i], sizeof(Agent*)*n);
slot = i;
}
agents[slot] = newag;
return dtMin(nagents+1, maxAgents);
}
void CrowdManager::updateTopologyOptimization(const float dt, dtNavMeshQuery* navquery, const dtQueryFilter* filter)
{
Agent* agents[MAX_AGENTS];
int nagents = getActiveAgents(agents, MAX_AGENTS);
if (!nagents)
return;
const float OPT_TIME_THR = 0.5f; // seconds
const int OPT_MAX_AGENTS = 1;
Agent* queue[OPT_MAX_AGENTS];
int nqueue = 0;
for (int i = 0; i < nagents; ++i)
{
Agent* ag = agents[i];
ag->topologyOptTime += dt;
if (ag->topologyOptTime >= OPT_TIME_THR)
{
nqueue = addToOptQueue(ag, queue, nqueue, OPT_MAX_AGENTS);
}
}
for (int i = 0; i < nqueue; ++i)
{
Agent* ag = queue[i];
ag->corridor.optimizePathTopology(navquery, filter);
ag->topologyOptTime = 0;
}
}
void CrowdManager::update(const float dt, unsigned int flags, dtNavMeshQuery* navquery)
{
m_sampleCount = 0;
@ -1251,6 +1349,10 @@ void CrowdManager::update(const float dt, unsigned int flags, dtNavMeshQuery* na
// Update async move request and path finder.
updateMoveRequest(dt, navquery, &m_filter);
// Optimize path topology.
if (flags & CROWDMAN_OPTIMIZE_TOPO)
updateTopologyOptimization(dt, navquery, &m_filter);
// Register agents to proximity grid.
m_grid.clear();
for (int i = 0; i < nagents; ++i)
@ -1283,12 +1385,12 @@ void CrowdManager::update(const float dt, unsigned int flags, dtNavMeshQuery* na
// Check to see if the corner after the next corner is directly visible,
// and short cut to there.
if (ag->ncorners > 0)
if ((flags & CROWDMAN_OPTIMIZE_VIS) && ag->ncorners > 0)
{
const float* target = &ag->cornerVerts[dtMin(1,ag->ncorners-1)*3];
dtVcopy(ag->opts, ag->corridor.getPos());
dtVcopy(ag->opte, target);
ag->corridor.optimizePath(target, ag->pathOptimizationRange, navquery, &m_filter);
ag->corridor.optimizePathVisibility(target, ag->pathOptimizationRange, navquery, &m_filter);
}
else
{

View File

@ -95,7 +95,7 @@ CrowdTool::CrowdTool() :
m_oldFlags(0),
m_targetRef(0),
m_expandDebugDraw(false),
m_showLabels(true),
m_showLabels(false),
m_showCorners(false),
m_showTargets(false),
m_showCollisionSegments(false),
@ -103,8 +103,12 @@ CrowdTool::CrowdTool() :
m_showVO(false),
m_showOpt(false),
m_showGrid(false),
m_showNodes(false),
m_showPerfGraph(false),
m_expandOptions(true),
m_anticipateTurns(true),
m_optimizeVis(true),
m_optimizeTopo(true),
m_useVO(true),
m_drunkMove(false),
m_run(true),
@ -168,6 +172,10 @@ void CrowdTool::handleMenu()
if (m_expandOptions)
{
imguiIndent();
if (imguiCheck("Optimize Visibility", m_optimizeVis))
m_optimizeVis = !m_optimizeVis;
if (imguiCheck("Optimize Topology", m_optimizeTopo))
m_optimizeTopo = !m_optimizeTopo;
if (imguiCheck("Anticipate Turns", m_anticipateTurns))
m_anticipateTurns = !m_anticipateTurns;
if (imguiCheck("Use VO", m_useVO))
@ -199,6 +207,10 @@ void CrowdTool::handleMenu()
m_showOpt = !m_showOpt;
if (imguiCheck("Show Prox Grid", m_showGrid))
m_showGrid = !m_showGrid;
if (imguiCheck("Show Nodes", m_showNodes))
m_showNodes = !m_showNodes;
if (imguiCheck("Show Perf Graph", m_showPerfGraph))
m_showPerfGraph = !m_showPerfGraph;
imguiUnindent();
}
}
@ -280,6 +292,10 @@ void CrowdTool::handleClick(const float* s, const float* p, bool shift)
}
void CrowdTool::handleStep()
{
}
void CrowdTool::handleToggle()
{
m_run = !m_run;
}
@ -298,6 +314,10 @@ void CrowdTool::handleUpdate(const float dt)
flags |= CROWDMAN_USE_VO;
if (m_drunkMove)
flags |= CROWDMAN_DRUNK;
if (m_optimizeVis)
flags |= CROWDMAN_OPTIMIZE_VIS;
if (m_optimizeTopo)
flags |= CROWDMAN_OPTIMIZE_TOPO;
m_crowd.update(dt, flags, m_sample->getNavMeshQuery());
@ -316,31 +336,74 @@ void CrowdTool::handleRender()
if (!nmesh)
return;
if (m_targetRef)
duDebugDrawCross(&dd, m_targetPos[0],m_targetPos[1]+0.1f,m_targetPos[2], s, duRGBA(0,0,0,128), 2.0f);
dtNavMeshQuery* navquery = m_sample->getNavMeshQuery();
if (m_showNodes)
{
if (navquery)
duDebugDrawNavMeshNodes(&dd, *navquery);
}
dd.depthMask(false);
// Draw paths
if (m_showPath)
{
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float height = ag->height;
const float radius = ag->radius;
const float* pos = ag->npos;
const float* target = ag->corridor.getTarget();
const float* vel = ag->vel;
const float* dvel = ag->dvel;
dd.depthMask(false);
if (m_showPath)
{
const dtPolyRef* path = ag->corridor.getPath();
const int npath = ag->corridor.getPathCount();
for (int i = 0; i < npath; ++i)
duDebugDrawNavMeshPoly(&dd, *nmesh, path[i], duRGBA(0,0,0,64));
duDebugDrawNavMeshPoly(&dd, *nmesh, path[i], duRGBA(0,0,0,32));
}
}
if (m_targetRef)
duDebugDrawCross(&dd, m_targetPos[0],m_targetPos[1]+0.1f,m_targetPos[2], s, duRGBA(255,255,255,192), 2.0f);
// Occupancy grid.
if (m_showGrid)
{
float gridy = -FLT_MAX;
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float* pos = ag->corridor.getPos();
gridy = dtMax(gridy, pos[1]);
}
gridy += 1.0f;
dd.begin(DU_DRAW_QUADS);
const ProximityGrid* grid = m_crowd.getGrid();
const int* bounds = grid->getBounds();
const float cs = grid->getCellSize();
for (int y = bounds[1]; y <= bounds[3]; ++y)
{
for (int x = bounds[0]; x <= bounds[2]; ++x)
{
const int count = grid->getItemCountAt(x,y);
if (!count) continue;
unsigned int col = duRGBA(128,0,0,dtMin(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
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float* pos = ag->npos;
dd.begin(DU_DRAW_LINES,3.0f);
float prev[3], preva = 1;
@ -357,12 +420,17 @@ void CrowdTool::handleRender()
}
dd.end();
if (m_showTargets)
{
duDebugDrawArc(&dd, pos[0], pos[1], pos[2], target[0], target[1], target[2],
0.25f, 0, 0.4f, duRGBA(0,0,0,128), 1.0f);
}
// Corners & co
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float radius = ag->radius;
const float* pos = ag->npos;
if (m_showCorners)
{
if (ag->ncorners)
@ -372,14 +440,14 @@ void CrowdTool::handleRender()
{
const float* va = j == 0 ? pos : &ag->cornerVerts[(j-1)*3];
const float* vb = &ag->cornerVerts[j*3];
dd.vertex(va[0],va[1]+radius,va[2], duRGBA(128,0,0,64));
dd.vertex(vb[0],vb[1]+radius,vb[2], duRGBA(128,0,0,64));
dd.vertex(va[0],va[1]+radius,va[2], duRGBA(128,0,0,192));
dd.vertex(vb[0],vb[1]+radius,vb[2], duRGBA(128,0,0,192));
}
dd.end();
if (m_anticipateTurns)
{
/* float dvel[3], pos[3];
/* float dvel[3], pos[3];
calcSmoothSteerDirection(ag->pos, ag->cornerVerts, ag->ncorners, dvel);
pos[0] = ag->pos[0] + dvel[0];
pos[1] = ag->pos[1] + dvel[1];
@ -429,6 +497,48 @@ void CrowdTool::handleRender()
dd.vertex(ag->opte[0],ag->opte[1]+0.3f,ag->opte[2], duRGBA(0,128,0,192));
dd.end();
}
}
// Agent cylinders.
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float radius = ag->radius;
const float* pos = ag->npos;
duDebugDrawCircle(&dd, pos[0], pos[1], pos[2], radius, duRGBA(0,0,0,32), 2.0f);
}
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float height = ag->height;
const float radius = ag->radius;
const float* pos = ag->npos;
duDebugDrawCylinder(&dd, pos[0]-radius, pos[1]+radius*0.1f, pos[2]-radius,
pos[0]+radius, pos[1]+height, pos[2]+radius,
duRGBA(220,220,220,128));
}
// Velocity stuff.
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float radius = ag->radius;
const float height = ag->height;
const float* pos = ag->npos;
const float* vel = ag->vel;
const float* dvel = ag->dvel;
duDebugDrawCircle(&dd, pos[0], pos[1]+height, pos[2], radius, duRGBA(220,220,220,192), 2.0f);
if (m_showVO)
{
@ -458,138 +568,31 @@ void CrowdTool::handleRender()
}
duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2],
pos[0]+vel[0],pos[1]+height+vel[1],pos[2]+vel[2],
0.0f, 0.4f, duRGBA(0,0,0,192), 2.0f);
duDebugDrawArrow(&dd, pos[0],pos[1]+height-0.1f,pos[2],
pos[0]+dvel[0],pos[1]+height-0.1f+dvel[1],pos[2]+dvel[2],
pos[0]+dvel[0],pos[1]+height+dvel[1],pos[2]+dvel[2],
0.0f, 0.4f, duRGBA(0,192,255,192), 1.0f);
duDebugDrawCylinderWire(&dd, pos[0]-radius, pos[1]+radius*0.1f, pos[2]-radius,
pos[0]+radius, pos[1]+height, pos[2]+radius,
duRGBA(0,192,255,255), 3.0f);
dd.depthMask(true);
duDebugDrawArrow(&dd, pos[0],pos[1]+height,pos[2],
pos[0]+vel[0],pos[1]+height+vel[1],pos[2]+vel[2],
0.0f, 0.4f, duRGBA(0,0,0,192), 2.0f);
}
if (m_showGrid)
{
float gridy = -FLT_MAX;
// Targets
for (int i = 0; i < m_crowd.getAgentCount(); ++i)
{
const Agent* ag = m_crowd.getAgent(i);
if (!ag->active) continue;
const float* pos = ag->corridor.getPos();
gridy = dtMax(gridy, pos[1]);
}
gridy += 1.0f;
dd.depthMask(false);
dd.begin(DU_DRAW_QUADS);
const ProximityGrid* grid = m_crowd.getGrid();
const int* bounds = grid->getBounds();
const float cs = grid->getCellSize();
for (int y = bounds[1]; y <= bounds[3]; ++y)
{
for (int x = bounds[0]; x <= bounds[2]; ++x)
{
const int count = grid->getItemCountAt(x,y);
if (!count) continue;
unsigned int col = duRGBA(128,0,0,dtMin(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();
dd.depthMask(true);
}
const float* pos = ag->npos;
const float* target = ag->corridor.getTarget();
/*
for (int i = 0; i < m_form.npolys; ++i)
if (m_showTargets)
{
duDebugDrawNavMeshPoly(&dd, *nmesh, m_form.polys[i], duRGBA(255,255,255,32));
duDebugDrawArc(&dd, pos[0], pos[1], pos[2], target[0], target[1], target[2],
0.25f, 0, 0.4f, duRGBA(0,0,0,128), 1.0f);
}
dd.depthMask(false);
dd.begin(DU_DRAW_POINTS, 4.0f);
for (int i = 0; i < m_form.nsegs; ++i)
{
const FormationSeg* seg = &m_form.segs[i];
for (int j = 0; j < seg->nints-1; ++j)
{
if (seg->ints[j].inside == 0) continue;
const float u0 = seg->ints[j].u;
const float u1 = seg->ints[j+1].u;
float ia[3], ib[3];
dtVlerp(ia, seg->p,seg->q, u0);
dtVlerp(ib, seg->p,seg->q, u1);
dd.vertex(ia,duRGBA(128,0,0,192));
dd.vertex(ib,duRGBA(128,0,0,192));
}
}
dd.end();
dd.begin(DU_DRAW_LINES, 2.0f);
for (int i = 0; i < m_form.nsegs; ++i)
{
const FormationSeg* seg = &m_form.segs[i];
dd.vertex(seg->p,duRGBA(255,255,255,128));
dd.vertex(seg->q,duRGBA(255,255,255,128));
for (int j = 0; j < seg->nints-1; ++j)
{
if (seg->ints[j].inside == 0) continue;
const float u0 = seg->ints[j].u;
const float u1 = seg->ints[j+1].u;
float ia[3], ib[3];
dtVlerp(ia, seg->p,seg->q, u0);
dtVlerp(ib, seg->p,seg->q, u1);
dd.vertex(ia,duRGBA(128,0,0,192));
dd.vertex(ib,duRGBA(128,0,0,192));
}
}
dd.end();
{
const float r = m_sample->getAgentRadius();
dd.begin(DU_DRAW_LINES, 2.0f);
for (int i = 0; i < m_form.nsegs; ++i)
{
const FormationSeg* seg = &m_form.segs[i];
dd.vertex(seg->p,duRGBA(255,255,255,128));
dd.vertex(seg->q,duRGBA(255,255,255,128));
for (int j = 0; j < seg->nints-1; ++j)
{
if (seg->ints[j].inside == 0) continue;
const float u0 = seg->ints[j].u;
const float u1 = seg->ints[j+1].u;
float ia[3], ib[3];
dtVlerp(ia, seg->p,seg->q, u0);
dtVlerp(ib, seg->p,seg->q, u1);
const float spacing = r*2.5f;
float delta[3];
dtVsub(delta, ib,ia);
float d = dtVlen(delta);
int np = (int)floorf(d/spacing);
for (int k = 0; k < np; ++k)
{
float pos[3];
dtVmad(pos, ia, delta, (float)(k+0.5f)/(float)np);
dd.vertex(pos[0],pos[1]-1,pos[2],duRGBA(128,0,0,192));
dd.vertex(pos[0],pos[1]+2,pos[2],duRGBA(128,0,0,192));
}
}
}
dd.end();
}
dd.depthMask(true);
*/
}
void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view)
@ -622,6 +625,8 @@ void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view)
}
}
if (m_showPerfGraph)
{
GraphParams gp;
gp.setRect(300, 10, 500, 200, 8);
gp.setValueRange(0.0f, 2.0f, 4, "ms");
@ -633,4 +638,5 @@ void CrowdTool::handleRenderOverlay(double* proj, double* model, int* view)
gp.setRect(300, 10, 500, 50, 8);
gp.setValueRange(0.0f, 2000.0f, 1, "0");
drawGraph(&gp, &m_crowdSampleCount, 0, "Sample Count", duRGBA(255,255,255,255));
}
}

View File

@ -321,6 +321,10 @@ void NavMeshTesterTool::handleClick(const float* /*s*/, const float* p, bool shi
}
void NavMeshTesterTool::handleStep()
{
}
void NavMeshTesterTool::handleToggle()
{
// TODO: merge separate to a path iterator. Use same code in recalc() too.
if (m_toolMode != TOOLMODE_PATHFIND_FOLLOW)

View File

@ -132,6 +132,10 @@ void OffMeshConnectionTool::handleClick(const float* /*s*/, const float* p, bool
}
void OffMeshConnectionTool::handleToggle()
{
}
void OffMeshConnectionTool::handleStep()
{
}

View File

@ -176,6 +176,12 @@ void Sample::handleClick(const float* s, const float* p, bool shift)
m_tool->handleClick(s, p, shift);
}
void Sample::handleToggle()
{
if (m_tool)
m_tool->handleToggle();
}
void Sample::handleStep()
{
if (m_tool)

View File

@ -357,10 +357,10 @@ void Sample_Debug::handleClick(const float* s, const float* p, bool shift)
m_tool->handleClick(s, p, shift);
}
void Sample_Debug::handleStep()
void Sample_Debug::handleToggle()
{
if (m_tool)
m_tool->handleStep();
m_tool->handleToggle();
}
bool Sample_Debug::handleBuild()

View File

@ -86,6 +86,8 @@ public:
m_sample->setHighlightedTile(m_hitPos);
}
virtual void handleToggle() {}
virtual void handleStep() {}
virtual void handleUpdate(const float /*dt*/) {}

View File

@ -125,6 +125,8 @@ public:
}
}
virtual void handleToggle() {}
virtual void handleStep() {}
virtual void handleUpdate(const float /*dt*/) {}

View File

@ -204,14 +204,19 @@ int main(int /*argc*/, char** /*argv*/)
else if (event.key.keysym.sym == SDLK_SPACE)
{
if (sample)
sample->handleStep();
sample->handleToggle();
}
else if (event.key.keysym.sym == SDLK_1)
{
if (sample)
sample->handleStep();
}
else if (event.key.keysym.sym == SDLK_9)
{
if (geom)
geom->save("geomset.txt");
}
else if (event.key.keysym.sym == SDLK_2)
else if (event.key.keysym.sym == SDLK_0)
{
delete geom;
geom = new InputGeom;