collisionComponent.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "T3D/components/collision/collisionComponent.h"
  23. #include "T3D/components/collision/collisionComponent_ScriptBinding.h"
  24. #include "T3D/components/physics/physicsBehavior.h"
  25. #include "console/consoleTypes.h"
  26. #include "core/util/safeDelete.h"
  27. #include "core/resourceManager.h"
  28. #include "console/consoleTypes.h"
  29. #include "console/consoleObject.h"
  30. #include "core/stream/bitStream.h"
  31. #include "scene/sceneRenderState.h"
  32. #include "gfx/gfxTransformSaver.h"
  33. #include "gfx/gfxDrawUtil.h"
  34. #include "console/engineAPI.h"
  35. #include "T3D/physics/physicsPlugin.h"
  36. #include "T3D/physics/physicsBody.h"
  37. #include "T3D/physics/physicsCollision.h"
  38. #include "T3D/gameBase/gameConnection.h"
  39. #include "collision/extrudedPolyList.h"
  40. #include "math/mathIO.h"
  41. #include "gfx/sim/debugDraw.h"
  42. #include "collision/concretePolyList.h"
  43. #include "T3D/trigger.h"
  44. #include "opcode/Opcode.h"
  45. #include "opcode/Ice/IceAABB.h"
  46. #include "opcode/Ice/IcePoint.h"
  47. #include "opcode/OPC_AABBTree.h"
  48. #include "opcode/OPC_AABBCollider.h"
  49. #include "math/mathUtils.h"
  50. #include "materials/baseMatInstance.h"
  51. #include "collision/vertexPolyList.h"
  52. extern bool gEditingMission;
  53. static bool sRenderColliders = false;
  54. //Docs
  55. ConsoleDocClass(CollisionComponent,
  56. "@brief The Box Collider component uses a box or rectangular convex shape for collisions.\n\n"
  57. "Colliders are individualized components that are similarly based off the CollisionInterface core.\n"
  58. "They are basically the entire functionality of how Torque handles collisions compacted into a single component.\n"
  59. "A collider will both collide against and be collided with, other entities.\n"
  60. "Individual colliders will offer different shapes. This box collider will generate a box/rectangle convex, \n"
  61. "while the mesh collider will take the owner Entity's rendered shape and do polysoup collision on it, etc.\n\n"
  62. "The general flow of operations for how collisions happen is thus:\n"
  63. " -When the component is added(or updated) prepCollision() is called.\n"
  64. " This will set up our initial convex shape for usage later.\n\n"
  65. " -When we update via processTick(), we first test if our entity owner is mobile.\n"
  66. " If our owner isn't mobile(as in, they have no components that provide it a velocity to move)\n"
  67. " then we skip doing our active collision checks. Collisions are checked by the things moving, as\n"
  68. " opposed to being reactionary. If we're moving, we call updateWorkingCollisionSet().\n"
  69. " updateWorkingCollisionSet() estimates our bounding space for our current ticket based on our position and velocity.\n"
  70. " If our bounding space has changed since the last tick, we proceed to call updateWorkingList() on our convex.\n"
  71. " This notifies any object in the bounding space that they may be collided with, so they will call buildConvex().\n"
  72. " buildConvex() will set up our ConvexList with our collision convex info.\n\n"
  73. " -When the component that is actually causing our movement, such as SimplePhysicsBehavior, updates, it will check collisions.\n"
  74. " It will call checkCollisions() on us. checkCollisions() will first build a bounding shape for our convex, and test\n"
  75. " if we can early out because we won't hit anything based on our starting point, velocity, and tick time.\n"
  76. " If we don't early out, we proceed to call updateCollisions(). This builds an ExtrudePolyList, which is then extruded\n"
  77. " based on our velocity. We then test our extruded polies on our working list of objects we build\n"
  78. " up earlier via updateWorkingCollisionSet. Any collisions that happen here will be added to our mCollisionList.\n"
  79. " Finally, we call handleCollisionList() on our collisionList, which then queues out the colliison notice\n"
  80. " to the object(s) we collided with so they can do callbacks and the like. We also report back on if we did collide\n"
  81. " to the physics component via our bool return in checkCollisions() so it can make the physics react accordingly.\n\n"
  82. "One interesting point to note is the usage of mBlockColliding.\n"
  83. "This is set so that it dictates the return on checkCollisions(). If set to false, it will ensure checkCollisions()\n"
  84. "will return false, regardless if we actually collided. This is useful, because even if checkCollisions() returns false,\n"
  85. "we still handle the collisions so the callbacks happen. This enables us to apply a collider to an object that doesn't block\n"
  86. "objects, but does have callbacks, so it can act as a trigger, allowing for arbitrarily shaped triggers, as any collider can\n"
  87. "act as a trigger volume(including MeshCollider).\n\n"
  88. "@tsexample\n"
  89. "new CollisionComponentInstance()\n"
  90. "{\n"
  91. " template = CollisionComponentTemplate;\n"
  92. " colliderSize = \"1 1 2\";\n"
  93. " blockColldingObject = \"1\";\n"
  94. "};\n"
  95. "@endtsexample\n"
  96. "@see SimplePhysicsBehavior\n"
  97. "@ingroup Collision\n"
  98. "@ingroup Components\n"
  99. );
  100. //Docs
  101. /////////////////////////////////////////////////////////////////////////
  102. ImplementEnumType(CollisionMeshMeshType,
  103. "Type of mesh data available in a shape.\n"
  104. "@ingroup gameObjects")
  105. { CollisionComponent::None, "None", "No mesh data." },
  106. { CollisionComponent::Bounds, "Bounds", "Bounding box of the shape." },
  107. { CollisionComponent::CollisionMesh, "Collision Mesh", "Specifically desingated \"collision\" meshes." },
  108. { CollisionComponent::VisibleMesh, "Visible Mesh", "Rendered mesh polygons." },
  109. EndImplementEnumType;
  110. //
  111. CollisionComponent::CollisionComponent() : Component()
  112. {
  113. mNetFlags.set(Ghostable | ScopeAlways);
  114. mFriendlyName = "Collision(Component)";
  115. mOwnerRenderInterface = NULL;
  116. mOwnerPhysicsInterface = NULL;
  117. mBlockColliding = true;
  118. mCollisionType = CollisionMesh;
  119. mLOSType = CollisionMesh;
  120. mDecalType = CollisionMesh;
  121. colisionMeshPrefix = StringTable->insert("Collision");
  122. CollisionMoveMask = (TerrainObjectType | PlayerObjectType |
  123. StaticShapeObjectType | VehicleObjectType |
  124. VehicleBlockerObjectType | DynamicShapeObjectType | StaticObjectType | EntityObjectType | TriggerObjectType);
  125. mPhysicsRep = NULL;
  126. mPhysicsWorld = NULL;
  127. mTimeoutList = NULL;
  128. }
  129. CollisionComponent::~CollisionComponent()
  130. {
  131. for (S32 i = 0; i < mFields.size(); ++i)
  132. {
  133. ComponentField &field = mFields[i];
  134. SAFE_DELETE_ARRAY(field.mFieldDescription);
  135. }
  136. SAFE_DELETE_ARRAY(mDescription);
  137. }
  138. IMPLEMENT_CO_NETOBJECT_V1(CollisionComponent);
  139. void CollisionComponent::onComponentAdd()
  140. {
  141. Parent::onComponentAdd();
  142. RenderComponentInterface *renderInterface = mOwner->getComponent<RenderComponentInterface>();
  143. if (renderInterface)
  144. {
  145. renderInterface->onShapeInstanceChanged.notify(this, &CollisionComponent::targetShapeChanged);
  146. mOwnerRenderInterface = renderInterface;
  147. }
  148. //physicsInterface
  149. PhysicsComponentInterface *physicsInterface = mOwner->getComponent<PhysicsComponentInterface>();
  150. if (!physicsInterface)
  151. {
  152. mPhysicsRep = PHYSICSMGR->createBody();
  153. }
  154. prepCollision();
  155. }
  156. void CollisionComponent::onComponentRemove()
  157. {
  158. SAFE_DELETE(mPhysicsRep);
  159. Parent::onComponentRemove();
  160. }
  161. void CollisionComponent::componentAddedToOwner(Component *comp)
  162. {
  163. if (comp->getId() == getId())
  164. return;
  165. //test if this is a shape component!
  166. RenderComponentInterface *renderInterface = dynamic_cast<RenderComponentInterface*>(comp);
  167. if (renderInterface)
  168. {
  169. renderInterface->onShapeInstanceChanged.notify(this, &CollisionComponent::targetShapeChanged);
  170. mOwnerRenderInterface = renderInterface;
  171. prepCollision();
  172. }
  173. PhysicsComponentInterface *physicsInterface = dynamic_cast<PhysicsComponentInterface*>(comp);
  174. if (physicsInterface)
  175. {
  176. if (mPhysicsRep)
  177. SAFE_DELETE(mPhysicsRep);
  178. prepCollision();
  179. }
  180. }
  181. void CollisionComponent::componentRemovedFromOwner(Component *comp)
  182. {
  183. if (comp->getId() == getId()) //?????????
  184. return;
  185. //test if this is a shape component!
  186. RenderComponentInterface *renderInterface = dynamic_cast<RenderComponentInterface*>(comp);
  187. if (renderInterface)
  188. {
  189. renderInterface->onShapeInstanceChanged.remove(this, &CollisionComponent::targetShapeChanged);
  190. mOwnerRenderInterface = NULL;
  191. prepCollision();
  192. }
  193. //physicsInterface
  194. PhysicsComponentInterface *physicsInterface = dynamic_cast<PhysicsComponentInterface*>(comp);
  195. if (physicsInterface)
  196. {
  197. mPhysicsRep = PHYSICSMGR->createBody();
  198. prepCollision();
  199. }
  200. }
  201. void CollisionComponent::checkDependencies()
  202. {
  203. }
  204. void CollisionComponent::initPersistFields()
  205. {
  206. Parent::initPersistFields();
  207. addGroup("Collision");
  208. addField("CollisionType", TypeCollisionMeshMeshType, Offset(mCollisionType, CollisionComponent),
  209. "The type of mesh data to use for collision queries.");
  210. addField("LineOfSightType", TypeCollisionMeshMeshType, Offset(mLOSType, CollisionComponent),
  211. "The type of mesh data to use for collision queries.");
  212. addField("DecalType", TypeCollisionMeshMeshType, Offset(mDecalType, CollisionComponent),
  213. "The type of mesh data to use for collision queries.");
  214. addField("CollisionMeshPrefix", TypeString, Offset(colisionMeshPrefix, CollisionComponent),
  215. "The type of mesh data to use for collision queries.");
  216. addField("BlockCollisions", TypeBool, Offset(mBlockColliding, CollisionComponent), "");
  217. endGroup("Collision");
  218. }
  219. void CollisionComponent::inspectPostApply()
  220. {
  221. // Apply any transformations set in the editor
  222. Parent::inspectPostApply();
  223. if (isServerObject())
  224. {
  225. setMaskBits(ColliderMask);
  226. prepCollision();
  227. }
  228. }
  229. U32 CollisionComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
  230. {
  231. U32 retMask = Parent::packUpdate(con, mask, stream);
  232. if (stream->writeFlag(mask & (ColliderMask | InitialUpdateMask)))
  233. {
  234. stream->write((U32)mCollisionType);
  235. stream->writeString(colisionMeshPrefix);
  236. }
  237. return retMask;
  238. }
  239. void CollisionComponent::unpackUpdate(NetConnection *con, BitStream *stream)
  240. {
  241. Parent::unpackUpdate(con, stream);
  242. if (stream->readFlag()) // UpdateMask
  243. {
  244. U32 collisionType = CollisionMesh;
  245. stream->read(&collisionType);
  246. // Handle it if we have changed CollisionType's
  247. if ((MeshType)collisionType != mCollisionType)
  248. {
  249. mCollisionType = (MeshType)collisionType;
  250. prepCollision();
  251. }
  252. char readBuffer[1024];
  253. stream->readString(readBuffer);
  254. colisionMeshPrefix = StringTable->insert(readBuffer);
  255. }
  256. }
  257. void CollisionComponent::ownerTransformSet(MatrixF *mat)
  258. {
  259. if (mPhysicsRep)
  260. mPhysicsRep->setTransform(mOwner->getTransform());
  261. }
  262. void CollisionComponent::targetShapeChanged(RenderComponentInterface* instanceInterface)
  263. {
  264. prepCollision();
  265. }
  266. void CollisionComponent::prepCollision()
  267. {
  268. if (!mOwner)
  269. return;
  270. // Let the client know that the collision was updated
  271. setMaskBits(ColliderMask);
  272. mOwner->disableCollision();
  273. if ((!PHYSICSMGR || mCollisionType == None) ||
  274. (mOwnerRenderInterface == NULL && (mCollisionType == CollisionMesh || mCollisionType == VisibleMesh)))
  275. return;
  276. PhysicsCollision *colShape = NULL;
  277. if (mCollisionType == Bounds)
  278. {
  279. MatrixF offset(true);
  280. if (mOwnerRenderInterface && mOwnerRenderInterface->getShape())
  281. offset.setPosition(mOwnerRenderInterface->getShape()->center);
  282. colShape = PHYSICSMGR->createCollision();
  283. colShape->addBox(mOwner->getObjBox().getExtents() * 0.5f * mOwner->getScale(), offset);
  284. }
  285. else if (mCollisionType == CollisionMesh || (mCollisionType == VisibleMesh /*&& !mOwner->getComponent<AnimatedMesh>()*/))
  286. {
  287. colShape = buildColShapes();
  288. }
  289. if (colShape)
  290. {
  291. mPhysicsWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client");
  292. if (mPhysicsRep)
  293. {
  294. if (mBlockColliding)
  295. mPhysicsRep->init(colShape, 0, 0, mOwner, mPhysicsWorld);
  296. else
  297. mPhysicsRep->init(colShape, 0, PhysicsBody::BF_TRIGGER, mOwner, mPhysicsWorld);
  298. mPhysicsRep->setTransform(mOwner->getTransform());
  299. }
  300. }
  301. mOwner->enableCollision();
  302. onCollisionChanged.trigger(colShape);
  303. }
  304. void CollisionComponent::processTick()
  305. {
  306. if (!isActive())
  307. return;
  308. //ProcessTick is where our collision testing begins!
  309. //callback if we have a persisting contact
  310. if (mContactInfo.contactObject)
  311. {
  312. if (mContactInfo.contactTimer > 0)
  313. {
  314. if (isMethod("updateContact"))
  315. Con::executef(this, "updateContact");
  316. if (mOwner->isMethod("updateContact"))
  317. Con::executef(mOwner, "updateContact");
  318. }
  319. ++mContactInfo.contactTimer;
  320. }
  321. else if (mContactInfo.contactTimer != 0)
  322. mContactInfo.clear();
  323. }
  324. void CollisionComponent::updatePhysics()
  325. {
  326. }
  327. PhysicsCollision* CollisionComponent::getCollisionData()
  328. {
  329. if ((!PHYSICSMGR || mCollisionType == None) || mOwnerRenderInterface == NULL)
  330. return NULL;
  331. PhysicsCollision *colShape = NULL;
  332. if (mCollisionType == Bounds)
  333. {
  334. MatrixF offset(true);
  335. offset.setPosition(mOwnerRenderInterface->getShape()->center);
  336. colShape = PHYSICSMGR->createCollision();
  337. colShape->addBox(mOwner->getObjBox().getExtents() * 0.5f * mOwner->getScale(), offset);
  338. }
  339. else if (mCollisionType == CollisionMesh || (mCollisionType == VisibleMesh/* && !mOwner->getComponent<AnimatedMesh>()*/))
  340. {
  341. colShape = buildColShapes();
  342. //colShape = mOwnerShapeInstance->getShape()->buildColShape(mCollisionType == VisibleMesh, mOwner->getScale());
  343. }
  344. /*else if (mCollisionType == VisibleMesh && !mOwner->getComponent<AnimatedMesh>())
  345. {
  346. //We don't have support for visible mesh collisions with animated meshes currently in the physics abstraction layer
  347. //so we don't generate anything if we're set to use a visible mesh but have an animated mesh component.
  348. colShape = mOwnerShapeInstance->getShape()->buildColShape(mCollisionType == VisibleMesh, mOwner->getScale());
  349. }*/
  350. else if (mCollisionType == VisibleMesh/* && mOwner->getComponent<AnimatedMesh>()*/)
  351. {
  352. Con::printf("CollisionComponent::updatePhysics: Cannot use visible mesh collisions with an animated mesh!");
  353. }
  354. return colShape;
  355. }
  356. bool CollisionComponent::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
  357. {
  358. if (!mCollisionType == None)
  359. {
  360. if (mPhysicsWorld)
  361. {
  362. return mPhysicsWorld->castRay(start, end, info, Point3F::Zero);
  363. }
  364. }
  365. return false;
  366. }
  367. PhysicsCollision* CollisionComponent::buildColShapes()
  368. {
  369. PROFILE_SCOPE(CollisionComponent_buildColShapes);
  370. PhysicsCollision *colShape = NULL;
  371. U32 surfaceKey = 0;
  372. TSShape* shape = mOwnerRenderInterface->getShape();
  373. if (mCollisionType == VisibleMesh)
  374. {
  375. // Here we build triangle collision meshes from the
  376. // visible detail levels.
  377. // A negative subshape on the detail means we don't have geometry.
  378. const TSShape::Detail &detail = shape->details[0];
  379. if (detail.subShapeNum < 0)
  380. return NULL;
  381. // We don't try to optimize the triangles we're given
  382. // and assume the art was created properly for collision.
  383. ConcretePolyList polyList;
  384. polyList.setTransform(&MatrixF::Identity, mOwner->getScale());
  385. // Create the collision meshes.
  386. S32 start = shape->subShapeFirstObject[detail.subShapeNum];
  387. S32 end = start + shape->subShapeNumObjects[detail.subShapeNum];
  388. for (S32 o = start; o < end; o++)
  389. {
  390. const TSShape::Object &object = shape->objects[o];
  391. if (detail.objectDetailNum >= object.numMeshes)
  392. continue;
  393. // No mesh or no verts.... nothing to do.
  394. TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum];
  395. if (!mesh || mesh->mNumVerts == 0)
  396. continue;
  397. // Gather the mesh triangles.
  398. polyList.clear();
  399. mesh->buildPolyList(0, &polyList, surfaceKey, NULL);
  400. // Create the collision shape if we haven't already.
  401. if (!colShape)
  402. colShape = PHYSICSMGR->createCollision();
  403. // Get the object space mesh transform.
  404. MatrixF localXfm;
  405. shape->getNodeWorldTransform(object.nodeIndex, &localXfm);
  406. colShape->addTriangleMesh(polyList.mVertexList.address(),
  407. polyList.mVertexList.size(),
  408. polyList.mIndexList.address(),
  409. polyList.mIndexList.size() / 3,
  410. localXfm);
  411. }
  412. // Return what we built... if anything.
  413. return colShape;
  414. }
  415. else if (mCollisionType == CollisionMesh)
  416. {
  417. // Scan out the collision hulls...
  418. //
  419. // TODO: We need to support LOS collision for physics.
  420. //
  421. for (U32 i = 0; i < shape->details.size(); i++)
  422. {
  423. const TSShape::Detail &detail = shape->details[i];
  424. const String &name = shape->names[detail.nameIndex];
  425. // Is this a valid collision detail.
  426. if (!dStrStartsWith(name, colisionMeshPrefix) || detail.subShapeNum < 0)
  427. continue;
  428. // Now go thru the meshes for this detail.
  429. S32 start = shape->subShapeFirstObject[detail.subShapeNum];
  430. S32 end = start + shape->subShapeNumObjects[detail.subShapeNum];
  431. if (start >= end)
  432. continue;
  433. for (S32 o = start; o < end; o++)
  434. {
  435. const TSShape::Object &object = shape->objects[o];
  436. const String &meshName = shape->names[object.nameIndex];
  437. if (object.numMeshes <= detail.objectDetailNum)
  438. continue;
  439. // No mesh, a flat bounds, or no verts.... nothing to do.
  440. TSMesh *mesh = shape->meshes[object.startMeshIndex + detail.objectDetailNum];
  441. if (!mesh || mesh->getBounds().isEmpty() || mesh->mNumVerts == 0)
  442. continue;
  443. // We need the default mesh transform.
  444. MatrixF localXfm;
  445. shape->getNodeWorldTransform(object.nodeIndex, &localXfm);
  446. // We have some sort of collision shape... so allocate it.
  447. if (!colShape)
  448. colShape = PHYSICSMGR->createCollision();
  449. // Any other mesh name we assume as a generic convex hull.
  450. //
  451. // Collect the verts using the vertex polylist which will
  452. // filter out duplicates. This is importaint as the convex
  453. // generators can sometimes fail with duplicate verts.
  454. //
  455. VertexPolyList polyList;
  456. MatrixF meshMat(localXfm);
  457. Point3F t = meshMat.getPosition();
  458. t.convolve(mOwner->getScale());
  459. meshMat.setPosition(t);
  460. polyList.setTransform(&MatrixF::Identity, mOwner->getScale());
  461. mesh->buildPolyList(0, &polyList, surfaceKey, NULL);
  462. colShape->addConvex(polyList.getVertexList().address(),
  463. polyList.getVertexList().size(),
  464. meshMat);
  465. } // objects
  466. } // details
  467. }
  468. return colShape;
  469. }