OPC_HybridModel.cpp 16 KB

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