CollisionShape.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "CollisionShape.h"
  25. #include "Context.h"
  26. #include "DebugRenderer.h"
  27. #include "Geometry.h"
  28. #include "Log.h"
  29. #include "Model.h"
  30. #include "PhysicsWorld.h"
  31. #include "Profiler.h"
  32. #include "ResourceCache.h"
  33. #include "RigidBody.h"
  34. #include "Scene.h"
  35. #include "StringUtils.h"
  36. #include "XMLFile.h"
  37. #include <ode/ode.h>
  38. #include <../ode/src/heightfield.h>
  39. #include <../ode/src/collision_std.h>
  40. #include <hull.h>
  41. #include "DebugNew.h"
  42. static const std::string typeNames[] =
  43. {
  44. "none",
  45. "box",
  46. "sphere",
  47. "capsule",
  48. "cylinder",
  49. "trianglemesh",
  50. "heightfield",
  51. "convexhull",
  52. ""
  53. };
  54. static const float DEFAULT_FRICTION = 0.5f;
  55. static const float DEFAULT_BOUNCE = 0.0f;
  56. void GetVertexAndIndexData(const Model* model, unsigned lodLevel, SharedArrayPtr<Vector3>& destVertexData, unsigned& destVertexCount,
  57. SharedArrayPtr<unsigned>& destIndexData, unsigned& destIndexCount, const Vector3& scale)
  58. {
  59. const std::vector<std::vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
  60. destVertexCount = 0;
  61. destIndexCount = 0;
  62. for (unsigned i = 0; i < geometries.size(); ++i)
  63. {
  64. unsigned subGeometryLodLevel = Clamp(lodLevel, 0, geometries[i].size());
  65. Geometry* geom = geometries[i][subGeometryLodLevel];
  66. if (!geom)
  67. continue;
  68. destVertexCount += geom->GetVertexCount();
  69. destIndexCount += geom->GetIndexCount();
  70. }
  71. if ((!destVertexCount) || (!destIndexCount))
  72. return;
  73. destVertexData = new Vector3[destVertexCount];
  74. destIndexData = new unsigned[destIndexCount];
  75. unsigned firstVertex = 0;
  76. unsigned firstIndex = 0;
  77. for (unsigned i = 0; i < geometries.size(); ++i)
  78. {
  79. unsigned subGeometryLodLevel = lodLevel;
  80. if (subGeometryLodLevel >= geometries[i].size())
  81. subGeometryLodLevel = geometries[i].size() / 2;
  82. Geometry* geom = geometries[i][subGeometryLodLevel];
  83. if (!geom)
  84. continue;
  85. const unsigned char* vertexData;
  86. const unsigned char* indexData;
  87. unsigned vertexSize;
  88. unsigned indexSize;
  89. geom->LockRawData(vertexData, vertexSize, indexData, indexSize);
  90. if ((!vertexData) || (!indexData))
  91. continue;
  92. unsigned vertexStart = geom->GetVertexStart();
  93. unsigned vertexCount = geom->GetVertexCount();
  94. // Copy vertex data
  95. for (unsigned j = 0; j < vertexCount; ++j)
  96. {
  97. const Vector3& v = *((const Vector3*)(&vertexData[(vertexStart + j) * vertexSize]));
  98. destVertexData[firstVertex + j] = scale * v;
  99. }
  100. unsigned indexStart = geom->GetIndexStart();
  101. unsigned indexCount = geom->GetIndexCount();
  102. // 16-bit indices
  103. if (indexSize == sizeof(unsigned short))
  104. {
  105. const unsigned short* indices = (const unsigned short*)indexData;
  106. for (unsigned j = 0; j < indexCount; j += 3)
  107. {
  108. // Rebase the indices according to our vertex numbering
  109. destIndexData[firstIndex + j] = indices[indexStart + j] - vertexStart + firstVertex;
  110. destIndexData[firstIndex + j + 1] = indices[indexStart + j + 1] - vertexStart + firstVertex;
  111. destIndexData[firstIndex + j + 2] = indices[indexStart + j + 2] - vertexStart + firstVertex;
  112. }
  113. }
  114. // 32-bit indices
  115. else
  116. {
  117. const unsigned* indices = (const unsigned*)indexData;
  118. for (unsigned j = 0; j < indexCount; j += 3)
  119. {
  120. // Rebase the indices according to our vertex numbering
  121. destIndexData[firstIndex + j] = indices[indexStart + j] - vertexStart + firstVertex;
  122. destIndexData[firstIndex + j + 1] = indices[indexStart + j + 1] - vertexStart + firstVertex;
  123. destIndexData[firstIndex + j + 2] = indices[indexStart + j + 2] - vertexStart + firstVertex;
  124. }
  125. }
  126. firstVertex += vertexCount;
  127. firstIndex += indexCount;
  128. geom->UnlockRawData();
  129. }
  130. }
  131. TriangleMeshData::TriangleMeshData(Model* model, bool makeConvexHull, float thickness, unsigned lodLevel, const Vector3& scale) :
  132. triMesh_(0)
  133. {
  134. modelName_ = model->GetName();
  135. unsigned vertexCount;
  136. unsigned indexCount;
  137. if (!makeConvexHull)
  138. GetVertexAndIndexData(model, lodLevel, vertexData_, vertexCount, indexData_, indexCount, scale);
  139. else
  140. {
  141. SharedArrayPtr<Vector3> originalVertices;
  142. SharedArrayPtr<unsigned> originalIndices;
  143. unsigned originalVertexCount;
  144. unsigned originalIndexCount;
  145. GetVertexAndIndexData(model, lodLevel, originalVertices, originalVertexCount, originalIndices, originalIndexCount, scale);
  146. // Build the convex hull from the raw geometry
  147. StanHull::HullDesc desc;
  148. desc.SetHullFlag(StanHull::QF_TRIANGLES);
  149. desc.mVcount = originalVertexCount;
  150. desc.mVertices = (float*)originalVertices.GetPtr();
  151. desc.mVertexStride = 3 * sizeof(float);
  152. desc.mSkinWidth = thickness;
  153. StanHull::HullLibrary lib;
  154. StanHull::HullResult result;
  155. lib.CreateConvexHull(desc, result);
  156. vertexCount = result.mNumOutputVertices;
  157. indexCount = result.mNumIndices;
  158. // Copy vertex data
  159. vertexData_ = new Vector3[vertexCount];
  160. memcpy(vertexData_.GetPtr(), result.mOutputVertices, vertexCount * sizeof(Vector3));
  161. // Copy index data
  162. indexData_ = new unsigned[indexCount];
  163. memcpy(indexData_.GetPtr(), result.mIndices, indexCount * sizeof(unsigned));
  164. lib.ReleaseResult(result);
  165. }
  166. triMesh_ = dGeomTriMeshDataCreate();
  167. dGeomTriMeshDataBuildSingle(triMesh_, vertexData_.GetPtr(), sizeof(Vector3), vertexCount,
  168. indexData_.GetPtr(), indexCount, 3 * sizeof(unsigned));
  169. }
  170. TriangleMeshData::~TriangleMeshData()
  171. {
  172. if (triMesh_)
  173. {
  174. dGeomTriMeshDataDestroy(triMesh_);
  175. triMesh_ = 0;
  176. }
  177. }
  178. HeightfieldData::HeightfieldData(Model* model, IntVector2 numPoints, float thickness, unsigned lodLevel,
  179. const Vector3& scale) :
  180. heightfield_(0)
  181. {
  182. modelName_ = model->GetName();
  183. const std::vector<std::vector<SharedPtr<Geometry> > >& geometries = model->GetGeometries();
  184. if (!geometries.size())
  185. return;
  186. lodLevel = Clamp(lodLevel, 0, geometries[0].size());
  187. Geometry* geom = geometries[0][lodLevel];
  188. if (!geom)
  189. return;
  190. const unsigned char* vertexData;
  191. const unsigned char* indexData;
  192. unsigned vertexSize;
  193. unsigned indexSize;
  194. geom->LockRawData(vertexData, vertexSize, indexData, indexSize);
  195. if ((!vertexData) || (!indexData))
  196. return;
  197. unsigned indexStart = geom->GetIndexStart();
  198. unsigned indexCount = geom->GetIndexCount();
  199. // If X & Z size not specified, try to guess them
  200. if (numPoints == IntVector2::ZERO)
  201. numPoints.x_ = numPoints.y_ = (int)sqrtf((float)geom->GetVertexCount());
  202. unsigned dataSize = numPoints.x_ * numPoints.y_;
  203. // Then allocate the heightfield
  204. BoundingBox box = model->GetBoundingBox();
  205. heightData_ = new float[dataSize];
  206. // Calculate spacing from model's bounding box
  207. float xSpacing = (box.max_.x_ - box.min_.x_) / (numPoints.x_ - 1);
  208. float zSpacing = (box.max_.z_ - box.min_.z_) / (numPoints.y_ - 1);
  209. // Initialize the heightfield with minimum height
  210. for (unsigned i = 0; i < dataSize; ++i)
  211. heightData_[i] = box.min_.y_ * scale.y_;
  212. unsigned vertexStart = geom->GetVertexStart();
  213. unsigned vertexCount = geom->GetVertexCount();
  214. // Now go through vertex data and fit the vertices into the heightfield
  215. for (unsigned i = vertexStart; i < vertexStart + vertexCount; ++i)
  216. {
  217. const Vector3& vertex = *((const Vector3*)(&vertexData[i * vertexSize]));
  218. int x = (int)((vertex.x_ - box.min_.x_) / xSpacing + 0.25f);
  219. int z = (int)((vertex.z_ - box.min_.z_) / zSpacing + 0.25f);
  220. if (x >= numPoints.x_)
  221. x = numPoints.x_ - 1;
  222. if (z >= numPoints.y_)
  223. z = numPoints.y_ - 1;
  224. if (vertex.y_ > heightData_[z * numPoints.x_ + x])
  225. heightData_[z * numPoints.x_ + x] = vertex.y_ * scale.y_;
  226. }
  227. geom->UnlockRawData();
  228. heightfield_ = dGeomHeightfieldDataCreate();
  229. dGeomHeightfieldDataBuildSingle(heightfield_, heightData_.GetPtr(), 0, (box.max_.x_ - box.min_.x_) * scale.x_,
  230. (box.max_.z_ - box.min_.z_) * scale.z_, numPoints.x_, numPoints.y_, 1.0f, 0.0f, thickness, 0);
  231. dGeomHeightfieldDataSetBounds(heightfield_, box.min_.y_ * scale.y_, box.max_.y_ * scale.y_);
  232. }
  233. HeightfieldData::~HeightfieldData()
  234. {
  235. if (heightfield_)
  236. {
  237. dGeomHeightfieldDataDestroy(heightfield_);
  238. heightfield_ = 0;
  239. }
  240. }
  241. OBJECTTYPESTATIC(CollisionShape);
  242. CollisionShape::CollisionShape(Context* context) :
  243. Component(context),
  244. geometry_(0),
  245. shapeType_(SHAPE_NONE),
  246. size_(Vector3::ZERO),
  247. thickness_(0.0f),
  248. lodLevel_(M_MAX_UNSIGNED),
  249. position_(Vector3::ZERO),
  250. rotation_(Quaternion::IDENTITY),
  251. geometryScale_(Vector3::UNITY),
  252. collisionGroup_(M_MAX_UNSIGNED),
  253. collisionMask_(M_MAX_UNSIGNED),
  254. friction_(DEFAULT_FRICTION),
  255. bounce_(DEFAULT_BOUNCE)
  256. {
  257. }
  258. CollisionShape::~CollisionShape()
  259. {
  260. Clear();
  261. }
  262. void CollisionShape::RegisterObject(Context* context)
  263. {
  264. context->RegisterFactory<CollisionShape>();
  265. ENUM_ATTRIBUTE(CollisionShape, "Shape Type", shapeType_, typeNames, SHAPE_NONE);
  266. ATTRIBUTE(CollisionShape, VAR_VECTOR3, "Size", size_, Vector3::ZERO);
  267. ATTRIBUTE(CollisionShape, VAR_FLOAT, "Hull Thickness", thickness_, 0.0f);
  268. ATTRIBUTE(CollisionShape, VAR_INT, "Model LOD Level", lodLevel_, M_MAX_UNSIGNED);
  269. ATTRIBUTE(CollisionShape, VAR_VECTOR3, "Offset Position", position_, Vector3::ZERO);
  270. ATTRIBUTE(CollisionShape, VAR_QUATERNION, "Rotation", rotation_, Quaternion::IDENTITY);
  271. ATTRIBUTE(CollisionShape, VAR_INT, "Collision Group", collisionGroup_, M_MAX_UNSIGNED);
  272. ATTRIBUTE(CollisionShape, VAR_INT, "Collision Mask", collisionMask_, M_MAX_UNSIGNED);
  273. ATTRIBUTE(CollisionShape, VAR_FLOAT, "Friction", friction_, DEFAULT_FRICTION);
  274. ATTRIBUTE(CollisionShape, VAR_FLOAT, "Bounce", bounce_, DEFAULT_BOUNCE);
  275. ATTRIBUTE(CollisionShape, VAR_RESOURCEREF, "Model", model_, ResourceRef(Model::GetTypeStatic()));
  276. }
  277. void CollisionShape::OnSetAttribute(const AttributeInfo& attr, const Variant& value)
  278. {
  279. ResourceCache* cache = GetSubsystem<ResourceCache>();
  280. switch (attr.offset_)
  281. {
  282. case offsetof(CollisionShape, model_):
  283. model_ = cache->GetResource<Model>(value.GetResourceRef().id_);
  284. break;
  285. default:
  286. Serializable::OnSetAttribute(attr, value);
  287. break;
  288. }
  289. }
  290. Variant CollisionShape::OnGetAttribute(const AttributeInfo& attr)
  291. {
  292. switch (attr.offset_)
  293. {
  294. case offsetof(CollisionShape, model_):
  295. return GetResourceRef(model_, Model::GetTypeStatic());
  296. default:
  297. return Serializable::OnGetAttribute(attr);
  298. }
  299. }
  300. void CollisionShape::PostLoad()
  301. {
  302. CreateGeometry();
  303. }
  304. void CollisionShape::Clear()
  305. {
  306. ReleaseGeometry();
  307. shapeType_ = SHAPE_NONE;
  308. }
  309. void CollisionShape::SetSphere(float radius, const Vector3& position, const Quaternion& rotation)
  310. {
  311. ReleaseGeometry();
  312. shapeType_ = SHAPE_SPHERE;
  313. size_ = Vector3(radius, radius, radius);
  314. position_ = position;
  315. rotation_ = rotation;
  316. CreateGeometry();
  317. }
  318. void CollisionShape::SetBox(const Vector3& size, const Vector3& position, const Quaternion& rotation)
  319. {
  320. ReleaseGeometry();
  321. shapeType_ = SHAPE_BOX;
  322. size_ = size;
  323. position_ = position;
  324. rotation_ = rotation;
  325. CreateGeometry();
  326. }
  327. void CollisionShape::SetCapsule(float radius, float height, const Vector3& position, const Quaternion& rotation)
  328. {
  329. ReleaseGeometry();
  330. shapeType_ = SHAPE_CAPSULE;
  331. size_ = Vector3(radius, radius, height);
  332. position_ = position;
  333. rotation_ = rotation;
  334. CreateGeometry();
  335. }
  336. void CollisionShape::SetCylinder(float radius, float height, const Vector3& position, const Quaternion& rotation)
  337. {
  338. ReleaseGeometry();
  339. shapeType_ = SHAPE_CYLINDER;
  340. size_ = Vector3(radius, radius, height);
  341. position_ = position;
  342. rotation_ = rotation;
  343. CreateGeometry();
  344. }
  345. void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& position, const Quaternion& rotation)
  346. {
  347. PROFILE(SetTriangleMeshShape);
  348. if (!model)
  349. {
  350. LOGERROR("Null model, can not set triangle mesh");
  351. return;
  352. }
  353. ReleaseGeometry();
  354. model_ = model;
  355. shapeType_ = SHAPE_TRIANGLEMESH;
  356. lodLevel_ = lodLevel;
  357. size_ = model->GetBoundingBox().GetSize();
  358. position_ = position;
  359. rotation_ = rotation;
  360. CreateGeometry();
  361. }
  362. void CollisionShape::SetHeightfield(Model* model, const IntVector2& numPoints, float thickness, unsigned lodLevel, const Vector3& position, const Quaternion& rotation)
  363. {
  364. PROFILE(SetHeightFieldShape);
  365. if (!model)
  366. {
  367. LOGERROR("Null model, can not set heightfield");
  368. return;
  369. }
  370. ReleaseGeometry();
  371. model_ = model;
  372. shapeType_ = SHAPE_HEIGHTFIELD;
  373. numPoints_ = numPoints;
  374. thickness_ = thickness;
  375. lodLevel_ = lodLevel;
  376. position_ = position;
  377. rotation_ = rotation;
  378. size_ = model->GetBoundingBox().GetSize();
  379. CreateGeometry();
  380. }
  381. void CollisionShape::SetConvexHull(Model* model, float thickness, unsigned lodLevel, const Vector3& position, const Quaternion& rotation)
  382. {
  383. PROFILE(SetConvexHullShape);
  384. if (!model)
  385. {
  386. LOGERROR("Null model, can not set convex hull");
  387. return;
  388. }
  389. ReleaseGeometry();
  390. model_ = model;
  391. shapeType_ = SHAPE_CONVEXHULL;
  392. thickness_ = thickness;
  393. lodLevel_ = lodLevel;
  394. size_ = model->GetBoundingBox().GetSize();
  395. position_ = position;
  396. rotation_ = rotation;
  397. CreateGeometry();
  398. }
  399. void CollisionShape::SetPosition(const Vector3& position)
  400. {
  401. position_ = position;
  402. UpdateTransform();
  403. }
  404. void CollisionShape::SetRotation(const Quaternion& rotation)
  405. {
  406. rotation_ = rotation;
  407. UpdateTransform();
  408. }
  409. void CollisionShape::SetTransform(const Vector3& position, const Quaternion& rotation)
  410. {
  411. position_ = position;
  412. rotation_ = rotation;
  413. UpdateTransform();
  414. }
  415. void CollisionShape::SetCollisionGroup(unsigned group)
  416. {
  417. collisionGroup_ = group;
  418. if (geometry_)
  419. dGeomSetCategoryBits(geometry_, group);
  420. }
  421. void CollisionShape::SetCollisionMask(unsigned mask)
  422. {
  423. collisionMask_ = mask;
  424. if (geometry_)
  425. dGeomSetCollideBits(geometry_, mask);
  426. }
  427. void CollisionShape::SetFriction(float friction)
  428. {
  429. friction_ = Max(friction, 0.0f);
  430. }
  431. void CollisionShape::SetBounce(float bounce)
  432. {
  433. bounce_ = Max(bounce, 0.0f);
  434. }
  435. void CollisionShape::UpdateTransform()
  436. {
  437. if (!geometry_)
  438. return;
  439. // Get the ODE body ID from the RigidBody component, if it exists
  440. dBodyID body = 0;
  441. RigidBody* rigidBody = GetComponent<RigidBody>();
  442. if (rigidBody)
  443. body = rigidBody->GetBody();
  444. // If body already assigned, need to do nothing
  445. if (body)
  446. {
  447. if (dGeomGetBody(geometry_) == body)
  448. return;
  449. // Assign the body, then set offset transform if necessary
  450. dGeomSetBody(geometry_, body);
  451. if ((position_ != Vector3::ZERO) || (rotation_ != Quaternion::IDENTITY))
  452. {
  453. Vector3 offset = geometryScale_ * position_;
  454. dGeomSetOffsetPosition(geometry_, offset.x_, offset.y_, offset.z_);
  455. dGeomSetOffsetQuaternion(geometry_, rotation_.GetData());
  456. }
  457. }
  458. else
  459. {
  460. // No rigid body. Must update the geometry transform manually
  461. Vector3 nodePos = GetWorldPosition();
  462. Quaternion nodeRot = GetWorldRotation();
  463. Vector3 geoposition_ = nodePos + (nodeRot * (geometryScale_ * position_));
  464. Quaternion geomRot = nodeRot * rotation_;
  465. dGeomSetPosition(geometry_, geoposition_.x_, geoposition_.y_, geoposition_.z_);
  466. dGeomSetQuaternion(geometry_, geomRot.GetData());
  467. }
  468. }
  469. void CollisionShape::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  470. {
  471. if (!geometry_)
  472. return;
  473. Color color(0.0f, 1.0f, 0.0f);
  474. RigidBody* rigidBody = GetComponent<RigidBody>();
  475. if ((rigidBody) && (rigidBody->IsActive()))
  476. color = Color(1.0f, 1.0f, 1.0f);
  477. // Drawing all the debug geometries of a large world may be expensive (especially triangle meshes)
  478. // so check the geometry AABB against the debug geometry frustum first
  479. float aabb[6];
  480. dGeomGetAABB(geometry_, aabb);
  481. BoundingBox box;
  482. box.min_.x_ = aabb[0];
  483. box.max_.x_ = aabb[1];
  484. box.min_.y_ = aabb[2];
  485. box.max_.y_ = aabb[3];
  486. box.min_.z_ = aabb[4];
  487. box.max_.z_ = aabb[5];
  488. if (!debug->IsInside(box))
  489. return;
  490. const dReal* pos = dGeomGetPosition(geometry_);
  491. dQuaternion quat;
  492. dGeomGetQuaternion(geometry_, quat);
  493. Matrix4x3 transform(Vector3(pos[0], pos[1], pos[2]), Quaternion(quat[0], quat[1], quat[2], quat[3]), 1.0f);
  494. switch (dGeomGetClass(geometry_))
  495. {
  496. case dSphereClass:
  497. {
  498. float radius = dGeomSphereGetRadius(geometry_);
  499. for (unsigned i = 0; i < 360; i += 45)
  500. {
  501. unsigned j = i + 45;
  502. float a = radius * sinf(i * M_DEGTORAD);
  503. float b = radius * cosf(i * M_DEGTORAD);
  504. float c = radius * sinf(j * M_DEGTORAD);
  505. float d = radius * cosf(j * M_DEGTORAD);
  506. Vector3 start, end;
  507. start = transform * Vector3(a, b, 0.0f);
  508. end = transform * Vector3(c, d, 0.0f);
  509. debug->AddLine(start, end, color, depthTest);
  510. start = transform * Vector3(a, 0.0f, b);
  511. end = transform * Vector3(c, 0.0f, d);
  512. debug->AddLine(start, end, color, depthTest);
  513. start = transform * Vector3(0.0f, a, b);
  514. end = transform * Vector3(0.0f, c, d);
  515. debug->AddLine(start, end, color, depthTest);
  516. }
  517. }
  518. break;
  519. case dBoxClass:
  520. {
  521. dVector3 size;
  522. dGeomBoxGetLengths(geometry_, size);
  523. BoundingBox box(0.5f * Vector3(size[0], size[1], size[2]), 0.5f * Vector3(-size[0], -size[1], -size[2]));
  524. debug->AddBoundingBox(box, transform, color, depthTest);
  525. }
  526. break;
  527. case dCapsuleClass:
  528. {
  529. float radius, length;
  530. dGeomCapsuleGetParams(geometry_, &radius, &length);
  531. for (unsigned i = 0; i < 360; i += 45)
  532. {
  533. unsigned j = i + 45;
  534. float a = radius * sinf(i * M_DEGTORAD);
  535. float b = radius * cosf(i * M_DEGTORAD);
  536. float c = radius * sinf(j * M_DEGTORAD);
  537. float d = radius * cosf(j * M_DEGTORAD);
  538. Vector3 start, end;
  539. start = transform * Vector3(a, b, 0.5f * length);
  540. end = transform * Vector3(c, d, 0.5f * length);
  541. debug->AddLine(start, end, color, depthTest);
  542. start = transform * Vector3(a, b, -0.5f * length);
  543. end = transform * Vector3(c, d, -0.5f * length);
  544. debug->AddLine(start, end, color, depthTest);
  545. if (!(i & 1))
  546. {
  547. start = transform * Vector3(a, b, 0.5f * length);
  548. end = transform * Vector3(a, b, -0.5f * length);
  549. debug->AddLine(start, end, color, depthTest);
  550. }
  551. if (b > -M_EPSILON)
  552. {
  553. start = transform * Vector3(a, 0.0f, b + 0.5f * length);
  554. end = transform * Vector3(c, 0.0f, d + 0.5f * length);
  555. debug->AddLine(start, end, color, depthTest);
  556. start = transform * Vector3(0.0f, a, b + 0.5f * length);
  557. end = transform * Vector3(0.0f, c, d + 0.5f * length);
  558. debug->AddLine(start, end, color, depthTest);
  559. start = transform * Vector3(a, 0.0f, -b - 0.5f * length);
  560. end = transform * Vector3(c, 0.0f, -d - 0.5f * length);
  561. debug->AddLine(start, end, color, depthTest);
  562. start = transform * Vector3(0.0f, a, -b - 0.5f * length);
  563. end = transform * Vector3(0.0f, c, -d - 0.5f * length);
  564. debug->AddLine(start, end, color, depthTest);
  565. }
  566. }
  567. }
  568. break;
  569. case dCylinderClass:
  570. {
  571. float radius, length;
  572. dGeomCylinderGetParams(geometry_, &radius, &length);
  573. for (unsigned i = 0; i < 360; i += 45)
  574. {
  575. unsigned j = i + 45;
  576. float a = radius * sinf(i * M_DEGTORAD);
  577. float b = radius * cosf(i * M_DEGTORAD);
  578. float c = radius * sinf(j * M_DEGTORAD);
  579. float d = radius * cosf(j * M_DEGTORAD);
  580. Vector3 start, end;
  581. start = transform * Vector3(a, b, 0.5f * length);
  582. end = transform * Vector3(c, d, 0.5f * length);
  583. debug->AddLine(start, end, color, depthTest);
  584. start = transform * Vector3(a, b, -0.5f * length);
  585. end = transform * Vector3(c, d, -0.5f * length);
  586. debug->AddLine(start, end, color, depthTest);
  587. start = transform * Vector3(a, b, 0.5f * length);
  588. end = transform * Vector3(a, b, -0.5f * length);
  589. debug->AddLine(start, end, color, depthTest);
  590. }
  591. }
  592. break;
  593. case dTriMeshClass:
  594. {
  595. unsigned numTriangles = dGeomTriMeshGetTriangleCount(geometry_);
  596. for (unsigned i = 0; i < numTriangles; ++i)
  597. {
  598. dVector3 v0;
  599. dVector3 v1;
  600. dVector3 v2;
  601. dGeomTriMeshGetTriangle(geometry_, i, &v0, &v1, &v2);
  602. Vector3 a(v0[0], v0[1], v0[2]);
  603. Vector3 b(v1[0], v1[1], v1[2]);
  604. Vector3 c(v2[0], v2[1], v2[2]);
  605. debug->AddLine(a, b, color, depthTest);
  606. debug->AddLine(b, c, color, depthTest);
  607. debug->AddLine(c, a, color, depthTest);
  608. }
  609. }
  610. break;
  611. case dHeightfieldClass:
  612. {
  613. dHeightfieldDataID heightData = dGeomHeightfieldGetHeightfieldData(geometry_);
  614. unsigned xPoints = heightData->m_nWidthSamples;
  615. unsigned zPoints = heightData->m_nDepthSamples;
  616. float xWidth = heightData->m_fWidth;
  617. float zWidth = heightData->m_fDepth;
  618. float xBase = -0.5f * xWidth;
  619. float zBase = -0.5f * zWidth;
  620. float xSpacing = xWidth / (xPoints - 1);
  621. float zSpacing = zWidth / (zPoints - 1);
  622. float* heights = (float*)heightData->m_pHeightData;
  623. for (unsigned z = 0; z < zPoints - 1; ++z)
  624. {
  625. for (unsigned x = 0; x < xPoints - 1; ++x)
  626. {
  627. Vector3 a = transform * Vector3(xBase + x * xSpacing, heights[z * xPoints + x], zBase + z * zSpacing);
  628. Vector3 b = transform * Vector3(xBase + (x + 1) * xSpacing, heights[z * xPoints + x + 1], zBase + z * zSpacing);
  629. Vector3 c = transform * Vector3(xBase + x * xSpacing, heights[(z + 1) * xPoints + x], zBase + (z + 1) * zSpacing);
  630. debug->AddLine(a, b, color, depthTest);
  631. debug->AddLine(a, c, color, depthTest);
  632. }
  633. }
  634. for (unsigned z = 0; z < zPoints - 1; ++z)
  635. {
  636. unsigned x = xPoints - 1;
  637. Vector3 a = transform * Vector3(xBase + x * xSpacing, heights[z * xPoints + x], zBase + z * zSpacing);
  638. Vector3 b = transform * Vector3(xBase + x * xSpacing, heights[(z + 1) * xPoints + x], zBase + (z + 1) * zSpacing);
  639. debug->AddLine(a, b, color, depthTest);
  640. }
  641. for (unsigned x = 0; x < xPoints - 1; ++x)
  642. {
  643. unsigned z = zPoints - 1;
  644. Vector3 a = transform * Vector3(xBase + x * xSpacing, heights[z * xPoints + x], zBase + z * zSpacing);
  645. Vector3 b = transform * Vector3(xBase + (x + 1) * xSpacing, heights[z * xPoints + x + 1], zBase + z * zSpacing);
  646. debug->AddLine(a, b, color, depthTest);
  647. }
  648. }
  649. break;
  650. }
  651. }
  652. void CollisionShape::OnMarkedDirty(Node* node)
  653. {
  654. // If scale has changed, must recreate the geometry
  655. if (GetWorldScale() != geometryScale_)
  656. CreateGeometry();
  657. else
  658. UpdateTransform();
  659. }
  660. void CollisionShape::OnNodeSet(Node* node)
  661. {
  662. if (node)
  663. {
  664. Scene* scene = node->GetScene();
  665. if (scene)
  666. physicsWorld_ = scene->GetComponent<PhysicsWorld>();
  667. node->AddListener(this);
  668. }
  669. }
  670. void CollisionShape::CreateGeometry()
  671. {
  672. PROFILE(CreateCollisionShape);
  673. if (!physicsWorld_)
  674. {
  675. LOGERROR("Null physics world, can not create collision shape");
  676. return;
  677. }
  678. // Destroy previous geometry if exists
  679. if (geometry_)
  680. {
  681. dGeomDestroy(geometry_);
  682. geometry_ = 0;
  683. }
  684. geometryScale_ = GetWorldScale();
  685. Vector3 size = size_ * geometryScale_;
  686. dSpaceID space = physicsWorld_->GetSpace();
  687. switch (shapeType_)
  688. {
  689. case SHAPE_BOX:
  690. geometry_ = dCreateBox(space, size.x_, size.y_, size.z_);
  691. break;
  692. case SHAPE_SPHERE:
  693. geometry_ = dCreateSphere(space, size.x_);
  694. break;
  695. case SHAPE_CAPSULE:
  696. geometry_ = dCreateCapsule(space, size.x_, size.z_);
  697. break;
  698. case SHAPE_CYLINDER:
  699. geometry_ = dCreateCylinder(space, size.x_, size.z_);
  700. break;
  701. case SHAPE_TRIANGLEMESH:
  702. case SHAPE_CONVEXHULL:
  703. {
  704. // Check the geometry cache
  705. std::string id = model_->GetName() + "_" + ToString(geometryScale_) + "_" + ToString(lodLevel_);
  706. if (shapeType_ == SHAPE_CONVEXHULL)
  707. id += "_" + ToString(thickness_);
  708. std::map<std::string, SharedPtr<TriangleMeshData> >& cache = physicsWorld_->GetTriangleMeshCache();
  709. std::map<std::string, SharedPtr<TriangleMeshData> >::iterator j = cache.find(id);
  710. if (j != cache.end())
  711. {
  712. geometry_ = dCreateTriMesh(space, j->second->triMesh_, 0, 0, 0);
  713. geometryData_ = StaticCast<CollisionGeometryData>(j->second);
  714. }
  715. else
  716. {
  717. SharedPtr<TriangleMeshData> newData(new TriangleMeshData(model_, shapeType_ == SHAPE_CONVEXHULL, thickness_,
  718. lodLevel_, geometryScale_));
  719. cache[id] = newData;
  720. geometry_ = dCreateTriMesh(space, newData->triMesh_, 0, 0, 0);
  721. geometryData_ = StaticCast<CollisionGeometryData>(newData);
  722. }
  723. }
  724. break;
  725. case SHAPE_HEIGHTFIELD:
  726. {
  727. // Check the geometry cache
  728. std::string id = model_->GetName() + "_" + ToString(numPoints_) + "_" + ToString(thickness_) + "_" + ToString(lodLevel_);
  729. std::map<std::string, SharedPtr<HeightfieldData> >& cache = physicsWorld_->GetHeightfieldCache();
  730. std::map<std::string, SharedPtr<HeightfieldData> >::iterator j = cache.find(id);
  731. if (j != cache.end())
  732. {
  733. geometry_ = dCreateHeightfield(space, j->second->heightfield_, 1);
  734. geometryData_ = StaticCast<CollisionGeometryData>(j->second);
  735. }
  736. else
  737. {
  738. SharedPtr<HeightfieldData> newData(new HeightfieldData(model_, numPoints_, thickness_, lodLevel_, geometryScale_));
  739. cache[id] = newData;
  740. geometry_ = dCreateHeightfield(space, newData->heightfield_, 1);
  741. geometryData_ = StaticCast<CollisionGeometryData>(newData);
  742. }
  743. }
  744. break;
  745. }
  746. // Set collision group and mask & userdata
  747. if (geometry_)
  748. {
  749. dGeomSetCategoryBits(geometry_, collisionGroup_);
  750. dGeomSetCollideBits(geometry_, collisionMask_);
  751. dGeomSetData(geometry_, this);
  752. }
  753. UpdateTransform();
  754. // If rigid body component exists, let it recalculate its mass now
  755. RigidBody* rigidBody = GetComponent<RigidBody>();
  756. if (rigidBody)
  757. rigidBody->UpdateMass();
  758. }
  759. void CollisionShape::ReleaseGeometry(bool notifyBody)
  760. {
  761. if (geometry_)
  762. {
  763. dGeomDestroy(geometry_);
  764. geometry_ = 0;
  765. }
  766. model_.Reset();
  767. geometryData_.Reset();
  768. if (physicsWorld_)
  769. physicsWorld_->CleanupGeometryCache();
  770. // If rigid body component exists, let it recalculate its mass now
  771. if (notifyBody)
  772. {
  773. RigidBody* rigidBody = GetComponent<RigidBody>();
  774. if (rigidBody)
  775. rigidBody->UpdateMass();
  776. }
  777. }