OPC_HybridModel.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  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. #if (defined _MSC_VER) && (_MSC_VER <= 1500)
  83. #ifdef _WIN64 // [
  84. typedef unsigned __int64 uintptr_t;
  85. #else // _WIN64 ][
  86. typedef _W64 unsigned int uintptr_t;
  87. #endif // _WIN64 ]
  88. #else
  89. #include <stdint.h>
  90. #endif
  91. using namespace Opcode;
  92. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  93. /**
  94. * Constructor.
  95. */
  96. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. HybridModel::HybridModel() :
  98. mNbLeaves (0),
  99. mNbPrimitives (0),
  100. mTriangles (null),
  101. mIndices (null)
  102. {
  103. }
  104. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  105. /**
  106. * Destructor.
  107. */
  108. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. HybridModel::~HybridModel()
  110. {
  111. Release();
  112. }
  113. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  114. /**
  115. * Releases everything.
  116. */
  117. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  118. void HybridModel::Release()
  119. {
  120. ReleaseBase();
  121. DELETEARRAY(mIndices);
  122. DELETEARRAY(mTriangles);
  123. mNbLeaves = 0;
  124. mNbPrimitives = 0;
  125. }
  126. struct Internal
  127. {
  128. Internal()
  129. {
  130. mNbLeaves = 0;
  131. mLeaves = null;
  132. mTriangles = null;
  133. mBase = null;
  134. }
  135. ~Internal()
  136. {
  137. DELETEARRAY(mLeaves);
  138. }
  139. udword mNbLeaves;
  140. AABB* mLeaves;
  141. LeafTriangles* mTriangles;
  142. const udword* mBase;
  143. };
  144. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  145. /**
  146. * Builds a collision model.
  147. * \param create [in] model creation structure
  148. * \return true if success
  149. */
  150. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  151. bool HybridModel::Build(const OPCODECREATE& create)
  152. {
  153. // 1) Checkings
  154. if(!create.mIMesh || !create.mIMesh->IsValid()) return false;
  155. // Look for degenerate faces.
  156. udword NbDegenerate = create.mIMesh->CheckTopology();
  157. if(NbDegenerate) Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate);
  158. // We continue nonetheless....
  159. Release(); // Make sure previous tree has been discarded
  160. // 1-1) Setup mesh interface automatically
  161. SetMeshInterface(create.mIMesh);
  162. bool Status = false;
  163. AABBTree* LeafTree = null;
  164. Internal Data;
  165. // 2) Build a generic AABB Tree.
  166. mSource = new AABBTree;
  167. CHECKALLOC(mSource);
  168. // 2-1) Setup a builder. Our primitives here are triangles from input mesh,
  169. // so we use an AABBTreeOfTrianglesBuilder.....
  170. {
  171. AABBTreeOfTrianglesBuilder TB;
  172. TB.mIMesh = create.mIMesh;
  173. TB.mNbPrimitives = create.mIMesh->GetNbTriangles();
  174. TB.mSettings = create.mSettings;
  175. TB.mSettings.mLimit = 16; // ### Hardcoded, but maybe we could let the user choose 8 / 16 / 32 ...
  176. if(!mSource->Build(&TB)) goto FreeAndExit;
  177. }
  178. // 2-2) Here's the trick : create *another* AABB tree using the leaves of the first one (which are boxes, this time)
  179. struct Local
  180. {
  181. // A callback to count leaf nodes
  182. static bool CountLeaves(const AABBTreeNode* current, udword depth, void* user_data)
  183. {
  184. if(current->IsLeaf())
  185. {
  186. Internal* Data = (Internal*)user_data;
  187. Data->mNbLeaves++;
  188. }
  189. return true;
  190. }
  191. // A callback to setup leaf nodes in our internal structures
  192. static bool SetupLeafData(const AABBTreeNode* current, udword depth, void* user_data)
  193. {
  194. if(current->IsLeaf())
  195. {
  196. Internal* Data = (Internal*)user_data;
  197. // Get current leaf's box
  198. Data->mLeaves[Data->mNbLeaves] = *current->GetAABB();
  199. // Setup leaf data
  200. udword Index = (uintptr_t(current->GetPrimitives()) - uintptr_t(Data->mBase))/sizeof(uintptr_t);
  201. Data->mTriangles[Data->mNbLeaves].SetData(current->GetNbPrimitives(), Index);
  202. Data->mNbLeaves++;
  203. }
  204. return true;
  205. }
  206. };
  207. // Walk the tree & count number of leaves
  208. Data.mNbLeaves = 0;
  209. mSource->Walk(Local::CountLeaves, &Data);
  210. mNbLeaves = Data.mNbLeaves; // Keep track of it
  211. // Special case for 1-leaf meshes
  212. if(mNbLeaves==1)
  213. {
  214. mModelCode |= OPC_SINGLE_NODE;
  215. Status = true;
  216. goto FreeAndExit;
  217. }
  218. // Allocate our structures
  219. Data.mLeaves = new AABB[Data.mNbLeaves]; CHECKALLOC(Data.mLeaves);
  220. mTriangles = new LeafTriangles[Data.mNbLeaves]; CHECKALLOC(mTriangles);
  221. // Walk the tree again & setup leaf data
  222. Data.mTriangles = mTriangles;
  223. Data.mBase = mSource->GetIndices();
  224. Data.mNbLeaves = 0; // Reset for incoming walk
  225. mSource->Walk(Local::SetupLeafData, &Data);
  226. // Handle source indices
  227. {
  228. bool MustKeepIndices = true;
  229. if(create.mCanRemap)
  230. {
  231. // We try to get rid of source indices (saving more ram!) by reorganizing triangle arrays...
  232. // Remap can fail when we use callbacks => keep track of indices in that case (it still
  233. // works, only using more memory)
  234. if(create.mIMesh->RemapClient(mSource->GetNbPrimitives(), mSource->GetIndices()))
  235. {
  236. MustKeepIndices = false;
  237. }
  238. }
  239. if(MustKeepIndices)
  240. {
  241. // Keep track of source indices (from vanilla tree)
  242. mNbPrimitives = mSource->GetNbPrimitives();
  243. mIndices = new udword[mNbPrimitives];
  244. CopyMemory(mIndices, mSource->GetIndices(), mNbPrimitives*sizeof(udword));
  245. }
  246. }
  247. // Now, create our optimized tree using previous leaf nodes
  248. LeafTree = new AABBTree;
  249. CHECKALLOC(LeafTree);
  250. {
  251. AABBTreeOfAABBsBuilder TB; // Now using boxes !
  252. TB.mSettings = create.mSettings;
  253. TB.mSettings.mLimit = 1; // We now want a complete tree so that we can "optimize" it
  254. TB.mNbPrimitives = Data.mNbLeaves;
  255. TB.mAABBArray = Data.mLeaves;
  256. if(!LeafTree->Build(&TB)) goto FreeAndExit;
  257. }
  258. // 3) Create an optimized tree according to user-settings
  259. if(!CreateTree(create.mNoLeaf, create.mQuantized)) goto FreeAndExit;
  260. // 3-2) Create optimized tree
  261. if(!mTree->Build(LeafTree)) goto FreeAndExit;
  262. // Finally ok...
  263. Status = true;
  264. FreeAndExit: // Allow me this one...
  265. DELETESINGLE(LeafTree);
  266. // 3-3) Delete generic tree if needed
  267. if(!create.mKeepOriginal) DELETESINGLE(mSource);
  268. return Status;
  269. }
  270. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  271. /**
  272. * Gets the number of bytes used by the tree.
  273. * \return amount of bytes used
  274. */
  275. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  276. udword HybridModel::GetUsedBytes() const
  277. {
  278. udword UsedBytes = 0;
  279. if(mTree) UsedBytes += mTree->GetUsedBytes();
  280. if(mIndices) UsedBytes += mNbPrimitives * sizeof(udword); // mIndices
  281. if(mTriangles) UsedBytes += mNbLeaves * sizeof(LeafTriangles); // mTriangles
  282. return UsedBytes;
  283. }
  284. inline_ void ComputeMinMax(Point& min, Point& max, const VertexPointers& vp)
  285. {
  286. // Compute triangle's AABB = a leaf box
  287. #ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much
  288. min.x = FCMin3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x);
  289. max.x = FCMax3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x);
  290. min.y = FCMin3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y);
  291. max.y = FCMax3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y);
  292. min.z = FCMin3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z);
  293. max.z = FCMax3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z);
  294. #else
  295. min = *vp.Vertex[0];
  296. max = *vp.Vertex[0];
  297. min.Min(*vp.Vertex[1]);
  298. max.Max(*vp.Vertex[1]);
  299. min.Min(*vp.Vertex[2]);
  300. max.Max(*vp.Vertex[2]);
  301. #endif
  302. }
  303. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  304. /**
  305. * Refits the collision model. This can be used to handle dynamic meshes. Usage is:
  306. * 1. modify your mesh vertices (keep the topology constant!)
  307. * 2. refit the tree (call this method)
  308. * \return true if success
  309. */
  310. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  311. bool HybridModel::Refit()
  312. {
  313. if(!mIMesh) return false;
  314. if(!mTree) return false;
  315. if(IsQuantized()) return false;
  316. if(HasLeafNodes()) return false;
  317. const LeafTriangles* LT = GetLeafTriangles();
  318. const udword* Indices = GetIndices();
  319. // Bottom-up update
  320. VertexPointers VP;
  321. Point Min,Max;
  322. Point Min_,Max_;
  323. udword Index = mTree->GetNbNodes();
  324. AABBNoLeafNode* Nodes = (AABBNoLeafNode*)((AABBNoLeafTree*)mTree)->GetNodes();
  325. while(Index--)
  326. {
  327. AABBNoLeafNode& Current = Nodes[Index];
  328. if(Current.HasPosLeaf())
  329. {
  330. const LeafTriangles& CurrentLeaf = LT[Current.GetPosPrimitive()];
  331. Min.SetPlusInfinity();
  332. Max.SetMinusInfinity();
  333. Point TmpMin, TmpMax;
  334. // Each leaf box has a set of triangles
  335. udword NbTris = CurrentLeaf.GetNbTriangles();
  336. if(Indices)
  337. {
  338. const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
  339. // Loop through triangles and test each of them
  340. while(NbTris--)
  341. {
  342. mIMesh->GetTriangle(VP, *T++);
  343. ComputeMinMax(TmpMin, TmpMax, VP);
  344. Min.Min(TmpMin);
  345. Max.Max(TmpMax);
  346. }
  347. }
  348. else
  349. {
  350. udword BaseIndex = CurrentLeaf.GetTriangleIndex();
  351. // Loop through triangles and test each of them
  352. while(NbTris--)
  353. {
  354. mIMesh->GetTriangle(VP, BaseIndex++);
  355. ComputeMinMax(TmpMin, TmpMax, VP);
  356. Min.Min(TmpMin);
  357. Max.Max(TmpMax);
  358. }
  359. }
  360. }
  361. else
  362. {
  363. const CollisionAABB& CurrentBox = Current.GetPos()->mAABB;
  364. CurrentBox.GetMin(Min);
  365. CurrentBox.GetMax(Max);
  366. }
  367. if(Current.HasNegLeaf())
  368. {
  369. const LeafTriangles& CurrentLeaf = LT[Current.GetNegPrimitive()];
  370. Min_.SetPlusInfinity();
  371. Max_.SetMinusInfinity();
  372. Point TmpMin, TmpMax;
  373. // Each leaf box has a set of triangles
  374. udword NbTris = CurrentLeaf.GetNbTriangles();
  375. if(Indices)
  376. {
  377. const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()];
  378. // Loop through triangles and test each of them
  379. while(NbTris--)
  380. {
  381. mIMesh->GetTriangle(VP, *T++);
  382. ComputeMinMax(TmpMin, TmpMax, VP);
  383. Min_.Min(TmpMin);
  384. Max_.Max(TmpMax);
  385. }
  386. }
  387. else
  388. {
  389. udword BaseIndex = CurrentLeaf.GetTriangleIndex();
  390. // Loop through triangles and test each of them
  391. while(NbTris--)
  392. {
  393. mIMesh->GetTriangle(VP, BaseIndex++);
  394. ComputeMinMax(TmpMin, TmpMax, VP);
  395. Min_.Min(TmpMin);
  396. Max_.Max(TmpMax);
  397. }
  398. }
  399. }
  400. else
  401. {
  402. const CollisionAABB& CurrentBox = Current.GetNeg()->mAABB;
  403. CurrentBox.GetMin(Min_);
  404. CurrentBox.GetMax(Max_);
  405. }
  406. #ifdef OPC_USE_FCOMI
  407. Min.x = FCMin2(Min.x, Min_.x);
  408. Max.x = FCMax2(Max.x, Max_.x);
  409. Min.y = FCMin2(Min.y, Min_.y);
  410. Max.y = FCMax2(Max.y, Max_.y);
  411. Min.z = FCMin2(Min.z, Min_.z);
  412. Max.z = FCMax2(Max.z, Max_.z);
  413. #else
  414. Min.Min(Min_);
  415. Max.Max(Max_);
  416. #endif
  417. Current.mAABB.SetMinMax(Min, Max);
  418. }
  419. return true;
  420. }