Main.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. // Framework includes
  2. #include "BsApplication.h"
  3. #include "Resources/BsResources.h"
  4. #include "Resources/BsBuiltinResources.h"
  5. #include "Material/BsMaterial.h"
  6. #include "Components/BsCCamera.h"
  7. #include "Components/BsCRenderable.h"
  8. #include "Components/BsCSkybox.h"
  9. #include "Components/BsCPlaneCollider.h"
  10. #include "Components/BsCBoxCollider.h"
  11. #include "Components/BsCSphereCollider.h"
  12. #include "Components/BsCCharacterController.h"
  13. #include "Components/BsCRigidbody.h"
  14. #include "GUI/BsCGUIWidget.h"
  15. #include "GUI/BsGUIPanel.h"
  16. #include "GUI/BsGUILayoutY.h"
  17. #include "GUI/BsGUILabel.h"
  18. #include "Physics/BsPhysicsMaterial.h"
  19. #include "RenderAPI/BsRenderAPI.h"
  20. #include "RenderAPI/BsRenderWindow.h"
  21. #include "Scene/BsSceneObject.h"
  22. #include "Platform/BsCursor.h"
  23. #include "Input/BsInput.h"
  24. // Example includes
  25. #include "BsExampleFramework.h"
  26. #include "BsFPSWalker.h"
  27. #include "BsFPSCamera.h"
  28. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  29. // This example sets up a physical environment in which the user can walk around using the character controller component,
  30. // and shoot the placed geometry demonstrating various aspects of the physics system. This includes a demonstration of
  31. // static colliders, dynamic rigidbodies, physical materials, character controller and manual application of forces.
  32. //
  33. // The example first loads necessary resources, including textures, materialss and physical materials. Then it sets up the
  34. // scene, consisting of a floor, and multiple stacks of boxes that can be knocked down. Character controller is created
  35. // next, as well as the camera. Components for moving the character controller and the camera are attached to allow the
  36. // user to control the character. Finally an input callback is hooked up that shoots spheres when user presses the left
  37. // mouse button.
  38. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  39. namespace bs
  40. {
  41. constexpr float GROUND_PLANE_SCALE = 50.0f;
  42. UINT32 windowResWidth = 1280;
  43. UINT32 windowResHeight = 720;
  44. /** Set up the scene used by the example, and the camera to view the world through. */
  45. void setUpScene()
  46. {
  47. /************************************************************************/
  48. /* ASSETS */
  49. /************************************************************************/
  50. // Prepare all the resources we'll be using throughout this example
  51. // Grab a couple of test textures that we'll apply to the rendered objects
  52. HTexture gridPattern = ExampleFramework::loadTexture(ExampleTexture::GridPattern);
  53. HTexture gridPattern2 = ExampleFramework::loadTexture(ExampleTexture::GridPattern2);
  54. // Grab the default PBR shader
  55. HShader shader = gBuiltinResources().getBuiltinShader(BuiltinShader::Standard);
  56. // Create a set of materials to apply to renderables used
  57. HMaterial planeMaterial = Material::create(shader);
  58. planeMaterial->setTexture("gAlbedoTex", gridPattern2);
  59. // Tile the texture so every tile covers a 2x2m area
  60. planeMaterial->setVec2("gUVTile", Vector2::ONE * GROUND_PLANE_SCALE * 0.5f);
  61. HMaterial boxMaterial = Material::create(shader);
  62. boxMaterial->setTexture("gAlbedoTex", gridPattern);
  63. HMaterial sphereMaterial = Material::create(shader);
  64. // Load meshes we'll used for our rendered objects
  65. HMesh boxMesh = gBuiltinResources().getMesh(BuiltinMesh::Box);
  66. HMesh planeMesh = gBuiltinResources().getMesh(BuiltinMesh::Quad);
  67. HMesh sphereMesh = gBuiltinResources().getMesh(BuiltinMesh::Sphere);
  68. // Create a physics material we'll use for the box geometry, as well as the floor. The material has high
  69. // static and dynamic friction, with low restitution (low bounciness). Simulates a harder, rough, solid surface.
  70. HPhysicsMaterial boxPhysicsMaterial = PhysicsMaterial::create(1.0f, 1.0f, 0.0f);
  71. // Create a physics material for the sphere geometry, with higher bounciness. Simulates elasticity.
  72. HPhysicsMaterial spherePhysicsMaterial = PhysicsMaterial::create(1.0f, 1.0f, 0.5f);
  73. /************************************************************************/
  74. /* FLOOR */
  75. /************************************************************************/
  76. // Set up renderable geometry for the floor plane
  77. HSceneObject floorSO = SceneObject::create("Floor");
  78. HRenderable floorRenderable = floorSO->addComponent<CRenderable>();
  79. floorRenderable->setMesh(planeMesh);
  80. floorRenderable->setMaterial(planeMaterial);
  81. floorSO->setScale(Vector3(GROUND_PLANE_SCALE, 1.0f, GROUND_PLANE_SCALE));
  82. // Add a plane collider that will prevent physical objects going through the floor
  83. HPlaneCollider planeCollider = floorSO->addComponent<CPlaneCollider>();
  84. // Apply the non-bouncy material
  85. planeCollider->setMaterial(boxPhysicsMaterial);
  86. /************************************************************************/
  87. /* BOXES */
  88. /************************************************************************/
  89. // Helper method that creates a pyramid of six boxes that can be physically manipulated
  90. auto createBoxStack = [=](const Vector3& position, const Quaternion& rotation = Quaternion::IDENTITY)
  91. {
  92. HSceneObject boxSO[6];
  93. for (auto& entry : boxSO)
  94. {
  95. // Create a scene object and a renderable
  96. entry = SceneObject::create("Box");
  97. HRenderable boxRenderable = entry->addComponent<CRenderable>();
  98. boxRenderable->setMesh(boxMesh);
  99. boxRenderable->setMaterial(boxMaterial);
  100. // Add a plane collider that represent's the physical geometry of the box
  101. HBoxCollider boxCollider = entry->addComponent<CBoxCollider>();
  102. // Apply the non-bouncy material
  103. boxCollider->setMaterial(boxPhysicsMaterial);
  104. // Set the mass of a box to 25 kilograms
  105. boxCollider->setMass(25.0f);
  106. // Add a rigidbody, making the box geometry able to react to interactions with other physical objects
  107. HRigidbody boxRigidbody = entry->addComponent<CRigidbody>();
  108. }
  109. // Stack the boxes in a pyramid
  110. Vector3 positions[] =
  111. {
  112. // First row
  113. Vector3(-1.25f, 0.55f, 0.0f),
  114. Vector3(0.0f, 0.55f, 0.0f),
  115. Vector3(1.25f, 0.55f, 0.0f),
  116. // Second row
  117. Vector3(-0.65f, 1.6f, 0.0f),
  118. Vector3(0.65f, 1.6f, 0.0f),
  119. // Third row
  120. Vector3(0.0f, 2.65f, 0.0f),
  121. };
  122. for(UINT32 i = 0; i < 6; i++)
  123. {
  124. Vector3 pos = rotation.rotate(positions[i]) + position;
  125. boxSO[i]->setPosition(pos);
  126. }
  127. };
  128. createBoxStack(Vector3::ZERO);
  129. createBoxStack(Vector3(6.0f, 0.0f, 3.0f), Quaternion(Degree(0.0f), Degree(-45.0f), Degree(0.0f)));
  130. createBoxStack(Vector3(-6.0f, 0.0f, 3.0f), Quaternion(Degree(0.0f), Degree(45.0f), Degree(0.0f)));
  131. /************************************************************************/
  132. /* CHARACTER */
  133. /************************************************************************/
  134. // Add physics geometry and components for character movement and physics interaction
  135. HSceneObject characterSO = SceneObject::create("Character");
  136. characterSO->setPosition(Vector3(0.0f, 1.0f, 5.0f));
  137. // Add a character controller, representing the physical geometry of the character
  138. HCharacterController charController = characterSO->addComponent<CCharacterController>();
  139. // Make the character about 1.8m high, with 0.4m radius (controller represents a capsule)
  140. charController->setHeight(1.0f); // + 0.4 * 2 radius = 1.8m height
  141. charController->setRadius(0.4f);
  142. // FPS walker uses default input controls to move the character controller attached to the same object
  143. characterSO->addComponent<FPSWalker>();
  144. /************************************************************************/
  145. /* CAMERA */
  146. /************************************************************************/
  147. // In order something to render on screen we need at least one camera.
  148. // Like before, we create a new scene object at (0, 0, 0).
  149. HSceneObject sceneCameraSO = SceneObject::create("SceneCamera");
  150. // Get the primary render window we need for creating the camera.
  151. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  152. // Add a Camera component that will output whatever it sees into that window
  153. // (You could also use a render texture or another window you created).
  154. HCamera sceneCamera = sceneCameraSO->addComponent<CCamera>();
  155. sceneCamera->getViewport()->setTarget(window);
  156. // Set up camera component properties
  157. // Set closest distance that is visible. Anything below that is clipped.
  158. sceneCamera->setNearClipDistance(0.005f);
  159. // Set farthest distance that is visible. Anything above that is clipped.
  160. sceneCamera->setFarClipDistance(1000);
  161. // Set aspect ratio depending on the current resolution
  162. sceneCamera->setAspectRatio(windowResWidth / (float)windowResHeight);
  163. // Add a component that allows the camera to be rotated using the mouse
  164. HFPSCamera fpsCamera = sceneCameraSO->addComponent<FPSCamera>();
  165. // Set the character controller on the FPS camera, so the component can apply yaw rotation to it
  166. fpsCamera->setCharacter(characterSO);
  167. // Make the camera a child of the character scene object, and position it roughly at eye level
  168. sceneCameraSO->setParent(characterSO);
  169. sceneCameraSO->setPosition(Vector3(0.0f, 1.8f * 0.5f - 0.1f, 0.0f));
  170. /************************************************************************/
  171. /* SKYBOX */
  172. /************************************************************************/
  173. // Load a skybox texture
  174. HTexture skyCubemap = ExampleFramework::loadTexture(ExampleTexture::EnvironmentDaytime, false, true, true);
  175. // Add a skybox texture for sky reflections
  176. HSceneObject skyboxSO = SceneObject::create("Skybox");
  177. HSkybox skybox = skyboxSO->addComponent<CSkybox>();
  178. skybox->setTexture(skyCubemap);
  179. /************************************************************************/
  180. /* CURSOR */
  181. /************************************************************************/
  182. // Hide and clip the cursor, since we only use the mouse movement for camera rotation
  183. Cursor::instance().hide();
  184. Cursor::instance().clipToWindow(*window);
  185. /************************************************************************/
  186. /* INPUT */
  187. /************************************************************************/
  188. // Hook up input that launches a sphere when user clicks the mouse, and Esc key to quit
  189. gInput().onButtonUp.connect([=](const ButtonEvent& ev)
  190. {
  191. if(ev.buttonCode == BC_MOUSE_LEFT)
  192. {
  193. // Create the scene object and renderable geometry of the sphere
  194. HSceneObject sphereSO = SceneObject::create("Sphere");
  195. HRenderable sphereRenderable = sphereSO->addComponent<CRenderable>();
  196. sphereRenderable->setMesh(sphereMesh);
  197. sphereRenderable->setMaterial(sphereMaterial);
  198. // Create a spherical collider, represting physical geometry
  199. HSphereCollider sphereCollider = sphereSO->addComponent<CSphereCollider>();
  200. // Apply the bouncy material
  201. sphereCollider->setMaterial(spherePhysicsMaterial);
  202. // Set mass to 25kg
  203. sphereCollider->setMass(25.0f);
  204. // Add a rigidbody, making the object interactable
  205. HRigidbody sphereRigidbody = sphereSO->addComponent<CRigidbody>();
  206. // Position the sphere in front of the character, and scale it down a bit
  207. Vector3 spawnPos = characterSO->getTransform().getPosition();
  208. spawnPos += sceneCameraSO->getTransform().getForward() * 0.5f;
  209. spawnPos.y += 0.5f;
  210. sphereSO->setPosition(spawnPos);
  211. sphereSO->setScale(Vector3(0.3f, 0.3f, 0.3f));
  212. // Apply force to the sphere, launching it forward in the camera's view direction
  213. sphereRigidbody->addForce(sceneCameraSO->getTransform().getForward() * 40.0f, ForceMode::Velocity);
  214. }
  215. else if(ev.buttonCode == BC_ESCAPE)
  216. {
  217. // Quit the application when Escape key is pressed
  218. gApplication().quitRequested();
  219. }
  220. });
  221. /************************************************************************/
  222. /* GUI */
  223. /************************************************************************/
  224. // Display GUI elements indicating to the user which input keys are available
  225. // Add a GUIWidget component we will use for rendering the GUI
  226. HSceneObject guiSO = SceneObject::create("GUI");
  227. HGUIWidget gui = guiSO->addComponent<CGUIWidget>(sceneCamera);
  228. // Grab the main panel onto which to attach the GUI elements to
  229. GUIPanel* mainPanel = gui->getPanel();
  230. // Create a vertical GUI layout to align the labels one below each other
  231. GUILayoutY* vertLayout = GUILayoutY::create();
  232. // Create the GUI labels displaying the available input commands
  233. HString shootString(u8"Press left mouse button to shoot");
  234. HString quitString(u8"Press the Escape key to quit");
  235. vertLayout->addNewElement<GUILabel>(shootString);
  236. vertLayout->addNewElement<GUILabel>(quitString);
  237. // Register the layout with the main GUI panel, placing the layout in top left corner of the screen by default
  238. mainPanel->addElement(vertLayout);
  239. }
  240. }
  241. /** Main entry point into the application. */
  242. #if BS_PLATFORM == BS_PLATFORM_WIN32
  243. #include <windows.h>
  244. int CALLBACK WinMain(
  245. _In_ HINSTANCE hInstance,
  246. _In_ HINSTANCE hPrevInstance,
  247. _In_ LPSTR lpCmdLine,
  248. _In_ int nCmdShow
  249. )
  250. #else
  251. int main()
  252. #endif
  253. {
  254. using namespace bs;
  255. // Initializes the application and creates a window with the specified properties
  256. VideoMode videoMode(windowResWidth, windowResHeight);
  257. Application::startUp(videoMode, "Example", false);
  258. // Registers a default set of input controls
  259. ExampleFramework::setupInputConfig();
  260. // Set up the scene with an object to render and a camera
  261. setUpScene();
  262. // Runs the main loop that does most of the work. This method will exit when user closes the main
  263. // window or exits in some other way.
  264. Application::instance().runMainLoop();
  265. // When done, clean up
  266. Application::shutDown();
  267. return 0;
  268. }