OPC_HybridModel.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. /*
  3. * OPCODE - Optimized Collision Detection
  4. * Copyright (C) 2001 Pierre Terdiman
  5. * Homepage: http://www.codercorner.com/Opcode.htm
  6. */
  7. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. /**
  10. * Contains code for hybrid models.
  11. * \file OPC_HybridModel.cpp
  12. * \author Pierre Terdiman
  13. * \date May, 18, 2003
  14. */
  15. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. /**
  18. * An hybrid collision model.
  19. *
  20. * The problem :
  21. *
  22. * Opcode really shines for mesh-mesh collision, especially when meshes are deeply overlapping
  23. * (it typically outperforms RAPID in those cases).
  24. *
  25. * Unfortunately this is not the typical scenario in games.
  26. *
  27. * For close-proximity cases, especially for volume-mesh queries, it's relatively easy to run faster
  28. * than Opcode, that suffers from a relatively high setup time.
  29. *
  30. * In particular, Opcode's "vanilla" trees in those cases -can- run faster. They can also use -less-
  31. * memory than the optimized ones, when you let the system stop at ~10 triangles / leaf for example
  32. * (i.e. when you don't use "complete" trees). However, those trees tend to fragment memory quite a
  33. * lot, increasing cache misses : since they're not "complete", we can't predict the final number of
  34. * nodes and we have to allocate nodes on-the-fly. For the same reasons we can't use Opcode's "optimized"
  35. * trees here, since they rely on a known layout to perform the "optimization".
  36. *
  37. * Hybrid trees :
  38. *
  39. * Hybrid trees try to combine best of both worlds :
  40. *
  41. * - they use a maximum limit of 16 triangles/leaf. "16" is used so that we'll be able to save the
  42. * number of triangles using 4 bits only.
  43. *
  44. * - they're still "complete" trees thanks to a two-passes building phase. First we create a "vanilla"
  45. * AABB-tree with Opcode, limited to 16 triangles/leaf. Then we create a *second* vanilla tree, this
  46. * time using the leaves of the first one. The trick is : this second tree is now "complete"... so we
  47. * can further transform it into an Opcode's optimized tree.
  48. *
  49. * - then we run the collision queries on that standard Opcode tree. The only difference is that leaf
  50. * nodes contain indices to leaf nodes of another tree. Also, we have to skip all primitive tests in
  51. * Opcode optimized trees, since our leaves don't contain triangles anymore.
  52. *
  53. * - finally, for each collided leaf, we simply loop through 16 triangles max, and collide them with
  54. * the bounding volume used in the query (we only support volume-vs-mesh queries here, not mesh-vs-mesh)
  55. *
  56. * All of that is wrapped in this "hybrid model" that contains the minimal data required for this to work.
  57. * It's a mix between old "vanilla" trees, and old "optimized" trees.
  58. *
  59. * Extra advantages:
  60. *
  61. * - If we use them for dynamic models, we're left with a very small number of leaf nodes to refit. It
  62. * might be a bit faster since we have less nodes to write back.
  63. *
  64. * - In rigid body simulation, using temporal coherence and sleeping objects greatly reduce the actual
  65. * influence of one tree over another (i.e. the speed difference is often invisible). So memory is really
  66. * the key element to consider, and in this regard hybrid trees are just better.
  67. *
  68. * Information to take home:
  69. * - they use less ram
  70. * - they're not slower (they're faster or slower depending on cases, overall there's no significant
  71. * difference *as long as objects don't interpenetrate too much* - in which case Opcode's optimized trees
  72. * are still notably faster)
  73. *
  74. * \class HybridModel
  75. * \author Pierre Terdiman
  76. * \version 1.3
  77. * \date May, 18, 2003
  78. */
  79. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  80. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  81. #include "Opcode.h"
  82. #include <stdint.h>
  83. using namespace Opcode;
  84. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  85. /**
  86. * Constructor.
  87. */
  88. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  89. HybridModel::HybridModel() :
  90. mNbLeaves (0),
  91. mNbPrimitives (0),
  92. mTriangles (null),
  93. mIndices (null)
  94. {
  95. }
  96. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. /**
  98. * Destructor.
  99. */
  100. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  101. HybridModel::~HybridModel()
  102. {
  103. Release();
  104. }
  105. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  106. /**
  107. * Releases everything.
  108. */
  109. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  110. void HybridModel::Release()
  111. {
  112. ReleaseBase();
  113. DELETEARRAY(mIndices);
  114. DELETEARRAY(mTriangles);
  115. mNbLeaves = 0;
  116. mNbPrimitives = 0;
  117. }
  118. struct Internal
  119. {
  120. Internal()
  121. {
  122. mNbLeaves = 0;
  123. mLeaves = null;
  124. mTriangles = null;
  125. mBase = null;
  126. }
  127. ~Internal()
  128. {
  129. DELETEARRAY(mLeaves);
  130. }
  131. udword mNbLeaves;
  132. AABB* mLeaves;
  133. LeafTriangles* mTriangles;
  134. const udword* mBase;
  135. };
  136. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  137. /**
  138. * Builds a collision model.
  139. * \param create [in] model creation structure
  140. * \return true if success
  141. */
  142. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  143. bool HybridModel::Build(const OPCODECREATE& create)
  144. {
  145. // 1) Checkings
  146. if(!create.mIMesh || !create.mIMesh->IsValid()) return false;
  147. // Look for degenerate faces.
  148. udword NbDegenerate = create.mIMesh->CheckTopology();
  149. if(NbDegenerate) Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate);
  150. // We continue nonetheless....
  151. Release(); // Make sure previous tree has been discarded
  152. // 1-1) Setup mesh interface automatically
  153. SetMeshInterface(create.mIMesh);
  154. bool Status = false;
  155. AABBTree* LeafTree = null;
  156. Internal Data;
  157. // 2) Build a generic AABB Tree.
  158. mSource = new AABBTree;
  159. CHECKALLOC(mSource);
  160. // 2-1) Setup a builder. Our primitives here are triangles from input mesh,
  161. // so we use an AABBTreeOfTrianglesBuilder.....
  162. {
  163. AABBTreeOfTrianglesBuilder TB;
  164. TB.mIMesh = create.mIMesh;
  165. TB.mNbPrimitives = create.mIMesh->GetNbTriangles();
  166. TB.mSettings = create.mSettings;
  167. TB.mSettings.mLimit = 16; // ### Hardcoded, but maybe we could let the user choose 8 / 16 / 32 ...
  168. if(!mSource->Build(&TB)) goto FreeAndExit;
  169. }
  170. // 2-2) Here's the trick : create *another* AABB tree using the leaves of the first one (which are boxes, this time)
  171. struct Local
  172. {
  173. // A callback to count leaf nodes
  174. static bool CountLeaves(const AABBTreeNode* current, udword depth, void* user_data)
  175. {
  176. if(current->IsLeaf())
  177. {
  178. Internal* Data = (Internal*)user_data;
  179. Data->mNbLeaves++;
  180. }
  181. return true;
  182. }
  183. // A callback to setup leaf nodes in our internal structures
  184. static bool SetupLeafData(const AABBTreeNode* current, udword depth, void* user_data)
  185. {
  186. if(current->IsLeaf())
  187. {
  188. Internal* Data = (Internal*)user_data;
  189. // Get current leaf's box
  190. Data->mLeaves[Data->mNbLeaves] = *current->GetAABB();
  191. // Setup leaf data
  192. udword Index = (uintptr_t(current->GetPrimitives()) - uintptr_t(Data->mBase))/sizeof(uintptr_t);
  193. Data->mTriangles[Data->mNbLeaves].SetData(current->GetNbPrimitives(), Index);
  194. Data->mNbLeaves++;
  195. }
  196. return true;
  197. }
  198. };
  199. // Walk the tree & count number of leaves
  200. Data.mNbLeaves = 0;
  201. mSource->Walk(Local::CountLeaves, &Data);
  202. mNbLeaves = Data.mNbLeaves; // Keep track of it
  203. // Special case for 1-leaf meshes
  204. if(mNbLeaves==1)
  205. {
  206. mModelCode |= OPC_SINGLE_NODE;
  207. Status = true;
  208. goto FreeAndExit;
  209. }
  210. // Allocate our structures
  211. Data.mLeaves = new AABB[Data.mNbLeaves]; CHECKALLOC(Data.mLeaves);
  212. mTriangles = new LeafTriangles[Data.mNbLeaves]; CHECKALLOC(mTriangles);
  213. // Walk the tree again & setup leaf data
  214. Data.mTriangles = mTriangles;
  215. Data.mBase = mSource->GetIndices();
  216. Data.mNbLeaves = 0; // Reset for incoming walk
  217. mSource->Walk(Local::SetupLeafData, &Data);
  218. // Handle source indices
  219. {
  220. bool MustKeepIndices = true;
  221. if(create.mCanRemap)
  222. {
  223. // We try to get rid of source indices (saving more ram!) by reorganizing triangle arrays...
  224. // Remap can fail when we use callbacks => keep track of indices in that case (it still
  225. // works, only using more memory)
  226. if(create.mIMesh->RemapClient(mSource->GetNbPrimitives(), mSource->GetIndices()))
  227. {
  228. MustKeepIndices = false;
  229. }
  230. }
  231. if(MustKeepIndices)
  232. {
  233. // Keep track of source indices (from vanilla tree)
  234. mNbPrimitives = mSource->GetNbPrimitives();
  235. mIndices = new udword[mNbPrimitives];
  236. CopyMemory(mIndices, mSource->GetIndices(), mNbPrimitives*sizeof(udword));
  237. }
  238. }
  239. // Now, create our optimized tree using previous leaf nodes
  240. LeafTree = new AABBTree;
  241. CHECKALLOC(LeafTree);
  242. {
  243. AABBTreeOfAABBsBuilder TB; // Now using boxes !
  244. TB.mSettings = create.mSettings;
  245. TB.mSettings.mLimit = 1; // We now want a complete tree so that we can "optimize" it
  246. TB.mNbPrimitives = Data.mNbLeaves;
  247. TB.mAABBArray = Data.mLeaves;
  248. if(!LeafTree->Build(&TB)) goto FreeAndExit;
  249. }
  250. // 3) Create an optimized tree according to user-settings
  251. if(!CreateTree(create.mNoLeaf, create.mQuantized)) goto FreeAndExit;
  252. // 3-2) Create optimized tree
  253. if(!mTree->Build(LeafTree)) goto FreeAndExit;
  254. // Finally ok...
  255. Status = true;
  256. FreeAndExit: // Allow me this one...
  257. DELETESINGLE(LeafTree);
  258. // 3-3) Delete generic tree if needed
  259. if(!create.mKeepOriginal) DELETESINGLE(mSource);
  260. return Status;
  261. }
  262. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  263. /**
  264. * Gets the number of bytes used by the tree.
  265. * \return amount of bytes used
  266. */
  267. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  268. udword HybridModel::GetUsedBytes() const
  269. {
  270. udword UsedBytes = 0;
  271. if(mTree) UsedBytes += mTree->GetUsedBytes();
  272. if(mIndices) UsedBytes += mNbPrimitives * sizeof(udword); // mIndices
  273. if(mTriangles) UsedBytes += mNbLeaves * sizeof(LeafTriangles); // mTriangles
  274. return UsedBytes;
  275. }
  276. inline_ void ComputeMinMax(Point& min, Point& max, const VertexPointers& vp)
  277. {
  278. // Compute triangle's AABB = a leaf box
  279. #ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much
  280. min.x = FCMin3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x);
  281. max.x = FCMax3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x);
  282. min.y = FCMin3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y);
  283. max.y = FCMax3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y);
  284. min.z = FCMin3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z);
  285. max.z = FCMax3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z);
  286. #else
  287. min = *vp.Vertex[0];
  288. max = *vp.Vertex[0];
  289. min.Min(*vp.Vertex[1]);
  290. max.Max(*vp.Vertex[1]);
  291. min.Min(*vp.Vertex[2]);
  292. max.Max(*vp.Vertex[2]);
  293. #endif
  294. }
  295. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  296. /**
  297. * Refits the collision model. This can be used to handle dynamic meshes. Usage is:
  298. * 1. modify your mesh vertices (keep the topology constant!)
  299. * 2. refit the tree (call this method)
  300. * \return true if success
  301. */
  302. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  303. bool HybridModel::Refit()
  304. {
  305. if(!mIMesh) return false;
  306. if(!mTree) return false;
  307. if(IsQuantized()) return false;
  308. if(HasLeafNodes()) return false;
  309. const LeafTriangles* LT = GetLeafTriangles();
  310. const udword* Indices = GetIndices();
  311. // Bottom-up update
  312. VertexPointers VP;
  313. Point Min,Max;
  314. Point Min_,Max_;
  315. udword Index = mTree->GetNbNodes();
  316. AABBNoLeafNode* Nodes = (AABBNoLeafNode*)((AABBNoLeafTree*)mTree)->GetNodes();
  317. while(Index--)
  318. {
  319. AABBNoLeafNode& Current = Nodes[Index];
  320. if(Current.HasPosLeaf())
  321. {
  322. const LeafTriangles& CurrentLeaf = LT[Current.GetPosPrimitive()];
  323. Min.SetPlusInfinity();
  324. Max.SetMinusInfinity();
  325. Point TmpMin, TmpMax;
  326. // Each leaf box has a set of triangles
  327. udword NbTris = CurrentLeaf.GetNbTriangles();
  328. if(Indices)
  329. {
  330. const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
  331. // Loop through triangles and test each of them
  332. while(NbTris--)
  333. {
  334. mIMesh->GetTriangle(VP, *T++);
  335. ComputeMinMax(TmpMin, TmpMax, VP);
  336. Min.Min(TmpMin);
  337. Max.Max(TmpMax);
  338. }
  339. }
  340. else
  341. {
  342. udword BaseIndex = CurrentLeaf.GetTriangleIndex();
  343. // Loop through triangles and test each of them
  344. while(NbTris--)
  345. {
  346. mIMesh->GetTriangle(VP, BaseIndex++);
  347. ComputeMinMax(TmpMin, TmpMax, VP);
  348. Min.Min(TmpMin);
  349. Max.Max(TmpMax);
  350. }
  351. }
  352. }
  353. else
  354. {
  355. const CollisionAABB& CurrentBox = Current.GetPos()->mAABB;
  356. CurrentBox.GetMin(Min);
  357. CurrentBox.GetMax(Max);
  358. }
  359. if(Current.HasNegLeaf())
  360. {
  361. const LeafTriangles& CurrentLeaf = LT[Current.GetNegPrimitive()];
  362. Min_.SetPlusInfinity();
  363. Max_.SetMinusInfinity();
  364. Point TmpMin, TmpMax;
  365. // Each leaf box has a set of triangles
  366. udword NbTris = CurrentLeaf.GetNbTriangles();
  367. if(Indices)
  368. {
  369. const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
  370. // Loop through triangles and test each of them
  371. while(NbTris--)
  372. {
  373. mIMesh->GetTriangle(VP, *T++);
  374. ComputeMinMax(TmpMin, TmpMax, VP);
  375. Min_.Min(TmpMin);
  376. Max_.Max(TmpMax);
  377. }
  378. }
  379. else
  380. {
  381. udword BaseIndex = CurrentLeaf.GetTriangleIndex();
  382. // Loop through triangles and test each of them
  383. while(NbTris--)
  384. {
  385. mIMesh->GetTriangle(VP, BaseIndex++);
  386. ComputeMinMax(TmpMin, TmpMax, VP);
  387. Min_.Min(TmpMin);
  388. Max_.Max(TmpMax);
  389. }
  390. }
  391. }
  392. else
  393. {
  394. const CollisionAABB& CurrentBox = Current.GetNeg()->mAABB;
  395. CurrentBox.GetMin(Min_);
  396. CurrentBox.GetMax(Max_);
  397. }
  398. #ifdef OPC_USE_FCOMI
  399. Min.x = FCMin2(Min.x, Min_.x);
  400. Max.x = FCMax2(Max.x, Max_.x);
  401. Min.y = FCMin2(Min.y, Min_.y);
  402. Max.y = FCMax2(Max.y, Max_.y);
  403. Min.z = FCMin2(Min.z, Min_.z);
  404. Max.z = FCMax2(Max.z, Max_.z);
  405. #else
  406. Min.Min(Min_);
  407. Max.Max(Max_);
  408. #endif
  409. Current.mAABB.SetMinMax(Min, Max);
  410. }
  411. return true;
  412. }