ODERayCastRequestManager.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Collections.Concurrent;
  30. using System.Reflection;
  31. using System.Runtime.CompilerServices;
  32. using System.Runtime.InteropServices;
  33. using OpenSim.Framework;
  34. using OpenSim.Region.PhysicsModules.SharedBase;
  35. using log4net;
  36. using OpenMetaverse;
  37. namespace OpenSim.Region.PhysicsModule.ubOde
  38. {
  39. /// <summary>
  40. /// Processes raycast requests as ODE is in a state to be able to do them.
  41. /// This ensures that it's thread safe and there will be no conflicts.
  42. /// Requests get returned by a different thread then they were requested by.
  43. /// </summary>
  44. public class ODERayCastRequestManager
  45. {
  46. /// <summary>
  47. /// Pending ray requests
  48. /// </summary>
  49. protected ConcurrentQueue<ODERayRequest> m_PendingRequests = new();
  50. /// <summary>
  51. /// Scene that created this object.
  52. /// </summary>
  53. private readonly ODEScene m_scene;
  54. private readonly UBOdeNative.ContactGeom[] m_contacts;
  55. IntPtr ray; // the ray. we only need one for our lifetime
  56. private int CollisionContactGeomsPerTest = 25;
  57. private const int ResultsMaxCount = 25;
  58. private const int DefaultResultsMaxCount = 25;
  59. private const int MaxTimePerCallMS = 30;
  60. /// <summary>
  61. /// ODE near callback delegate
  62. /// </summary>
  63. private readonly UBOdeNative.NearCallback nearCallback;
  64. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  65. private readonly List<ContactResult> m_contactResults = new(ResultsMaxCount);
  66. private readonly object m_contactResultsLock = new();
  67. private RayFilterFlags CurrentRayFilter;
  68. private int CurrentMaxCount;
  69. ContactResult SharedCollisionResult = new();
  70. public ODERayCastRequestManager(ODEScene pScene)
  71. {
  72. m_scene = pScene;
  73. m_contacts = pScene.m_contacts;
  74. nearCallback = near;
  75. ray = UBOdeNative.CreateRay(IntPtr.Zero, 1.0f);
  76. UBOdeNative.GeomSetCategoryBits(ray, 0);
  77. }
  78. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  79. public void QueueRequest(ODERayRequest req)
  80. {
  81. if (req.Count == 0)
  82. req.Count = DefaultResultsMaxCount;
  83. m_PendingRequests.Enqueue(req);
  84. }
  85. /// <summary>
  86. /// Process all queued raycast requests
  87. /// </summary>
  88. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  89. public void ProcessQueuedRequests()
  90. {
  91. if (m_PendingRequests.IsEmpty)
  92. return ;
  93. int time = Util.EnvironmentTickCount();
  94. while (m_PendingRequests.TryDequeue(out ODERayRequest req))
  95. {
  96. if(req.length <= 0)
  97. {
  98. NoContacts(req);
  99. continue;
  100. }
  101. IntPtr geom = IntPtr.Zero;
  102. if (req.actor != null)
  103. {
  104. if (m_scene.haveActor(req.actor))
  105. {
  106. if (req.actor is OdePrim prim)
  107. geom = prim.m_prim_geom;
  108. else if (req.actor is OdeCharacter ch)
  109. geom = ch.collider;
  110. }
  111. if (geom == IntPtr.Zero)
  112. {
  113. NoContacts(req);
  114. continue;
  115. }
  116. }
  117. CurrentRayFilter = req.filter;
  118. CurrentMaxCount = req.Count;
  119. if (CurrentMaxCount > 25)
  120. CurrentMaxCount = 25;
  121. unchecked
  122. {
  123. CollisionContactGeomsPerTest = ((CurrentRayFilter & RayFilterFlags.ContactsUnImportant) != 0) ?
  124. CurrentMaxCount | (int)UBOdeNative.CONTACTS_UNIMPORTANT : CurrentMaxCount;
  125. }
  126. int backfacecull = ((CurrentRayFilter & RayFilterFlags.BackFaceCull) == 0 ? 0 : 1);
  127. UBOdeNative.GeomRaySetParams(ray, 0, backfacecull);
  128. if (req.callbackMethod is RaycastCallback)
  129. {
  130. // if we only want one get only one per Collision pair saving memory
  131. CurrentRayFilter |= RayFilterFlags.ClosestHit;
  132. UBOdeNative.GeomRaySetClosestHit(ray, 1);
  133. }
  134. else
  135. {
  136. int closestHit = ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0 ? 0 : 1);
  137. UBOdeNative.GeomRaySetClosestHit(ray, closestHit);
  138. }
  139. if (geom == IntPtr.Zero)
  140. {
  141. // translate ray filter to Collision flags
  142. CollisionCategories catflags = 0;
  143. if ((CurrentRayFilter & RayFilterFlags.volumedtc) != 0)
  144. catflags |= CollisionCategories.VolumeDtc;
  145. if ((CurrentRayFilter & RayFilterFlags.phantom) != 0)
  146. catflags |= CollisionCategories.Phantom;
  147. if ((CurrentRayFilter & RayFilterFlags.agent) != 0)
  148. catflags |= CollisionCategories.Character;
  149. if ((CurrentRayFilter & RayFilterFlags.PrimsNonPhantom) != 0)
  150. catflags |= CollisionCategories.Geom;
  151. if ((CurrentRayFilter & RayFilterFlags.land) != 0)
  152. catflags |= CollisionCategories.Land;
  153. if (catflags != 0)
  154. {
  155. UBOdeNative.GeomSetCollideBits(ray, (uint)catflags);
  156. doSpaceRay(req);
  157. }
  158. }
  159. else
  160. {
  161. // if we select a geom don't use filters
  162. UBOdeNative.GeomSetCollideBits(ray, (uint)CollisionCategories.All);
  163. doGeomRay(req,geom);
  164. }
  165. if (Util.EnvironmentTickCountSubtract(time) > MaxTimePerCallMS)
  166. break;
  167. }
  168. lock (m_contactResultsLock)
  169. m_contactResults.Clear();
  170. }
  171. /// <summary>
  172. /// Method that actually initiates the raycast with spaces
  173. /// </summary>
  174. /// <param name="req"></param>
  175. ///
  176. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  177. private static void NoContacts(ODERayRequest req)
  178. {
  179. if (req.callbackMethod is RaycastCallback callback)
  180. callback(false, Vector3.Zero, 0, 0, Vector3.Zero);
  181. else if (req.callbackMethod is RayCallback raycallback)
  182. raycallback(new List<ContactResult>());
  183. }
  184. private const RayFilterFlags FilterActiveSpace = RayFilterFlags.physical | RayFilterFlags.LSLPhantom;
  185. private const RayFilterFlags FilterStaticSpace = RayFilterFlags.nonphysical | RayFilterFlags.LSLPhantom;
  186. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  187. private void doSpaceRay(ODERayRequest req)
  188. {
  189. UBOdeNative.GeomRaySetLength(ray, req.length);
  190. UBOdeNative.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
  191. // Collide tests
  192. if ((CurrentRayFilter & FilterActiveSpace) != 0)
  193. UBOdeNative.SpaceCollide2(ray, m_scene.ActiveSpace, IntPtr.Zero, nearCallback);
  194. if ((CurrentRayFilter & RayFilterFlags.agent) != 0)
  195. {
  196. foreach(OdeCharacter chr in CollectionsMarshal.AsSpan(m_scene._charactersList))
  197. {
  198. if (m_contactResults.Count >= CurrentMaxCount)
  199. break;
  200. if(m_scene.CollideRaySimpleCapsule(chr, req.Origin, req.Normal, req.length, ref SharedCollisionResult))
  201. {
  202. SharedCollisionResult.ConsumerID = chr.m_baseLocalID;
  203. m_contactResults.Add(SharedCollisionResult);
  204. }
  205. }
  206. }
  207. if ((CurrentRayFilter & FilterStaticSpace) != 0 && (m_contactResults.Count < CurrentMaxCount))
  208. UBOdeNative.SpaceCollide2(ray, m_scene.StaticSpace, IntPtr.Zero, nearCallback);
  209. if ((CurrentRayFilter & RayFilterFlags.land) != 0 && (m_contactResults.Count < CurrentMaxCount))
  210. {
  211. // current ode land to ray collisions is very bad
  212. // so for now limit its range badly
  213. if (req.length > 60.0f)
  214. {
  215. Vector3 t = req.Normal * req.length;
  216. float tmp = t.X * t.X + t.Y * t.Y;
  217. if(tmp > 2500)
  218. {
  219. float tmp2 = req.length * req.length - tmp + 2500;
  220. tmp2 = (float)Math.Sqrt(tmp2);
  221. UBOdeNative.GeomRaySetLength(ray, tmp2);
  222. }
  223. }
  224. CollideRayTerrain(m_scene.TerrainGeom);
  225. }
  226. if (req.callbackMethod is RaycastCallback callback)
  227. {
  228. // Define default results
  229. bool hitYN = false;
  230. uint hitConsumerID = 0;
  231. float distance = float.MaxValue;
  232. Vector3 closestcontact = Vector3.Zero;
  233. Vector3 snormal = Vector3.Zero;
  234. // Find closest contact and object.
  235. lock (m_contactResultsLock)
  236. {
  237. foreach (ContactResult cResult in m_contactResults)
  238. {
  239. if(cResult.Depth < distance)
  240. {
  241. closestcontact = cResult.Pos;
  242. hitConsumerID = cResult.ConsumerID;
  243. distance = cResult.Depth;
  244. snormal = cResult.Normal;
  245. }
  246. }
  247. m_contactResults.Clear();
  248. }
  249. if (distance > 0 && distance < float.MaxValue)
  250. hitYN = true;
  251. callback(hitYN, closestcontact, hitConsumerID, distance, snormal);
  252. }
  253. else
  254. {
  255. List<ContactResult> cresult = new(m_contactResults.Count);
  256. lock (m_contactResultsLock)
  257. {
  258. cresult.AddRange(m_contactResults);
  259. m_contactResults.Clear();
  260. }
  261. ((RayCallback)req.callbackMethod)(cresult);
  262. }
  263. }
  264. /// <summary>
  265. /// Method that actually initiates the raycast with a geom
  266. /// </summary>
  267. /// <param name="req"></param>
  268. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  269. private void doGeomRay(ODERayRequest req, IntPtr geom)
  270. {
  271. UBOdeNative.GeomRaySetLength(ray, req.length);
  272. UBOdeNative.GeomRaySet(ray, req.Origin.X, req.Origin.Y, req.Origin.Z, req.Normal.X, req.Normal.Y, req.Normal.Z);
  273. // Collide test
  274. UBOdeNative.SpaceCollide2(ray, geom, IntPtr.Zero, nearCallback); // still do this to have full AABB pre test
  275. if (req.callbackMethod is RaycastCallback callback)
  276. {
  277. // Define default results
  278. bool hitYN = false;
  279. uint hitConsumerID = 0;
  280. float distance = float.MaxValue;
  281. Vector3 closestcontact = Vector3.Zero;
  282. Vector3 snormal = Vector3.Zero;
  283. // Find closest contact and object.
  284. lock (m_contactResultsLock)
  285. {
  286. foreach (ContactResult cResult in m_contactResults)
  287. {
  288. if(cResult.Depth < distance )
  289. {
  290. closestcontact = cResult.Pos;
  291. hitConsumerID = cResult.ConsumerID;
  292. distance = cResult.Depth;
  293. snormal = cResult.Normal;
  294. }
  295. }
  296. m_contactResults.Clear();
  297. }
  298. if (distance > 0 && distance < float.MaxValue)
  299. hitYN = true;
  300. callback(hitYN, closestcontact, hitConsumerID, distance, snormal);
  301. }
  302. else
  303. {
  304. List<ContactResult> cresult = new(m_contactResults.Count);
  305. lock (m_contactResultsLock)
  306. {
  307. cresult.AddRange(m_contactResults);
  308. m_contactResults.Clear();
  309. }
  310. ((RayCallback)req.callbackMethod)(cresult);
  311. }
  312. }
  313. // This is the standard Near. g1 is the ray
  314. private void near(IntPtr dummy, IntPtr g1, IntPtr g2)
  315. {
  316. if (g2 == IntPtr.Zero)
  317. return;
  318. if (m_contactResults.Count >= CurrentMaxCount)
  319. return;
  320. if (UBOdeNative.GeomIsSpace(g2))
  321. {
  322. try
  323. {
  324. UBOdeNative.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
  325. }
  326. catch (Exception e)
  327. {
  328. m_log.WarnFormat("[PHYSICS Ray]: Unable to Space collide test an object: {0}", e.Message);
  329. }
  330. return;
  331. }
  332. int count;
  333. try
  334. {
  335. count = UBOdeNative.CollidePtr(g1, g2, CollisionContactGeomsPerTest, m_scene.ContactgeomsArray, UBOdeNative.SizeOfContactGeom);
  336. }
  337. catch (Exception e)
  338. {
  339. m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
  340. return;
  341. }
  342. if (count == 0)
  343. return;
  344. m_scene.actor_name_map.TryGetValue(g2, out PhysicsActor p2);
  345. if (p2 is null || p2.PhysicsActorType != (int)ActorTypes.Prim)
  346. return;
  347. RayFilterFlags thisFlags = p2.IsPhysical ? RayFilterFlags.physical : RayFilterFlags.nonphysical;
  348. if (p2.Phantom)
  349. thisFlags |= RayFilterFlags.phantom;
  350. if (p2.IsVolumeDtc)
  351. thisFlags |= RayFilterFlags.volumedtc;
  352. if ((thisFlags & CurrentRayFilter) == 0)
  353. return;
  354. uint ID = ((OdePrim)p2).LocalID;
  355. // closestHit for now only works for meshs, so must do it for others
  356. if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0)
  357. {
  358. // Loop all contacts, build results.
  359. for (int i = 0; i < count; ++i)
  360. {
  361. ref UBOdeNative.ContactGeom curCtg = ref m_contacts[i];
  362. lock (m_contactResultsLock)
  363. {
  364. m_contactResults.Add(new ContactResult
  365. {
  366. ConsumerID = ID,
  367. Pos = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.pos),
  368. Normal = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.normal),
  369. Depth = curCtg.depth
  370. });
  371. if (m_contactResults.Count >= CurrentMaxCount)
  372. return;
  373. }
  374. }
  375. }
  376. else
  377. {
  378. // keep only closest contact
  379. ref UBOdeNative.ContactGeom curCtg = ref m_contacts[0];
  380. SharedCollisionResult.Pos = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.pos);
  381. SharedCollisionResult.Normal = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.normal);
  382. float depth = curCtg.depth;
  383. SharedCollisionResult.Depth = depth;
  384. for (int i = 1; i < count; ++i)
  385. {
  386. curCtg = ref m_contacts[i];
  387. if (curCtg.depth < depth)
  388. {
  389. SharedCollisionResult.Pos = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.pos);
  390. SharedCollisionResult.Normal = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.normal);
  391. depth = curCtg.depth;
  392. SharedCollisionResult.Depth = depth;
  393. }
  394. }
  395. SharedCollisionResult.ConsumerID = ID;
  396. lock (m_contactResultsLock)
  397. m_contactResults.Add(SharedCollisionResult);
  398. }
  399. }
  400. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  401. private void CollideRayAvatar(OdeCharacter chr)
  402. {
  403. int count;
  404. try
  405. {
  406. count = UBOdeNative.CollidePtr(ray, chr.collider, CollisionContactGeomsPerTest, m_scene.ContactgeomsArray, UBOdeNative.SizeOfContactGeom);
  407. if (count == 0)
  408. return;
  409. }
  410. catch (Exception e)
  411. {
  412. m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
  413. return;
  414. }
  415. // closestHit for now only works for meshs, so must do it for others
  416. if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0)
  417. {
  418. uint id = chr.LocalID;
  419. // Loop all contacts, build results.
  420. for (int i = 0; i < count; i++)
  421. {
  422. ref UBOdeNative.ContactGeom curCtg = ref m_contacts[i];
  423. lock (m_contactResultsLock)
  424. {
  425. m_contactResults.Add(new ContactResult
  426. {
  427. ConsumerID = id,
  428. Pos = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.pos),
  429. Normal = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.normal),
  430. Depth = curCtg.depth
  431. });
  432. if (m_contactResults.Count >= CurrentMaxCount)
  433. return;
  434. }
  435. }
  436. }
  437. else
  438. {
  439. // keep only closest contact
  440. ref UBOdeNative.ContactGeom curCtg = ref m_contacts[0];
  441. SharedCollisionResult.Pos = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.pos);
  442. SharedCollisionResult.Normal = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.normal);
  443. float depth = curCtg.depth;
  444. SharedCollisionResult.Depth = depth;
  445. for (int i = 1; i < count; ++i)
  446. {
  447. curCtg = ref m_contacts[i];
  448. if (curCtg.depth < depth)
  449. {
  450. SharedCollisionResult.Pos = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.pos);
  451. SharedCollisionResult.Normal = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.normal);
  452. depth = curCtg.depth;
  453. SharedCollisionResult.Depth = depth;
  454. }
  455. }
  456. SharedCollisionResult.ConsumerID = chr.LocalID;
  457. lock (m_contactResultsLock)
  458. m_contactResults.Add(SharedCollisionResult);
  459. }
  460. }
  461. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  462. private void CollideRayTerrain(IntPtr terrain)
  463. {
  464. if (terrain == IntPtr.Zero)
  465. return;
  466. int count;
  467. try
  468. {
  469. count = UBOdeNative.CollidePtr(ray, terrain, CollisionContactGeomsPerTest, m_scene.ContactgeomsArray, UBOdeNative.SizeOfContactGeom);
  470. if (count == 0)
  471. return;
  472. }
  473. catch (Exception e)
  474. {
  475. m_log.WarnFormat("[PHYSICS Ray]: Unable to collide test an object: {0}", e.Message);
  476. return;
  477. }
  478. // closestHit for now only works for meshs, so must do it for others
  479. if ((CurrentRayFilter & RayFilterFlags.ClosestHit) == 0)
  480. {
  481. // Loop all contacts, build results.
  482. for (int i = 0; i < count; i++)
  483. {
  484. ref UBOdeNative.ContactGeom curCtg = ref m_contacts[i];
  485. lock (m_contactResultsLock)
  486. {
  487. m_contactResults.Add(new ContactResult
  488. {
  489. ConsumerID = 0,
  490. Pos = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.pos),
  491. Normal = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.normal),
  492. Depth = curCtg.depth
  493. });
  494. if (m_contactResults.Count >= CurrentMaxCount)
  495. return;
  496. }
  497. }
  498. }
  499. else
  500. {
  501. // keep only closest contact
  502. ref UBOdeNative.ContactGeom curCtg = ref m_contacts[0];
  503. SharedCollisionResult.Pos = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.pos);
  504. SharedCollisionResult.Normal = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.normal);
  505. float depth = curCtg.depth;
  506. SharedCollisionResult.Depth = depth;
  507. for (int i = 1; i < count; ++i)
  508. {
  509. curCtg = ref m_contacts[i];
  510. if (curCtg.depth < depth)
  511. {
  512. SharedCollisionResult.Pos = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.pos);
  513. SharedCollisionResult.Normal = Unsafe.As<UBOdeNative.Vector3, Vector3>(ref curCtg.normal);
  514. depth = curCtg.depth;
  515. SharedCollisionResult.Depth = depth;
  516. }
  517. }
  518. SharedCollisionResult.ConsumerID = 0;
  519. lock (m_contactResultsLock)
  520. m_contactResults.Add(SharedCollisionResult);
  521. }
  522. }
  523. /// <summary>
  524. /// Dereference the creator scene so that it can be garbage collected if needed.
  525. /// </summary>
  526. internal void Dispose()
  527. {
  528. if (ray != IntPtr.Zero)
  529. {
  530. UBOdeNative.GeomDestroy(ray);
  531. ray = IntPtr.Zero;
  532. }
  533. }
  534. }
  535. public class ODERayRequest
  536. {
  537. public Vector3 Origin;
  538. public Vector3 Normal;
  539. public object callbackMethod;
  540. public PhysicsActor actor;
  541. public int Count;
  542. public float length;
  543. public RayFilterFlags filter;
  544. }
  545. }