DetourObstacleAvoidance.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen [email protected]
  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. // Modified by cosmy1 for Urho3D
  19. #include "DetourObstacleAvoidance.h"
  20. #include "DetourCommon.h"
  21. #include "DetourMath.h"
  22. #include "DetourAlloc.h"
  23. #include "DetourAssert.h"
  24. #include <string.h>
  25. #include <float.h>
  26. #include <new>
  27. static const float DT_PI = 3.14159265f;
  28. static int sweepCircleCircle(const float* c0, const float r0, const float* v,
  29. const float* c1, const float r1,
  30. float& tmin, float& tmax)
  31. {
  32. static const float EPS = 0.0001f;
  33. float s[3];
  34. dtVsub(s,c1,c0);
  35. float r = r0+r1;
  36. float c = dtVdot2D(s,s) - r*r;
  37. float a = dtVdot2D(v,v);
  38. if (a < EPS) return 0; // not moving
  39. // Overlap, calc time to exit.
  40. float b = dtVdot2D(v,s);
  41. float d = b*b - a*c;
  42. if (d < 0.0f) return 0; // no intersection.
  43. a = 1.0f / a;
  44. const float rd = dtSqrt(d);
  45. tmin = (b - rd) * a;
  46. tmax = (b + rd) * a;
  47. return 1;
  48. }
  49. static int isectRaySeg(const float* ap, const float* u,
  50. const float* bp, const float* bq,
  51. float& t)
  52. {
  53. float v[3], w[3];
  54. dtVsub(v,bq,bp);
  55. dtVsub(w,ap,bp);
  56. float d = dtVperp2D(u,v);
  57. if (dtMathFabs(d) < 1e-6f) return 0;
  58. d = 1.0f/d;
  59. t = dtVperp2D(v,w) * d;
  60. if (t < 0 || t > 1) return 0;
  61. float s = dtVperp2D(u,w) * d;
  62. if (s < 0 || s > 1) return 0;
  63. return 1;
  64. }
  65. dtObstacleAvoidanceDebugData* dtAllocObstacleAvoidanceDebugData()
  66. {
  67. void* mem = dtAlloc(sizeof(dtObstacleAvoidanceDebugData), DT_ALLOC_PERM);
  68. if (!mem) return 0;
  69. return new(mem) dtObstacleAvoidanceDebugData;
  70. }
  71. void dtFreeObstacleAvoidanceDebugData(dtObstacleAvoidanceDebugData* ptr)
  72. {
  73. if (!ptr) return;
  74. ptr->~dtObstacleAvoidanceDebugData();
  75. dtFree(ptr);
  76. }
  77. dtObstacleAvoidanceDebugData::dtObstacleAvoidanceDebugData() :
  78. m_nsamples(0),
  79. m_maxSamples(0),
  80. m_vel(0),
  81. m_ssize(0),
  82. m_pen(0),
  83. m_vpen(0),
  84. m_vcpen(0),
  85. m_spen(0),
  86. m_tpen(0)
  87. {
  88. }
  89. dtObstacleAvoidanceDebugData::~dtObstacleAvoidanceDebugData()
  90. {
  91. dtFree(m_vel);
  92. dtFree(m_ssize);
  93. dtFree(m_pen);
  94. dtFree(m_vpen);
  95. dtFree(m_vcpen);
  96. dtFree(m_spen);
  97. dtFree(m_tpen);
  98. }
  99. bool dtObstacleAvoidanceDebugData::init(const int maxSamples)
  100. {
  101. dtAssert(maxSamples);
  102. m_maxSamples = maxSamples;
  103. m_vel = (float*)dtAlloc(sizeof(float)*3*m_maxSamples, DT_ALLOC_PERM);
  104. if (!m_vel)
  105. return false;
  106. m_pen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  107. if (!m_pen)
  108. return false;
  109. m_ssize = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  110. if (!m_ssize)
  111. return false;
  112. m_vpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  113. if (!m_vpen)
  114. return false;
  115. m_vcpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  116. if (!m_vcpen)
  117. return false;
  118. m_spen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  119. if (!m_spen)
  120. return false;
  121. m_tpen = (float*)dtAlloc(sizeof(float)*m_maxSamples, DT_ALLOC_PERM);
  122. if (!m_tpen)
  123. return false;
  124. return true;
  125. }
  126. void dtObstacleAvoidanceDebugData::reset()
  127. {
  128. m_nsamples = 0;
  129. }
  130. void dtObstacleAvoidanceDebugData::addSample(const float* vel, const float ssize, const float pen,
  131. const float vpen, const float vcpen, const float spen, const float tpen)
  132. {
  133. if (m_nsamples >= m_maxSamples)
  134. return;
  135. dtAssert(m_vel);
  136. dtAssert(m_ssize);
  137. dtAssert(m_pen);
  138. dtAssert(m_vpen);
  139. dtAssert(m_vcpen);
  140. dtAssert(m_spen);
  141. dtAssert(m_tpen);
  142. dtVcopy(&m_vel[m_nsamples*3], vel);
  143. m_ssize[m_nsamples] = ssize;
  144. m_pen[m_nsamples] = pen;
  145. m_vpen[m_nsamples] = vpen;
  146. m_vcpen[m_nsamples] = vcpen;
  147. m_spen[m_nsamples] = spen;
  148. m_tpen[m_nsamples] = tpen;
  149. m_nsamples++;
  150. }
  151. static void normalizeArray(float* arr, const int n)
  152. {
  153. // Normalize penaly range.
  154. float minPen = FLT_MAX;
  155. float maxPen = -FLT_MAX;
  156. for (int i = 0; i < n; ++i)
  157. {
  158. minPen = dtMin(minPen, arr[i]);
  159. maxPen = dtMax(maxPen, arr[i]);
  160. }
  161. const float penRange = maxPen-minPen;
  162. const float s = penRange > 0.001f ? (1.0f / penRange) : 1;
  163. for (int i = 0; i < n; ++i)
  164. arr[i] = dtClamp((arr[i]-minPen)*s, 0.0f, 1.0f);
  165. }
  166. void dtObstacleAvoidanceDebugData::normalizeSamples()
  167. {
  168. normalizeArray(m_pen, m_nsamples);
  169. normalizeArray(m_vpen, m_nsamples);
  170. normalizeArray(m_vcpen, m_nsamples);
  171. normalizeArray(m_spen, m_nsamples);
  172. normalizeArray(m_tpen, m_nsamples);
  173. }
  174. dtObstacleAvoidanceQuery* dtAllocObstacleAvoidanceQuery()
  175. {
  176. void* mem = dtAlloc(sizeof(dtObstacleAvoidanceQuery), DT_ALLOC_PERM);
  177. if (!mem) return 0;
  178. return new(mem) dtObstacleAvoidanceQuery;
  179. }
  180. void dtFreeObstacleAvoidanceQuery(dtObstacleAvoidanceQuery* ptr)
  181. {
  182. if (!ptr) return;
  183. ptr->~dtObstacleAvoidanceQuery();
  184. dtFree(ptr);
  185. }
  186. // Urho3D: initialize all class members
  187. dtObstacleAvoidanceQuery::dtObstacleAvoidanceQuery() :
  188. m_maxCircles(0),
  189. m_circles(0),
  190. m_ncircles(0),
  191. m_maxSegments(0),
  192. m_segments(0),
  193. m_nsegments(0),
  194. m_invHorizTime(0), // Urho3D
  195. m_vmax(0), // Urho3D
  196. m_invVmax(0) // Urho3D
  197. {
  198. memset(&m_params, 0, sizeof(m_params)); // Urho3D
  199. }
  200. dtObstacleAvoidanceQuery::~dtObstacleAvoidanceQuery()
  201. {
  202. dtFree(m_circles);
  203. dtFree(m_segments);
  204. }
  205. bool dtObstacleAvoidanceQuery::init(const int maxCircles, const int maxSegments)
  206. {
  207. m_maxCircles = maxCircles;
  208. m_ncircles = 0;
  209. m_circles = (dtObstacleCircle*)dtAlloc(sizeof(dtObstacleCircle)*m_maxCircles, DT_ALLOC_PERM);
  210. if (!m_circles)
  211. return false;
  212. memset(m_circles, 0, sizeof(dtObstacleCircle)*m_maxCircles);
  213. m_maxSegments = maxSegments;
  214. m_nsegments = 0;
  215. m_segments = (dtObstacleSegment*)dtAlloc(sizeof(dtObstacleSegment)*m_maxSegments, DT_ALLOC_PERM);
  216. if (!m_segments)
  217. return false;
  218. memset(m_segments, 0, sizeof(dtObstacleSegment)*m_maxSegments);
  219. return true;
  220. }
  221. void dtObstacleAvoidanceQuery::reset()
  222. {
  223. m_ncircles = 0;
  224. m_nsegments = 0;
  225. }
  226. void dtObstacleAvoidanceQuery::addCircle(const float* pos, const float rad,
  227. const float* vel, const float* dvel)
  228. {
  229. if (m_ncircles >= m_maxCircles)
  230. return;
  231. dtObstacleCircle* cir = &m_circles[m_ncircles++];
  232. dtVcopy(cir->p, pos);
  233. cir->rad = rad;
  234. dtVcopy(cir->vel, vel);
  235. dtVcopy(cir->dvel, dvel);
  236. }
  237. void dtObstacleAvoidanceQuery::addSegment(const float* p, const float* q)
  238. {
  239. if (m_nsegments > m_maxSegments)
  240. return;
  241. dtObstacleSegment* seg = &m_segments[m_nsegments++];
  242. dtVcopy(seg->p, p);
  243. dtVcopy(seg->q, q);
  244. }
  245. void dtObstacleAvoidanceQuery::prepare(const float* pos, const float* dvel)
  246. {
  247. // Prepare obstacles
  248. for (int i = 0; i < m_ncircles; ++i)
  249. {
  250. dtObstacleCircle* cir = &m_circles[i];
  251. // Side
  252. const float* pa = pos;
  253. const float* pb = cir->p;
  254. const float orig[3] = {0,0};
  255. float dv[3];
  256. dtVsub(cir->dp,pb,pa);
  257. dtVnormalize(cir->dp);
  258. dtVsub(dv, cir->dvel, dvel);
  259. const float a = dtTriArea2D(orig, cir->dp,dv);
  260. if (a < 0.01f)
  261. {
  262. cir->np[0] = -cir->dp[2];
  263. cir->np[2] = cir->dp[0];
  264. }
  265. else
  266. {
  267. cir->np[0] = cir->dp[2];
  268. cir->np[2] = -cir->dp[0];
  269. }
  270. }
  271. for (int i = 0; i < m_nsegments; ++i)
  272. {
  273. dtObstacleSegment* seg = &m_segments[i];
  274. // Precalc if the agent is really close to the segment.
  275. const float r = 0.01f;
  276. float t;
  277. seg->touch = dtDistancePtSegSqr2D(pos, seg->p, seg->q, t) < dtSqr(r);
  278. }
  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. dtObstacleAvoidanceDebugData* debug)
  284. {
  285. // Find min time of impact and exit amongst all obstacles.
  286. float tmin = m_params.horizTime;
  287. float side = 0;
  288. int nside = 0;
  289. for (int i = 0; i < m_ncircles; ++i)
  290. {
  291. const dtObstacleCircle* cir = &m_circles[i];
  292. // RVO
  293. float vab[3];
  294. dtVscale(vab, vcand, 2);
  295. dtVsub(vab, vab, vel);
  296. dtVsub(vab, vab, cir->vel);
  297. // Side
  298. side += dtClamp(dtMin(dtVdot2D(cir->dp,vab)*0.5f+0.5f, dtVdot2D(cir->np,vab)*2), 0.0f, 1.0f);
  299. nside++;
  300. float htmin = 0, htmax = 0;
  301. if (!sweepCircleCircle(pos,rad, vab, cir->p,cir->rad, htmin, htmax))
  302. continue;
  303. // Handle overlapping obstacles.
  304. if (htmin < 0.0f && htmax > 0.0f)
  305. {
  306. // Avoid more when overlapped.
  307. htmin = -htmin * 0.5f;
  308. }
  309. if (htmin >= 0.0f)
  310. {
  311. // The closest obstacle is somewhere ahead of us, keep track of nearest obstacle.
  312. if (htmin < tmin)
  313. tmin = htmin;
  314. }
  315. }
  316. for (int i = 0; i < m_nsegments; ++i)
  317. {
  318. const dtObstacleSegment* seg = &m_segments[i];
  319. float htmin = 0;
  320. if (seg->touch)
  321. {
  322. // Special case when the agent is very close to the segment.
  323. float sdir[3], snorm[3];
  324. dtVsub(sdir, seg->q, seg->p);
  325. snorm[0] = -sdir[2];
  326. snorm[2] = sdir[0];
  327. // If the velocity is pointing towards the segment, no collision.
  328. if (dtVdot2D(snorm, vcand) < 0.0f)
  329. continue;
  330. // Else immediate collision.
  331. htmin = 0.0f;
  332. }
  333. else
  334. {
  335. if (!isectRaySeg(pos, vcand, seg->p, seg->q, htmin))
  336. continue;
  337. }
  338. // Avoid less when facing walls.
  339. htmin *= 2.0f;
  340. // The closest obstacle is somewhere ahead of us, keep track of nearest obstacle.
  341. if (htmin < tmin)
  342. tmin = htmin;
  343. }
  344. // Normalize side bias, to prevent it dominating too much.
  345. if (nside)
  346. side /= nside;
  347. const float vpen = m_params.weightDesVel * (dtVdist2D(vcand, dvel) * m_invVmax);
  348. const float vcpen = m_params.weightCurVel * (dtVdist2D(vcand, vel) * m_invVmax);
  349. const float spen = m_params.weightSide * side;
  350. const float tpen = m_params.weightToi * (1.0f/(0.1f+tmin*m_invHorizTime));
  351. const float penalty = vpen + vcpen + spen + tpen;
  352. // Store different penalties for debug viewing
  353. if (debug)
  354. debug->addSample(vcand, cs, penalty, vpen, vcpen, spen, tpen);
  355. return penalty;
  356. }
  357. int dtObstacleAvoidanceQuery::sampleVelocityGrid(const float* pos, const float rad, const float vmax,
  358. const float* vel, const float* dvel, float* nvel,
  359. const dtObstacleAvoidanceParams* params,
  360. dtObstacleAvoidanceDebugData* debug)
  361. {
  362. prepare(pos, dvel);
  363. memcpy(&m_params, params, sizeof(dtObstacleAvoidanceParams));
  364. m_invHorizTime = 1.0f / m_params.horizTime;
  365. m_vmax = vmax;
  366. m_invVmax = 1.0f / vmax;
  367. dtVset(nvel, 0,0,0);
  368. if (debug)
  369. debug->reset();
  370. const float cvx = dvel[0] * m_params.velBias;
  371. const float cvz = dvel[2] * m_params.velBias;
  372. const float cs = vmax * 2 * (1 - m_params.velBias) / (float)(m_params.gridSize-1);
  373. const float half = (m_params.gridSize-1)*cs*0.5f;
  374. float minPenalty = FLT_MAX;
  375. int ns = 0;
  376. for (int y = 0; y < m_params.gridSize; ++y)
  377. {
  378. for (int x = 0; x < m_params.gridSize; ++x)
  379. {
  380. float vcand[3];
  381. vcand[0] = cvx + x*cs - half;
  382. vcand[1] = 0;
  383. vcand[2] = cvz + y*cs - half;
  384. if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+cs/2)) continue;
  385. const float penalty = processSample(vcand, cs, pos,rad,vel,dvel, debug);
  386. ns++;
  387. if (penalty < minPenalty)
  388. {
  389. minPenalty = penalty;
  390. dtVcopy(nvel, vcand);
  391. }
  392. }
  393. }
  394. return ns;
  395. }
  396. int dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const float rad, const float vmax,
  397. const float* vel, const float* dvel, float* nvel,
  398. const dtObstacleAvoidanceParams* params,
  399. dtObstacleAvoidanceDebugData* debug)
  400. {
  401. prepare(pos, dvel);
  402. memcpy(&m_params, params, sizeof(dtObstacleAvoidanceParams));
  403. m_invHorizTime = 1.0f / m_params.horizTime;
  404. m_vmax = vmax;
  405. m_invVmax = 1.0f / vmax;
  406. dtVset(nvel, 0,0,0);
  407. if (debug)
  408. debug->reset();
  409. // Build sampling pattern aligned to desired velocity.
  410. float pat[(DT_MAX_PATTERN_DIVS*DT_MAX_PATTERN_RINGS+1)*2];
  411. int npat = 0;
  412. const int ndivs = (int)m_params.adaptiveDivs;
  413. const int nrings= (int)m_params.adaptiveRings;
  414. const int depth = (int)m_params.adaptiveDepth;
  415. const int nd = dtClamp(ndivs, 1, DT_MAX_PATTERN_DIVS);
  416. const int nr = dtClamp(nrings, 1, DT_MAX_PATTERN_RINGS);
  417. const float da = (1.0f/nd) * DT_PI*2;
  418. const float dang = dtMathAtan2f(dvel[2], dvel[0]);
  419. // Always add sample at zero
  420. pat[npat*2+0] = 0;
  421. pat[npat*2+1] = 0;
  422. npat++;
  423. for (int j = 0; j < nr; ++j)
  424. {
  425. const float r = (float)(nr-j)/(float)nr;
  426. float a = dang + (j&1)*0.5f*da;
  427. for (int i = 0; i < nd; ++i)
  428. {
  429. pat[npat*2+0] = cosf(a)*r;
  430. pat[npat*2+1] = sinf(a)*r;
  431. npat++;
  432. a += da;
  433. }
  434. }
  435. // Start sampling.
  436. float cr = vmax * (1.0f - m_params.velBias);
  437. float res[3];
  438. dtVset(res, dvel[0] * m_params.velBias, 0, dvel[2] * m_params.velBias);
  439. int ns = 0;
  440. for (int k = 0; k < depth; ++k)
  441. {
  442. float minPenalty = FLT_MAX;
  443. float bvel[3];
  444. dtVset(bvel, 0,0,0);
  445. for (int i = 0; i < npat; ++i)
  446. {
  447. float vcand[3];
  448. vcand[0] = res[0] + pat[i*2+0]*cr;
  449. vcand[1] = 0;
  450. vcand[2] = res[2] + pat[i*2+1]*cr;
  451. if (dtSqr(vcand[0])+dtSqr(vcand[2]) > dtSqr(vmax+0.001f)) continue;
  452. const float penalty = processSample(vcand,cr/10, pos,rad,vel,dvel, debug);
  453. ns++;
  454. if (penalty < minPenalty)
  455. {
  456. minPenalty = penalty;
  457. dtVcopy(bvel, vcand);
  458. }
  459. }
  460. dtVcopy(res, bvel);
  461. cr *= 0.5f;
  462. }
  463. dtVcopy(nvel, res);
  464. return ns;
  465. }