HelloWorld.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2025 Jorrit Rouwe
  3. // SPDX-License-Identifier: CC0-1.0
  4. // This file is in the public domain. It serves as an example to start building your own application using Jolt Physics. Feel free to copy paste without attribution!
  5. // The Jolt headers don't include Jolt.h. Always include Jolt.h before including any other Jolt header.
  6. // You can use Jolt.h in your precompiled header to speed up compilation.
  7. #include <Jolt/Jolt.h>
  8. // Jolt includes
  9. #include <Jolt/RegisterTypes.h>
  10. #include <Jolt/Core/Factory.h>
  11. #include <Jolt/Core/TempAllocator.h>
  12. #include <Jolt/Core/JobSystemThreadPool.h>
  13. #include <Jolt/Physics/PhysicsSettings.h>
  14. #include <Jolt/Physics/PhysicsSystem.h>
  15. #include <Jolt/Physics/Collision/Shape/BoxShape.h>
  16. #include <Jolt/Physics/Collision/Shape/SphereShape.h>
  17. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  18. #include <Jolt/Physics/Body/BodyActivationListener.h>
  19. // STL includes
  20. #include <iostream>
  21. #include <cstdarg>
  22. #include <thread>
  23. // Disable common warnings triggered by Jolt, you can use JPH_SUPPRESS_WARNING_PUSH / JPH_SUPPRESS_WARNING_POP to store and restore the warning state
  24. JPH_SUPPRESS_WARNINGS
  25. // All Jolt symbols are in the JPH namespace
  26. using namespace JPH;
  27. // If you want your code to compile using single or double precision write 0.0_r to get a Real value that compiles to double or float depending if JPH_DOUBLE_PRECISION is set or not.
  28. using namespace JPH::literals;
  29. // We're also using STL classes in this example
  30. using namespace std;
  31. // Callback for traces, connect this to your own trace function if you have one
  32. static void TraceImpl(const char *inFMT, ...)
  33. {
  34. // Format the message
  35. va_list list;
  36. va_start(list, inFMT);
  37. char buffer[1024];
  38. vsnprintf(buffer, sizeof(buffer), inFMT, list);
  39. va_end(list);
  40. // Print to the TTY
  41. cout << buffer << endl;
  42. }
  43. #ifdef JPH_ENABLE_ASSERTS
  44. // Callback for asserts, connect this to your own assert handler if you have one
  45. static bool AssertFailedImpl(const char *inExpression, const char *inMessage, const char *inFile, uint inLine)
  46. {
  47. // Print to the TTY
  48. cout << inFile << ":" << inLine << ": (" << inExpression << ") " << (inMessage != nullptr? inMessage : "") << endl;
  49. // Breakpoint
  50. return true;
  51. };
  52. #endif // JPH_ENABLE_ASSERTS
  53. // Layer that objects can be in, determines which other objects it can collide with
  54. // Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more
  55. // layers if you want. E.g. you could have a layer for high detail collision (which is not used by the physics simulation
  56. // but only if you do collision testing).
  57. namespace Layers
  58. {
  59. static constexpr ObjectLayer NON_MOVING = 0;
  60. static constexpr ObjectLayer MOVING = 1;
  61. static constexpr ObjectLayer NUM_LAYERS = 2;
  62. };
  63. /// Class that determines if two object layers can collide
  64. class ObjectLayerPairFilterImpl : public ObjectLayerPairFilter
  65. {
  66. public:
  67. virtual bool ShouldCollide(ObjectLayer inObject1, ObjectLayer inObject2) const override
  68. {
  69. switch (inObject1)
  70. {
  71. case Layers::NON_MOVING:
  72. return inObject2 == Layers::MOVING; // Non moving only collides with moving
  73. case Layers::MOVING:
  74. return true; // Moving collides with everything
  75. default:
  76. JPH_ASSERT(false);
  77. return false;
  78. }
  79. }
  80. };
  81. // Each broadphase layer results in a separate bounding volume tree in the broad phase. You at least want to have
  82. // a layer for non-moving and moving objects to avoid having to update a tree full of static objects every frame.
  83. // You can have a 1-on-1 mapping between object layers and broadphase layers (like in this case) but if you have
  84. // many object layers you'll be creating many broad phase trees, which is not efficient. If you want to fine tune
  85. // your broadphase layers define JPH_TRACK_BROADPHASE_STATS and look at the stats reported on the TTY.
  86. namespace BroadPhaseLayers
  87. {
  88. static constexpr BroadPhaseLayer NON_MOVING(0);
  89. static constexpr BroadPhaseLayer MOVING(1);
  90. static constexpr uint NUM_LAYERS(2);
  91. };
  92. // BroadPhaseLayerInterface implementation
  93. // This defines a mapping between object and broadphase layers.
  94. class BPLayerInterfaceImpl final : public BroadPhaseLayerInterface
  95. {
  96. public:
  97. BPLayerInterfaceImpl()
  98. {
  99. // Create a mapping table from object to broad phase layer
  100. mObjectToBroadPhase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING;
  101. mObjectToBroadPhase[Layers::MOVING] = BroadPhaseLayers::MOVING;
  102. }
  103. virtual uint GetNumBroadPhaseLayers() const override
  104. {
  105. return BroadPhaseLayers::NUM_LAYERS;
  106. }
  107. virtual BroadPhaseLayer GetBroadPhaseLayer(ObjectLayer inLayer) const override
  108. {
  109. JPH_ASSERT(inLayer < Layers::NUM_LAYERS);
  110. return mObjectToBroadPhase[inLayer];
  111. }
  112. #if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED)
  113. virtual const char * GetBroadPhaseLayerName(BroadPhaseLayer inLayer) const override
  114. {
  115. switch ((BroadPhaseLayer::Type)inLayer)
  116. {
  117. case (BroadPhaseLayer::Type)BroadPhaseLayers::NON_MOVING: return "NON_MOVING";
  118. case (BroadPhaseLayer::Type)BroadPhaseLayers::MOVING: return "MOVING";
  119. default: JPH_ASSERT(false); return "INVALID";
  120. }
  121. }
  122. #endif // JPH_EXTERNAL_PROFILE || JPH_PROFILE_ENABLED
  123. private:
  124. BroadPhaseLayer mObjectToBroadPhase[Layers::NUM_LAYERS];
  125. };
  126. /// Class that determines if an object layer can collide with a broadphase layer
  127. class ObjectVsBroadPhaseLayerFilterImpl : public ObjectVsBroadPhaseLayerFilter
  128. {
  129. public:
  130. virtual bool ShouldCollide(ObjectLayer inLayer1, BroadPhaseLayer inLayer2) const override
  131. {
  132. switch (inLayer1)
  133. {
  134. case Layers::NON_MOVING:
  135. return inLayer2 == BroadPhaseLayers::MOVING;
  136. case Layers::MOVING:
  137. return true;
  138. default:
  139. JPH_ASSERT(false);
  140. return false;
  141. }
  142. }
  143. };
  144. // An example contact listener
  145. class MyContactListener : public ContactListener
  146. {
  147. public:
  148. // See: ContactListener
  149. virtual ValidateResult OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult) override
  150. {
  151. cout << "Contact validate callback" << endl;
  152. // Allows you to ignore a contact before it is created (using layers to not make objects collide is cheaper!)
  153. return ValidateResult::AcceptAllContactsForThisBodyPair;
  154. }
  155. virtual void OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
  156. {
  157. cout << "A contact was added" << endl;
  158. }
  159. virtual void OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
  160. {
  161. cout << "A contact was persisted" << endl;
  162. }
  163. virtual void OnContactRemoved(const SubShapeIDPair &inSubShapePair) override
  164. {
  165. cout << "A contact was removed" << endl;
  166. }
  167. };
  168. // An example activation listener
  169. class MyBodyActivationListener : public BodyActivationListener
  170. {
  171. public:
  172. virtual void OnBodyActivated(const BodyID &inBodyID, uint64 inBodyUserData) override
  173. {
  174. cout << "A body got activated" << endl;
  175. }
  176. virtual void OnBodyDeactivated(const BodyID &inBodyID, uint64 inBodyUserData) override
  177. {
  178. cout << "A body went to sleep" << endl;
  179. }
  180. };
  181. // Program entry point
  182. int main(int argc, char** argv)
  183. {
  184. // Register allocation hook. In this example we'll just let Jolt use malloc / free but you can override these if you want (see Memory.h).
  185. // This needs to be done before any other Jolt function is called.
  186. RegisterDefaultAllocator();
  187. // Install trace and assert callbacks
  188. Trace = TraceImpl;
  189. JPH_IF_ENABLE_ASSERTS(AssertFailed = AssertFailedImpl;)
  190. // Create a factory, this class is responsible for creating instances of classes based on their name or hash and is mainly used for deserialization of saved data.
  191. // It is not directly used in this example but still required.
  192. Factory::sInstance = new Factory();
  193. // Register all physics types with the factory and install their collision handlers with the CollisionDispatch class.
  194. // If you have your own custom shape types you probably need to register their handlers with the CollisionDispatch before calling this function.
  195. // If you implement your own default material (PhysicsMaterial::sDefault) make sure to initialize it before this function or else this function will create one for you.
  196. RegisterTypes();
  197. // We need a temp allocator for temporary allocations during the physics update. We're
  198. // pre-allocating 10 MB to avoid having to do allocations during the physics update.
  199. // B.t.w. 10 MB is way too much for this example but it is a typical value you can use.
  200. // If you don't want to pre-allocate you can also use TempAllocatorMalloc to fall back to
  201. // malloc / free.
  202. TempAllocatorImpl temp_allocator(10 * 1024 * 1024);
  203. // We need a job system that will execute physics jobs on multiple threads. Typically
  204. // you would implement the JobSystem interface yourself and let Jolt Physics run on top
  205. // of your own job scheduler. JobSystemThreadPool is an example implementation.
  206. JobSystemThreadPool job_system(cMaxPhysicsJobs, cMaxPhysicsBarriers, thread::hardware_concurrency() - 1);
  207. // This is the max amount of rigid bodies that you can add to the physics system. If you try to add more you'll get an error.
  208. // Note: This value is low because this is a simple test. For a real project use something in the order of 65536.
  209. const uint cMaxBodies = 1024;
  210. // This determines how many mutexes to allocate to protect rigid bodies from concurrent access. Set it to 0 for the default settings.
  211. const uint cNumBodyMutexes = 0;
  212. // This is the max amount of body pairs that can be queued at any time (the broad phase will detect overlapping
  213. // body pairs based on their bounding boxes and will insert them into a queue for the narrowphase). If you make this buffer
  214. // too small the queue will fill up and the broad phase jobs will start to do narrow phase work. This is slightly less efficient.
  215. // Note: This value is low because this is a simple test. For a real project use something in the order of 65536.
  216. const uint cMaxBodyPairs = 1024;
  217. // This is the maximum size of the contact constraint buffer. If more contacts (collisions between bodies) are detected than this
  218. // number then these contacts will be ignored and bodies will start interpenetrating / fall through the world.
  219. // Note: This value is low because this is a simple test. For a real project use something in the order of 10240.
  220. const uint cMaxContactConstraints = 1024;
  221. // Create mapping table from object layer to broadphase layer
  222. // Note: As this is an interface, PhysicsSystem will take a reference to this so this instance needs to stay alive!
  223. // Also have a look at BroadPhaseLayerInterfaceTable or BroadPhaseLayerInterfaceMask for a simpler interface.
  224. BPLayerInterfaceImpl broad_phase_layer_interface;
  225. // Create class that filters object vs broadphase layers
  226. // Note: As this is an interface, PhysicsSystem will take a reference to this so this instance needs to stay alive!
  227. // Also have a look at ObjectVsBroadPhaseLayerFilterTable or ObjectVsBroadPhaseLayerFilterMask for a simpler interface.
  228. ObjectVsBroadPhaseLayerFilterImpl object_vs_broadphase_layer_filter;
  229. // Create class that filters object vs object layers
  230. // Note: As this is an interface, PhysicsSystem will take a reference to this so this instance needs to stay alive!
  231. // Also have a look at ObjectLayerPairFilterTable or ObjectLayerPairFilterMask for a simpler interface.
  232. ObjectLayerPairFilterImpl object_vs_object_layer_filter;
  233. // Now we can create the actual physics system.
  234. PhysicsSystem physics_system;
  235. physics_system.Init(cMaxBodies, cNumBodyMutexes, cMaxBodyPairs, cMaxContactConstraints, broad_phase_layer_interface, object_vs_broadphase_layer_filter, object_vs_object_layer_filter);
  236. // A body activation listener gets notified when bodies activate and go to sleep
  237. // Note that this is called from a job so whatever you do here needs to be thread safe.
  238. // Registering one is entirely optional.
  239. MyBodyActivationListener body_activation_listener;
  240. physics_system.SetBodyActivationListener(&body_activation_listener);
  241. // A contact listener gets notified when bodies (are about to) collide, and when they separate again.
  242. // Note that this is called from a job so whatever you do here needs to be thread safe.
  243. // Registering one is entirely optional.
  244. MyContactListener contact_listener;
  245. physics_system.SetContactListener(&contact_listener);
  246. // The main way to interact with the bodies in the physics system is through the body interface. There is a locking and a non-locking
  247. // variant of this. We're going to use the locking version (even though we're not planning to access bodies from multiple threads)
  248. BodyInterface &body_interface = physics_system.GetBodyInterface();
  249. // Next we can create a rigid body to serve as the floor, we make a large box
  250. // Create the settings for the collision volume (the shape).
  251. // Note that for simple shapes (like boxes) you can also directly construct a BoxShape.
  252. BoxShapeSettings floor_shape_settings(Vec3(100.0f, 1.0f, 100.0f));
  253. floor_shape_settings.SetEmbedded(); // A ref counted object on the stack (base class RefTarget) should be marked as such to prevent it from being freed when its reference count goes to 0.
  254. // Create the shape
  255. ShapeSettings::ShapeResult floor_shape_result = floor_shape_settings.Create();
  256. ShapeRefC floor_shape = floor_shape_result.Get(); // We don't expect an error here, but you can check floor_shape_result for HasError() / GetError()
  257. // Create the settings for the body itself. Note that here you can also set other properties like the restitution / friction.
  258. BodyCreationSettings floor_settings(floor_shape, RVec3(0.0_r, -1.0_r, 0.0_r), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING);
  259. // Create the actual rigid body
  260. Body *floor = body_interface.CreateBody(floor_settings); // Note that if we run out of bodies this can return nullptr
  261. // Add it to the world
  262. body_interface.AddBody(floor->GetID(), EActivation::DontActivate);
  263. // Now create a dynamic body to bounce on the floor
  264. // Note that this uses the shorthand version of creating and adding a body to the world
  265. BodyCreationSettings sphere_settings(new SphereShape(0.5f), RVec3(0.0_r, 2.0_r, 0.0_r), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING);
  266. BodyID sphere_id = body_interface.CreateAndAddBody(sphere_settings, EActivation::Activate);
  267. // Now you can interact with the dynamic body, in this case we're going to give it a velocity.
  268. // (note that if we had used CreateBody then we could have set the velocity straight on the body before adding it to the physics system)
  269. body_interface.SetLinearVelocity(sphere_id, Vec3(0.0f, -5.0f, 0.0f));
  270. // We simulate the physics world in discrete time steps. 60 Hz is a good rate to update the physics system.
  271. const float cDeltaTime = 1.0f / 60.0f;
  272. // Optional step: Before starting the physics simulation you can optimize the broad phase. This improves collision detection performance (it's pointless here because we only have 2 bodies).
  273. // You should definitely not call this every frame or when e.g. streaming in a new level section as it is an expensive operation.
  274. // Instead insert all new objects in batches instead of 1 at a time to keep the broad phase efficient.
  275. physics_system.OptimizeBroadPhase();
  276. // Now we're ready to simulate the body, keep simulating until it goes to sleep
  277. uint step = 0;
  278. while (body_interface.IsActive(sphere_id))
  279. {
  280. // Next step
  281. ++step;
  282. // Output current position and velocity of the sphere
  283. RVec3 position = body_interface.GetCenterOfMassPosition(sphere_id);
  284. Vec3 velocity = body_interface.GetLinearVelocity(sphere_id);
  285. cout << "Step " << step << ": Position = (" << position.GetX() << ", " << position.GetY() << ", " << position.GetZ() << "), Velocity = (" << velocity.GetX() << ", " << velocity.GetY() << ", " << velocity.GetZ() << ")" << endl;
  286. // If you take larger steps than 1 / 60th of a second you need to do multiple collision steps in order to keep the simulation stable. Do 1 collision step per 1 / 60th of a second (round up).
  287. const int cCollisionSteps = 1;
  288. // Step the world
  289. physics_system.Update(cDeltaTime, cCollisionSteps, &temp_allocator, &job_system);
  290. }
  291. // Remove the sphere from the physics system. Note that the sphere itself keeps all of its state and can be re-added at any time.
  292. body_interface.RemoveBody(sphere_id);
  293. // Destroy the sphere. After this the sphere ID is no longer valid.
  294. body_interface.DestroyBody(sphere_id);
  295. // Remove and destroy the floor
  296. body_interface.RemoveBody(floor->GetID());
  297. body_interface.DestroyBody(floor->GetID());
  298. // Unregisters all types with the factory and cleans up the default material
  299. UnregisterTypes();
  300. // Destroy the factory
  301. delete Factory::sInstance;
  302. Factory::sInstance = nullptr;
  303. return 0;
  304. }