DetourObstacleAvoidance.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen memon@inside.org
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. #include "DetourObstacleAvoidance.h"
  19. #include "recast/Detour/DetourCommon.h"
  20. #include "recast/Detour/DetourMath.h"
  21. #include "recast/Detour/DetourAlloc.h"
  22. #include "recast/Detour/DetourAssert.h"
  23. #include <string.h>
  24. #include <float.h>
  25. #include <new>
  26. static const float DT_PI = 3.14159265f;
  27. static int sweepCircleCircle(const float* c0, const float r0, const float* v,
  28. const float* c1, const float r1,
  29. float& tmin, float& tmax)
  30. {
  31. static const float EPS = 0.0001f;
  32. float s[3];
  33. dtVsub(s,c1,c0);
  34. float r = r0+r1;
  35. float c = dtVdot2D(s,s) - r*r;
  36. float a = dtVdot2D(v,v);
  37. if (a < EPS) return 0; // not moving
  38. // Overlap, calc time to exit.
  39. float b = dtVdot2D(v,s);
  40. float d = b*b - a*c;
  41. if (d < 0.0f) return 0; // no intersection.
  42. a = 1.0f / a;
  43. const float rd = dtMathSqrtf(d);
  44. tmin = (b - rd) * a;
  45. tmax = (b + rd) * a;
  46. return 1;
  47. }
  48. static int isectRaySeg(const float* ap, const float* u,
  49. const float* bp, const float* bq,
  50. float& t)
  51. {
  52. float v[3], w[3];
  53. dtVsub(v,bq,bp);
  54. dtVsub(w,ap,bp);
  55. float d = dtVperp2D(u,v);
  56. if (dtMathFabsf(d) < 1e-6f) return 0;
  57. d = 1.0f/d;
  58. t = dtVperp2D(v,w) * d;
  59. if (t < 0 || t > 1) return 0;
  60. float s = dtVperp2D(u,w) * d;
  61. if (s < 0 || s > 1) return 0;
  62. return 1;
  63. }
  64. dtObstacleAvoidanceDebugData* dtAllocObstacleAvoidanceDebugData()
  65. {
  66. void* mem = dtAlloc(sizeof(dtObstacleAvoidanceDebugData), DT_ALLOC_PERM);
  67. if (!mem) return 0;
  68. return new(mem) dtObstacleAvoidanceDebugData;
  69. }
  70. void dtFreeObstacleAvoidanceDebugData(dtObstacleAvoidanceDebugData* ptr)
  71. {
  72. if (!ptr) return;
  73. ptr->~dtObstacleAvoidanceDebugData();
  74. dtFree(ptr);
  75. }
  76. dtObstacleAvoidanceDebugData::dtObstacleAvoidanceDebugData() :
  77. m_nsamples(0),
  78. m_maxSamples(0),
  79. m_vel(0),
  80. m_ssize(0),
  81. m_pen(0),
  82. m_vpen(0),
  83. m_vcpen(0),
  84. m_spen(0),
  85. m_tpen(0)
  86. {
  87. }
  88. dtObstacleAvoidanceDebugData::~dtObstacleAvoidanceDebugData()
  89. {
  90. dtFree(m_vel);
  91. dtFree(m_ssize);
  92. dtFree(m_pen);
  93. dtFree(m_vpen);
  94. dtFree(m_vcpen);
  95. dtFree(m_spen);
  96. dtFree(m_tpen);
  97. }
  98. bool dtObstacleAvoidanceDebugData::init(const int maxSamples)
  99. {
  100. dtAssert(maxSamples);
  101. m_maxSamples = maxSamples;
  102. m_vel = (float*)dtAlloc(sizeof(float)*3*m_maxSamples, DT_ALLOC_PERM);
  103. if (!m_vel)
  104. return false;
  105. m_pen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  106. if (!m_pen)
  107. return false;
  108. m_ssize = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  109. if (!m_ssize)
  110. return false;
  111. m_vpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  112. if (!m_vpen)
  113. return false;
  114. m_vcpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  115. if (!m_vcpen)
  116. return false;
  117. m_spen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  118. if (!m_spen)
  119. return false;
  120. m_tpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  121. if (!m_tpen)
  122. return false;
  123. return true;
  124. }
  125. void dtObstacleAvoidanceDebugData::reset()
  126. {
  127. m_nsamples = 0;
  128. }
  129. void dtObstacleAvoidanceDebugData::addSample(const float* vel, const float ssize, const float pen,
  130. const float vpen, const float vcpen, const float spen, const float tpen)
  131. {
  132. if (m_nsamples >= m_maxSamples)
  133. return;
  134. dtAssert(m_vel);
  135. dtAssert(m_ssize);
  136. dtAssert(m_pen);
  137. dtAssert(m_vpen);
  138. dtAssert(m_vcpen);
  139. dtAssert(m_spen);
  140. dtAssert(m_tpen);
  141. dtVcopy(&m_vel[m_nsamples*3], vel);
  142. m_ssize[m_nsamples] = ssize;
  143. m_pen[m_nsamples] = pen;
  144. m_vpen[m_nsamples] = vpen;
  145. m_vcpen[m_nsamples] = vcpen;
  146. m_spen[m_nsamples] = spen;
  147. m_tpen[m_nsamples] = tpen;
  148. m_nsamples++;
  149. }
  150. static void normalizeArray(float* arr, const int n)
  151. {
  152. // Normalize penaly range.
  153. float minPen = FLT_MAX;
  154. float maxPen = -FLT_MAX;
  155. for (int i = 0; i < n; ++i)
  156. {
  157. minPen = dtMin(minPen, arr[i]);
  158. maxPen = dtMax(maxPen, arr[i]);
  159. }
  160. const float penRange = maxPen-minPen;
  161. const float s = penRange > 0.001f ? (1.0f / penRange) : 1;
  162. for (int i = 0; i < n; ++i)
  163. arr[i] = dtClamp((arr[i]-minPen)*s, 0.0f, 1.0f);
  164. }
  165. void dtObstacleAvoidanceDebugData::normalizeSamples()
  166. {
  167. normalizeArray(m_pen, m_nsamples);
  168. normalizeArray(m_vpen, m_nsamples);
  169. normalizeArray(m_vcpen, m_nsamples);
  170. normalizeArray(m_spen, m_nsamples);
  171. normalizeArray(m_tpen, m_nsamples);
  172. }
  173. dtObstacleAvoidanceQuery* dtAllocObstacleAvoidanceQuery()
  174. {
  175. void* mem = dtAlloc(sizeof(dtObstacleAvoidanceQuery), DT_ALLOC_PERM);
  176. if (!mem) return 0;
  177. return new(mem) dtObstacleAvoidanceQuery;
  178. }
  179. void dtFreeObstacleAvoidanceQuery(dtObstacleAvoidanceQuery* ptr)
  180. {
  181. if (!ptr) return;
  182. ptr->~dtObstacleAvoidanceQuery();
  183. dtFree(ptr);
  184. }
  185. dtObstacleAvoidanceQuery::dtObstacleAvoidanceQuery() :
  186. m_maxCircles(0),
  187. m_circles(0),
  188. m_ncircles(0),
  189. m_maxSegments(0),
  190. m_segments(0),
  191. m_nsegments(0)
  192. {
  193. }
  194. dtObstacleAvoidanceQuery::~dtObstacleAvoidanceQuery()
  195. {
  196. dtFree(m_circles);
  197. dtFree(m_segments);
  198. }
  199. bool dtObstacleAvoidanceQuery::init(const int maxCircles, const int maxSegments)
  200. {
  201. m_maxCircles = maxCircles;
  202. m_ncircles = 0;
  203. m_circles = (dtObstacleCircle*)dtAlloc(sizeof(dtObstacleCircle)*m_maxCircles, DT_ALLOC_PERM);
  204. if (!m_circles)
  205. return false;
  206. memset(m_circles, 0, sizeof(dtObstacleCircle)*m_maxCircles);
  207. m_maxSegments = maxSegments;
  208. m_nsegments = 0;
  209. m_segments = (dtObstacleSegment*)dtAlloc(sizeof(dtObstacleSegment)*m_maxSegments, DT_ALLOC_PERM);
  210. if (!m_segments)
  211. return false;
  212. memset(m_segments, 0, sizeof(dtObstacleSegment)*m_maxSegments);
  213. return true;
  214. }
  215. void dtObstacleAvoidanceQuery::reset()
  216. {
  217. m_ncircles = 0;
  218. m_nsegments = 0;
  219. }
  220. void dtObstacleAvoidanceQuery::addCircle(const float* pos, const float rad,
  221. const float* vel, const float* dvel)
  222. {
  223. if (m_ncircles >= m_maxCircles)
  224. return;
  225. dtObstacleCircle* cir = &m_circles[m_ncircles++];
  226. dtVcopy(cir->p, pos);
  227. cir->rad = rad;
  228. dtVcopy(cir->vel, vel);
  229. dtVcopy(cir->dvel, dvel);
  230. }
  231. void dtObstacleAvoidanceQuery::addSegment(const float* p, const float* q)
  232. {
  233. if (m_nsegments >= m_maxSegments)
  234. return;
  235. dtObstacleSegment* seg = &m_segments[m_nsegments++];
  236. dtVcopy(seg->p, p);
  237. dtVcopy(seg->q, q);
  238. }
  239. void dtObstacleAvoidanceQuery::prepare(const float* pos, const float* dvel)
  240. {
  241. // Prepare obstacles
  242. for (int i = 0; i < m_ncircles; ++i)
  243. {
  244. dtObstacleCircle* cir = &m_circles[i];
  245. // Side
  246. const float* pa = pos;
  247. const float* pb = cir->p;
  248. const float orig[3] = {0,0,0};
  249. float dv[3];
  250. dtVsub(cir->dp,pb,pa);
  251. dtVnormalize(cir->dp);
  252. dtVsub(dv, cir->dvel, dvel);
  253. const float a = dtTriArea2D(orig, cir->dp,dv);
  254. if (a < 0.01f)
  255. {
  256. cir->np[0] = -cir->dp[2];
  257. cir->np[2] = cir->dp[0];
  258. }
  259. else
  260. {
  261. cir->np[0] = cir->dp[2];
  262. cir->np[2] = -cir->dp[0];
  263. }
  264. }
  265. for (int i = 0; i < m_nsegments; ++i)
  266. {
  267. dtObstacleSegment* seg = &m_segments[i];
  268. // Precalc if the agent is really close to the segment.
  269. const float r = 0.01f;
  270. float t;
  271. seg->touch = dtDistancePtSegSqr2D(pos, seg->p, seg->q, t) < dtSqr(r);
  272. }
  273. }
  274. /* Calculate the collision penalty for a given velocity vector
  275. *
  276. * @param vcand sampled velocity
  277. * @param dvel desired velocity
  278. * @param minPenalty threshold penalty for early out
  279. */
  280. float dtObstacleAvoidanceQuery::processSample(const float* vcand, const float cs,
  281. const float* pos, const float rad,
  282. const float* vel, const float* dvel,
  283. const float minPenalty,
  284. dtObstacleAvoidanceDebugData* debug)
  285. {
  286. // penalty for straying away from the desired and current velocities
  287. const float vpen = m_params.weightDesVel * (dtVdist2D(vcand, dvel) * m_invVmax);
  288. const float vcpen = m_params.weightCurVel * (dtVdist2D(vcand, vel) * m_invVmax);
  289. // find the threshold hit time to bail out based on the early out penalty
  290. // (see how the penalty is calculated below to understnad)
  291. float minPen = minPenalty - vpen - vcpen;
  292. float tThresold = ((double)m_params.weightToi/(double)minPen - 0.1) * (double)m_params.horizTime;
  293. if (tThresold - m_params.horizTime > -FLT_EPSILON)
  294. return minPenalty; // already too much
  295. // Find min time of impact and exit amongst all obstacles.
  296. float tmin = m_params.horizTime;
  297. float side = 0;
  298. int nside = 0;
  299. for (int i = 0; i < m_ncircles; ++i)
  300. {
  301. const dtObstacleCircle* cir = &m_circles[i];
  302. // RVO
  303. float vab[3];
  304. dtVscale(vab, vcand, 2);
  305. dtVsub(vab, vab, vel);
  306. dtVsub(vab, vab, cir->vel);
  307. // Side
  308. side += dtClamp(dtMin(dtVdot2D(cir->dp,vab)*0.5f+0.5f, dtVdot2D(cir->np,vab)*2), 0.0f, 1.0f);
  309. nside++;
  310. float htmin = 0, htmax = 0;
  311. if (!sweepCircleCircle(pos,rad, vab, cir->p,cir->rad, htmin, htmax))
  312. continue;
  313. // Handle overlapping obstacles.
  314. if (htmin < 0.0f && htmax > 0.0f)
  315. {
  316. // Avoid more when overlapped.
  317. htmin = -htmin * 0.5f;
  318. }
  319. if (htmin >= 0.0f)
  320. {
  321. // The closest obstacle is somewhere ahead of us, keep track of nearest obstacle.
  322. if (htmin < tmin)
  323. {
  324. tmin = htmin;
  325. if (tmin < tThresold)
  326. return minPenalty;
  327. }
  328. }
  329. }
  330. for (int i = 0; i < m_nsegments; ++i)
  331. {
  332. const dtObstacleSegment* seg = &m_segments[i];
  333. float htmin = 0;
  334. if (seg->touch)
  335. {
  336. // Special case when the agent is very close to the segment.
  337. float sdir[3], snorm[3];
  338. dtVsub(sdir, seg->q, seg->p);
  339. snorm[0] = -sdir[2];
  340. snorm[2] = sdir[0];
  341. // If the velocity is pointing towards the segment, no collision.
  342. if (dtVdot2D(snorm, vcand) < 0.0f)
  343. continue;
  344. // Else immediate collision.
  345. htmin = 0.0f;
  346. }
  347. else
  348. {
  349. if (!isectRaySeg(pos, vcand, seg->p, seg->q, htmin))
  350. continue;
  351. }
  352. // Avoid less when facing walls.
  353. htmin *= 2.0f;
  354. // The closest obstacle is somewhere ahead of us, keep track of nearest obstacle.
  355. if (htmin < tmin)
  356. {
  357. tmin = htmin;
  358. if (tmin < tThresold)
  359. return minPenalty;
  360. }
  361. }
  362. // Normalize side bias, to prevent it dominating too much.
  363. if (nside)
  364. side /= nside;
  365. const float spen = m_params.weightSide * side;
  366. const float tpen = m_params.weightToi * (1.0f/(0.1f+tmin*m_invHorizTime));
  367. const float penalty = vpen + vcpen + spen + tpen;
  368. // Store different penalties for debug viewing
  369. if (debug)
  370. debug->addSample(vcand, cs, penalty, vpen, vcpen, spen, tpen);
  371. return penalty;
  372. }
  373. int dtObstacleAvoidanceQuery::sampleVelocityGrid(const float* pos, const float rad, const float vmax,
  374. const float* vel, const float* dvel, float* nvel,
  375. const dtObstacleAvoidanceParams* params,
  376. dtObstacleAvoidanceDebugData* debug)
  377. {
  378. prepare(pos, dvel);
  379. memcpy(&m_params, params, sizeof(dtObstacleAvoidanceParams));
  380. m_invHorizTime = 1.0f / m_params.horizTime;
  381. m_vmax = vmax;
  382. m_invVmax = vmax > 0 ? 1.0f / vmax : FLT_MAX;
  383. dtVset(nvel, 0,0,0);
  384. if (debug)
  385. debug->reset();
  386. const float cvx = dvel[0] * m_params.velBias;
  387. const float cvz = dvel[2] * m_params.velBias;
  388. const float cs = vmax * 2 * (1 - m_params.velBias) / (float)(m_params.gridSize-1);
  389. const float half = (m_params.gridSize-1)*cs*0.5f;
  390. float minPenalty = FLT_MAX;
  391. int ns = 0;
  392. for (int y = 0; y < m_params.gridSize; ++y)
  393. {
  394. for (int x = 0; x < m_params.gridSize; ++x)
  395. {
  396. float vcand[3];
  397. vcand[0] = cvx + x*cs - half;
  398. vcand[1] = 0;
  399. vcand[2] = cvz + y*cs - half;
  400. if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+cs/2)) continue;
  401. const float penalty = processSample(vcand, cs, pos,rad,vel,dvel, minPenalty, debug);
  402. ns++;
  403. if (penalty < minPenalty)
  404. {
  405. minPenalty = penalty;
  406. dtVcopy(nvel, vcand);
  407. }
  408. }
  409. }
  410. return ns;
  411. }
  412. // vector normalization that ignores the y-component.
  413. inline void dtNormalize2D(float* v)
  414. {
  415. float d = dtMathSqrtf(v[0] * v[0] + v[2] * v[2]);
  416. if (d==0)
  417. return;
  418. d = 1.0f / d;
  419. v[0] *= d;
  420. v[2] *= d;
  421. }
  422. // vector normalization that ignores the y-component.
  423. inline void dtRorate2D(float* dest, const float* v, float ang)
  424. {
  425. float c = cosf(ang);
  426. float s = sinf(ang);
  427. dest[0] = v[0]*c - v[2]*s;
  428. dest[2] = v[0]*s + v[2]*c;
  429. dest[1] = v[1];
  430. }
  431. int dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
  432. const float* vel, const float* dvel, float* nvel,
  433. const dtObstacleAvoidanceParams* params,
  434. dtObstacleAvoidanceDebugData* debug)
  435. {
  436. prepare(pos, dvel);
  437. memcpy(&m_params, params, sizeof(dtObstacleAvoidanceParams));
  438. m_invHorizTime = 1.0f / m_params.horizTime;
  439. m_vmax = vmax;
  440. m_invVmax = vmax > 0 ? 1.0f / vmax : FLT_MAX;
  441. dtVset(nvel, 0,0,0);
  442. if (debug)
  443. debug->reset();
  444. // Build sampling pattern aligned to desired velocity.
  445. float pat[(DT_MAX_PATTERN_DIVS*DT_MAX_PATTERN_RINGS+1)*2];
  446. int npat = 0;
  447. const int ndivs = (int)m_params.adaptiveDivs;
  448. const int nrings= (int)m_params.adaptiveRings;
  449. const int depth = (int)m_params.adaptiveDepth;
  450. const int nd = dtClamp(ndivs, 1, DT_MAX_PATTERN_DIVS);
  451. const int nr = dtClamp(nrings, 1, DT_MAX_PATTERN_RINGS);
  452. const int nd2 = nd / 2;
  453. const float da = (1.0f/nd) * DT_PI*2;
  454. const float ca = cosf(da);
  455. const float sa = sinf(da);
  456. // desired direction
  457. float ddir[6];
  458. dtVcopy(ddir, dvel);
  459. dtNormalize2D(ddir);
  460. dtRorate2D (ddir+3, ddir, da*0.5f); // rotated by da/2
  461. // Always add sample at zero
  462. pat[npat*2+0] = 0;
  463. pat[npat*2+1] = 0;
  464. npat++;
  465. for (int j = 0; j < nr; ++j)
  466. {
  467. const float r = (float)(nr-j)/(float)nr;
  468. pat[npat*2+0] = ddir[(j%1)*3] * r;
  469. pat[npat*2+1] = ddir[(j%1)*3+2] * r;
  470. float* last1 = pat + npat*2;
  471. float* last2 = last1;
  472. npat++;
  473. for (int i = 1; i < nd-1; i+=2)
  474. {
  475. // get next point on the "right" (rotate CW)
  476. pat[npat*2+0] = last1[0]*ca + last1[1]*sa;
  477. pat[npat*2+1] = -last1[0]*sa + last1[1]*ca;
  478. // get next point on the "left" (rotate CCW)
  479. pat[npat*2+2] = last2[0]*ca - last2[1]*sa;
  480. pat[npat*2+3] = last2[0]*sa + last2[1]*ca;
  481. last1 = pat + npat*2;
  482. last2 = last1 + 2;
  483. npat += 2;
  484. }
  485. if ((nd&1) == 0)
  486. {
  487. pat[npat*2+2] = last2[0]*ca - last2[1]*sa;
  488. pat[npat*2+3] = last2[0]*sa + last2[1]*ca;
  489. npat++;
  490. }
  491. }
  492. // Start sampling.
  493. float cr = vmax * (1.0f - m_params.velBias);
  494. float res[3];
  495. dtVset(res, dvel[0] * m_params.velBias, 0, dvel[2] * m_params.velBias);
  496. int ns = 0;
  497. for (int k = 0; k < depth; ++k)
  498. {
  499. float minPenalty = FLT_MAX;
  500. float bvel[3];
  501. dtVset(bvel, 0,0,0);
  502. for (int i = 0; i < npat; ++i)
  503. {
  504. float vcand[3];
  505. vcand[0] = res[0] + pat[i*2+0]*cr;
  506. vcand[1] = 0;
  507. vcand[2] = res[2] + pat[i*2+1]*cr;
  508. if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+0.001f)) continue;
  509. const float penalty = processSample(vcand,cr/10, pos,rad,vel,dvel, minPenalty, debug);
  510. ns++;
  511. if (penalty < minPenalty)
  512. {
  513. minPenalty = penalty;
  514. dtVcopy(bvel, vcand);
  515. }
  516. }
  517. dtVcopy(res, bvel);
  518. cr *= 0.5f;
  519. }
  520. dtVcopy(nvel, res);
  521. return ns;
  522. }