Main.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  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/BsCLight.h"
  9. #include "Components/BsCSkybox.h"
  10. #include "Components/BsCPlaneCollider.h"
  11. #include "Components/BsCCharacterController.h"
  12. #include "Components/BsCParticleSystem.h"
  13. #include "Image/BsSpriteTexture.h"
  14. #include "Particles/BsParticleSystem.h"
  15. #include "Particles/BsParticleEmitter.h"
  16. #include "Particles/BsParticleEvolver.h"
  17. #include "RenderAPI/BsRenderAPI.h"
  18. #include "RenderAPI/BsRenderWindow.h"
  19. #include "Scene/BsSceneObject.h"
  20. #include "Platform/BsCursor.h"
  21. #include "Input/BsInput.h"
  22. #include "Utility/BsTime.h"
  23. // Example includes
  24. #include "BsExampleFramework.h"
  25. #include "BsFPSWalker.h"
  26. #include "BsFPSCamera.h"
  27. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  28. // This example sets up an environment with three particle systems:
  29. // - Smoke effect using traditional billboard particles
  30. // - 3D particles with support for world collisions and lighting
  31. // - GPU particle simulation with a vector field
  32. //
  33. // It also sets up necessary physical objects for collision, as well as the character collider and necessary components
  34. // for walking around the environment.
  35. //
  36. // The example first loads necessary resources, including textures and materials. Then it set up the scene, consisting of a
  37. // floor and a skybox. Character controller is created next, as well as the camera. Components for moving the character
  38. // controller and the camera are attached to allow the user to control the character. Finally it sets up three separate
  39. // particle systems, their creation wrapped in their own creation methods. Finally the cursor is hidden and quit on Esc
  40. // key press hooked up.
  41. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  42. namespace bs
  43. {
  44. constexpr float GROUND_PLANE_SCALE = 50.0f;
  45. UINT32 windowResWidth = 1280;
  46. UINT32 windowResHeight = 720;
  47. // Set up a helper component that makes the object its attached to orbit a point. This is used by the 3D particle
  48. // system for moving its light.
  49. class LightOrbit : public Component
  50. {
  51. public:
  52. LightOrbit(const HSceneObject& parent, float radius)
  53. :Component(parent), mRadius(radius)
  54. { }
  55. void onInitialized() override
  56. {
  57. mCenter = SO()->getTransform().getPosition();
  58. }
  59. void update() override
  60. {
  61. Vector3 position = mCenter + mRadius * Vector3(Math::cos(mAngle), 0.0f, Math::sin(mAngle));
  62. mAngle += Degree(gTime().getFrameDelta() * 90.0f);
  63. SO()->setWorldPosition(position);
  64. }
  65. private:
  66. Degree mAngle = Degree(0.0f);
  67. Vector3 mCenter;
  68. float mRadius;
  69. };
  70. /** Container for all assets used by the particles systems in this example. */
  71. struct ParticleSystemAssets
  72. {
  73. // Smoke particle system assets
  74. HSpriteTexture smokeTex;
  75. HMaterial smokeMat;
  76. // 3D particle system assets
  77. HMesh sphereMesh;
  78. HMaterial particles3DMat;
  79. HMaterial lightMat;
  80. // GPU particle system assets
  81. HMaterial litParticleEmissiveMat;
  82. HVectorField vectorField;
  83. };
  84. /** Load the assets used by the particle systems. */
  85. ParticleSystemAssets loadParticleSystemAssets()
  86. {
  87. ParticleSystemAssets assets;
  88. // Smoke particle system assets
  89. //// Import the texture and set up a sprite texture so we can animate it
  90. HTexture smokeTex = ExampleFramework::loadTexture(ExampleTexture::ParticleSmoke);
  91. assets.smokeTex = SpriteTexture::create(smokeTex);
  92. //// Set up sprite sheet animation on the sprite texture
  93. SpriteSheetGridAnimation smokeGridAnim(5, 6, 30, 30);
  94. assets.smokeTex->setAnimation(smokeGridAnim);
  95. assets.smokeTex->setAnimationPlayback(SpriteAnimationPlayback::None);
  96. //// Set up a shader without lighting and enable soft particle rendering
  97. HShader particleUnlitShader = gBuiltinResources().getBuiltinShader(BuiltinShader::ParticlesUnlit);
  98. assets.smokeMat = Material::create(particleUnlitShader);
  99. assets.smokeMat->setVariation(ShaderVariation(
  100. {
  101. ShaderVariation::Param("SOFT", true)
  102. })
  103. );
  104. //// Fade over the range of 2m (used for soft particle blending)
  105. assets.smokeMat->setFloat("gInvDepthRange", 1.0f / 2.0f);
  106. assets.smokeMat->setSpriteTexture("gTexture", assets.smokeTex);
  107. // Set up an emissive material used in the GPU vector field example
  108. HShader particleLitShader = gBuiltinResources().getBuiltinShader(BuiltinShader::ParticlesLitOpaque);
  109. assets.litParticleEmissiveMat = Material::create(particleLitShader);
  110. assets.litParticleEmissiveMat->setTexture("gEmissiveMaskTex", gBuiltinResources().getTexture(BuiltinTexture::White));
  111. assets.litParticleEmissiveMat->setColor("gEmissiveColor", Color::White * 10.0f);
  112. // 3D particle system assets
  113. //// Create another lit material using a plain white albedo texture
  114. assets.particles3DMat = Material::create(particleLitShader);
  115. assets.particles3DMat->setTexture("gAlbedoTex", gBuiltinResources().getTexture(BuiltinTexture::White));
  116. //// Create a material used for rendering the light sphere itself
  117. HShader standardShader = gBuiltinResources().getBuiltinShader(BuiltinShader::Standard);
  118. assets.lightMat = Material::create(standardShader);
  119. assets.lightMat->setTexture("gEmissiveMaskTex", gBuiltinResources().getTexture(BuiltinTexture::White));
  120. assets.lightMat->setColor("gEmissiveColor", Color::Red * 5.0f);
  121. //// Import a vector field used in the GPU simulation
  122. assets.vectorField = ExampleFramework::loadResource<VectorField>(ExampleResource::VectorField);
  123. //// Import a sphere mesh used for the 3D particles and the light sphere
  124. assets.sphereMesh = gBuiltinResources().getMesh(BuiltinMesh::Sphere);
  125. return assets;
  126. }
  127. void setupGPUParticleEffect(const Vector3& pos, const ParticleSystemAssets& assets);
  128. void setup3DParticleEffect(const Vector3& pos, const ParticleSystemAssets& assets);
  129. void setupSmokeEffect(const Vector3& pos, const ParticleSystemAssets& assets);
  130. /** Set up the scene used by the example, and the camera to view the world through. */
  131. void setUpScene()
  132. {
  133. /************************************************************************/
  134. /* ASSETS */
  135. /************************************************************************/
  136. // Prepare the assets required for the scene and background
  137. // Grab a texture used for rendering the ground
  138. HTexture gridPattern = ExampleFramework::loadTexture(ExampleTexture::GridPattern2);
  139. // Grab the default PBR shader
  140. HShader shader = gBuiltinResources().getBuiltinShader(BuiltinShader::Standard);
  141. // Create a material for rendering the ground and apply the ground texture
  142. HMaterial planeMaterial = Material::create(shader);
  143. planeMaterial->setTexture("gAlbedoTex", gridPattern);
  144. // Tile the texture so every tile covers a 2x2m area
  145. planeMaterial->setVec2("gUVTile", Vector2::ONE * GROUND_PLANE_SCALE * 0.5f);
  146. // Load the floor mesh
  147. HMesh planeMesh = gBuiltinResources().getMesh(BuiltinMesh::Quad);
  148. // Load assets used by the particle systems
  149. ParticleSystemAssets assets = loadParticleSystemAssets();
  150. /************************************************************************/
  151. /* FLOOR */
  152. /************************************************************************/
  153. // Set up renderable geometry for the floor plane
  154. HSceneObject floorSO = SceneObject::create("Floor");
  155. HRenderable floorRenderable = floorSO->addComponent<CRenderable>();
  156. floorRenderable->setMesh(planeMesh);
  157. floorRenderable->setMaterial(planeMaterial);
  158. floorSO->setScale(Vector3(GROUND_PLANE_SCALE, 1.0f, GROUND_PLANE_SCALE));
  159. // Add a plane collider that will prevent physical objects going through the floor
  160. HPlaneCollider planeCollider = floorSO->addComponent<CPlaneCollider>();
  161. /************************************************************************/
  162. /* CHARACTER */
  163. /************************************************************************/
  164. // Add physics geometry and components for character movement and physics interaction
  165. HSceneObject characterSO = SceneObject::create("Character");
  166. characterSO->setPosition(Vector3(0.0f, 1.0f, 5.0f));
  167. // Add a character controller, representing the physical geometry of the character
  168. HCharacterController charController = characterSO->addComponent<CCharacterController>();
  169. // Make the character about 1.8m high, with 0.4m radius (controller represents a capsule)
  170. charController->setHeight(1.0f); // + 0.4 * 2 radius = 1.8m height
  171. charController->setRadius(0.4f);
  172. // FPS walker uses default input controls to move the character controller attached to the same object
  173. characterSO->addComponent<FPSWalker>();
  174. /************************************************************************/
  175. /* CAMERA */
  176. /************************************************************************/
  177. // In order something to render on screen we need at least one camera.
  178. // Like before, we create a new scene object at (0, 0, 0).
  179. HSceneObject sceneCameraSO = SceneObject::create("SceneCamera");
  180. // Get the primary render window we need for creating the camera.
  181. SPtr<RenderWindow> window = gApplication().getPrimaryWindow();
  182. // Add a Camera component that will output whatever it sees into that window
  183. // (You could also use a render texture or another window you created).
  184. HCamera sceneCamera = sceneCameraSO->addComponent<CCamera>();
  185. sceneCamera->getViewport()->setTarget(window);
  186. // Set up camera component properties
  187. // Set closest distance that is visible. Anything below that is clipped.
  188. sceneCamera->setNearClipDistance(0.005f);
  189. // Set farthest distance that is visible. Anything above that is clipped.
  190. sceneCamera->setFarClipDistance(1000);
  191. // Set aspect ratio depending on the current resolution
  192. sceneCamera->setAspectRatio(windowResWidth / (float)windowResHeight);
  193. // Add a component that allows the camera to be rotated using the mouse
  194. sceneCameraSO->setRotation(Quaternion(Degree(-10.0f), Degree(0.0f), Degree(0.0f)));
  195. HFPSCamera fpsCamera = sceneCameraSO->addComponent<FPSCamera>();
  196. // Set the character controller on the FPS camera, so the component can apply yaw rotation to it
  197. fpsCamera->setCharacter(characterSO);
  198. // Make the camera a child of the character scene object, and position it roughly at eye level
  199. sceneCameraSO->setParent(characterSO);
  200. sceneCameraSO->setPosition(Vector3(0.0f, 1.8f * 0.5f - 0.1f, -2.0f));
  201. // Enable Bloom effect so that emissive materials look better
  202. auto rs = sceneCamera->getRenderSettings();
  203. rs->bloom.enabled = true;
  204. rs->bloom.intensity = 0.1f;
  205. rs->bloom.threshold = 5.0f;
  206. rs->bloom.quality = 3;
  207. sceneCamera->setRenderSettings(rs);
  208. /************************************************************************/
  209. /* SKYBOX */
  210. /************************************************************************/
  211. // Load a skybox texture
  212. HTexture skyCubemap = ExampleFramework::loadTexture(ExampleTexture::EnvironmentDaytime, false, true, true);
  213. // Add a skybox texture for sky reflections
  214. HSceneObject skyboxSO = SceneObject::create("Skybox");
  215. HSkybox skybox = skyboxSO->addComponent<CSkybox>();
  216. skybox->setTexture(skyCubemap);
  217. /************************************************************************/
  218. /* PARTICLES */
  219. /************************************************************************/
  220. // Set up different particle systems
  221. setup3DParticleEffect(Vector3(-5.0f, 1.0f, 0.0f), assets);
  222. setupGPUParticleEffect(Vector3(0.0f, 1.0f, 0.0f), assets);
  223. setupSmokeEffect(Vector3(5.0f, 0.0f, 0.0f), assets);
  224. /************************************************************************/
  225. /* CURSOR */
  226. /************************************************************************/
  227. // Hide and clip the cursor, since we only use the mouse movement for camera rotation
  228. Cursor::instance().hide();
  229. Cursor::instance().clipToWindow(*window);
  230. /************************************************************************/
  231. /* INPUT */
  232. /************************************************************************/
  233. // Hook up Esc key to quit
  234. gInput().onButtonUp.connect([=](const ButtonEvent& ev)
  235. {
  236. if(ev.buttonCode == BC_ESCAPE)
  237. {
  238. // Quit the application when Escape key is pressed
  239. gApplication().quitRequested();
  240. }
  241. });
  242. }
  243. /**
  244. * Sets up a particle system using traditional billboard particles to render a smoke effect. The particles are emitted
  245. * from the base and distributed towards a cone shape. After emission particle color, size and velocity is modified
  246. * through particle evolvers.
  247. */
  248. void setupSmokeEffect(const Vector3& pos, const ParticleSystemAssets& assets)
  249. {
  250. // Create the particle system scene object and position/orient it
  251. HSceneObject particleSystemSO = SceneObject::create("Smoke");
  252. particleSystemSO->setPosition(pos);
  253. particleSystemSO->setRotation(Quaternion(Degree(0), Degree(90), Degree(90)));
  254. // Add a particle system component
  255. HParticleSystem particleSystem = particleSystemSO->addComponent<CParticleSystem>();
  256. // Set up the emitter
  257. SPtr<ParticleEmitter> emitter = bs_shared_ptr_new<ParticleEmitter>();
  258. // All newly spawned particles will have the size of 1m
  259. emitter->setInitialSize(1.0f);
  260. // 20 particles will be emitted per second
  261. emitter->setEmissionRate(20.0f);
  262. // Particles will initially move at a rate of 1m/s
  263. emitter->setInitialSpeed(1.0f);
  264. // Particles will live for exactly 5 seconds
  265. emitter->setInitialLifetime(5.0f);
  266. // Particles will initially have no tint
  267. emitter->setInitialColor(Color::White);
  268. // Set up a shape that determines the position and initial travel direction of newly spawned particles. In this
  269. // case we're using a cone shape.
  270. PARTICLE_CONE_SHAPE_DESC coneShape;
  271. // All particles will spawn at the narrow point in the cone (position doesn't vary)
  272. coneShape.type = ParticleEmitterConeType::Base;
  273. // The particle travel direction will be in the 10 degrees spawned by the cone
  274. coneShape.angle = Degree(10.0f);
  275. // Assign the shape to the emitter
  276. emitter->setShape(ParticleEmitterConeShape::create(coneShape));
  277. // Assign the emitter to the particle system
  278. particleSystem->setEmitters({emitter});
  279. // Set up evolvers that will modify the particle systems over its lifetime
  280. Vector<SPtr<ParticleEvolver>> evolvers;
  281. // Animate particle texture - this uses the sprite sheet animation set up during the asset loading step
  282. PARTICLE_TEXTURE_ANIMATION_DESC texAnimDesc;
  283. // Perform one animation cycle during the particle lifetime
  284. texAnimDesc.numCycles = 1;
  285. // Create and add the texture animation evolver
  286. SPtr<ParticleEvolver> texAnimEvolver = bs_shared_ptr_new<ParticleTextureAnimation>(texAnimDesc);
  287. evolvers.push_back(texAnimEvolver);
  288. // Scale particles from size 1 to size 4 over their lifetime
  289. PARTICLE_SIZE_DESC sizeDesc;
  290. sizeDesc.size = TAnimationCurve<float>(
  291. {
  292. TKeyframe<float>{1.0f, 0.0f, 1.0f, 0.0f},
  293. TKeyframe<float>{4.0f, 1.0f, 0.0f, 1.0f},
  294. });
  295. // Create and add the size evolver
  296. SPtr<ParticleEvolver> sizeEvolver = bs_shared_ptr_new<ParticleSize>(sizeDesc);
  297. evolvers.push_back(sizeEvolver);
  298. // Modify particle tint from white (no tint) to dark gray over first 40% of their lifetime
  299. PARTICLE_COLOR_DESC colorDesc;
  300. colorDesc.color = ColorGradient(
  301. {
  302. ColorGradientKey(Color::White, 0.0f),
  303. ColorGradientKey(Color(0.1f, 0.1f, 0.1f, 1.0f), 0.4f)
  304. }
  305. );
  306. // Create and add the color evolver
  307. SPtr<ParticleEvolver> colorEvolver = bs_shared_ptr_new<ParticleColor>(colorDesc);
  308. evolvers.push_back(colorEvolver);
  309. // Apply force moving the particles to the right
  310. PARTICLE_FORCE_DESC forceDesc;
  311. forceDesc.force = TAnimationCurve<Vector3>(
  312. {
  313. TKeyframe<Vector3>{Vector3::ZERO, Vector3::ZERO, Vector3::ONE, 0.0f},
  314. TKeyframe<Vector3>{Vector3(100.0f, 0.0f, 0.0f), -Vector3::ONE, Vector3::ZERO, 0.5f},
  315. });
  316. // Lets the system know the provided force direction is in world space
  317. forceDesc.worldSpace = true;
  318. // Create and add the force evolver
  319. SPtr<ParticleEvolver> forceEvolver = bs_shared_ptr_new<ParticleForce>(forceDesc);
  320. evolvers.push_back(forceEvolver);
  321. // Register all the evolvers with the particle system
  322. particleSystem->setEvolvers(evolvers);
  323. // Set up general particle system settings
  324. ParticleSystemSettings psSettings;
  325. // Orient the particles towards the camera plane (standard for billboard particles)
  326. psSettings.orientation = ParticleOrientation::ViewPlane;
  327. // But lock the Y orientation
  328. psSettings.orientationLockY = true;
  329. // Sort based on distance from the camera so that transparency looks appropriate
  330. psSettings.sortMode = ParticleSortMode::Distance;
  331. // Assign the material we created earlier
  332. psSettings.material = assets.smokeMat;
  333. // And actually apply the settings
  334. particleSystem->setSettings(psSettings);
  335. }
  336. /**
  337. * Sets up a particle system using 3D mesh particles. The particles support lighting which is demonstrated via an
  338. * addition of an orbiting point light. Once emitted the particles are evolved through the gravity evolver, ensuring
  339. * they fall down. After which they collide with the ground plane by using the collider evolver.
  340. */
  341. void setup3DParticleEffect(const Vector3& pos, const ParticleSystemAssets& assets)
  342. {
  343. // Create the particle system scene object and position/orient it
  344. HSceneObject particleSystemSO = SceneObject::create("3D particles");
  345. particleSystemSO->setPosition(pos);
  346. particleSystemSO->setRotation(Quaternion(Degree(0), Degree(90), Degree(0)));
  347. // Add a particle system component
  348. HParticleSystem particleSystem = particleSystemSO->addComponent<CParticleSystem>();
  349. // Set up the emitter
  350. SPtr<ParticleEmitter> emitter = bs_shared_ptr_new<ParticleEmitter>();
  351. // All newly spawned particles will have the size of 2cm
  352. emitter->setInitialSize(0.02f);
  353. // 50 particles will be emitted per second
  354. emitter->setEmissionRate(50.0f);
  355. // Particles will initially move at a rate of 1m/s
  356. emitter->setInitialSpeed(1.0f);
  357. // Particles will live for exactly 5 seconds
  358. emitter->setInitialLifetime(5.0f);
  359. // Set up a shape that determines the position and initial travel direction of newly spawned particles. In this
  360. // case we're using a cone shape.
  361. PARTICLE_CONE_SHAPE_DESC coneShape;
  362. // All particles will spawn at the narrow point in the cone (position doesn't vary)
  363. coneShape.type = ParticleEmitterConeType::Base;
  364. // The particle travel direction will be in the 45 degrees spawned by the cone
  365. coneShape.angle = Degree(45.0f);
  366. // Assign the shape to the emitter
  367. emitter->setShape(ParticleEmitterConeShape::create(coneShape));
  368. // Assign the emitter to the particle system
  369. particleSystem->setEmitters({emitter});
  370. // Set up evolvers that will modify the particle systems over its lifetime
  371. Vector<SPtr<ParticleEvolver>> evolvers;
  372. // Set up an evolver at applies gravity to the particles. The gravity as set by the physics system is used, but
  373. // can be scaled as needed
  374. PARTICLE_GRAVITY_DESC gravityDesc;
  375. gravityDesc.scale = 1.0f;
  376. // Create and add the gravity evolver
  377. SPtr<ParticleGravity> gravityEvolver = bs_shared_ptr_new<ParticleGravity>(gravityDesc);
  378. evolvers.push_back(gravityEvolver);
  379. // Set up an evolver that allows the particles to collide with the ground.
  380. PARTICLE_COLLISIONS_DESC collisionsDesc;
  381. // We use plane collisions but we could have also used world collisions (which are more expensive, but perform
  382. // general purpose collisions with all physical objects)
  383. collisionsDesc.mode = ParticleCollisionMode::Plane;
  384. // Set up the particle radius used for collisions (2cm, same as visible size)
  385. collisionsDesc.radius = 0.02f;
  386. // Create the collision evolver
  387. SPtr<ParticleCollisions> collisionEvolver = bs_shared_ptr_new<ParticleCollisions>(collisionsDesc);
  388. // Assign the plane the particles will collide with
  389. collisionEvolver->setPlanes( { Plane(Vector3::UNIT_Y, 0.0f)});
  390. // Register the collision evolver
  391. evolvers.push_back(collisionEvolver);
  392. // Register all evolvers with the particle system
  393. particleSystem->setEvolvers(evolvers);
  394. // Set up general particle system settings
  395. ParticleSystemSettings psSettings;
  396. // Specify that we want to render 3D meshes instead of billboards
  397. psSettings.renderMode = ParticleRenderMode::Mesh;
  398. // Specify the mesh to use for particles
  399. psSettings.mesh = assets.sphereMesh;
  400. // Set up a plain white diffuse material
  401. psSettings.material = assets.particles3DMat;
  402. // And actually apply the settings
  403. particleSystem->setSettings(psSettings);
  404. // Set up an orbiting light
  405. //// Create the scene object, position and scale it
  406. HSceneObject lightSO = SceneObject::create("Radial light");
  407. lightSO->setPosition(pos - Vector3(0.0f, 0.8f, 0.0f));
  408. lightSO->setScale(Vector3::ONE * 0.02f);
  409. //// Add the light component, emitting a red light
  410. HLight light = lightSO->addComponent<CLight>();
  411. light->setIntensity(30.0f);
  412. light->setColor(Color::Red);
  413. light->setUseAutoAttenuation(false);
  414. light->setAttenuationRadius(20.0f);
  415. //// Add a sphere using an emissive material to represent the light
  416. HRenderable lightSphere = lightSO->addComponent<CRenderable>();
  417. lightSphere->setMesh(assets.sphereMesh);
  418. lightSphere->setMaterial(assets.lightMat);
  419. //// Add a component that orbits the light at 1m of its original position
  420. lightSO->addComponent<LightOrbit>(1.0f);
  421. }
  422. /**
  423. * Sets up a particle system that uses the GPU particle simulation. Particles are spawned on a surface of a sphere and
  424. * a vector field is used for evolving the particles during their lifetime.
  425. */
  426. void setupGPUParticleEffect(const Vector3& pos, const ParticleSystemAssets& assets)
  427. {
  428. // Create the particle system scene object and position/orient it
  429. HSceneObject particleSystemSO = SceneObject::create("Vector field");
  430. particleSystemSO->setPosition(pos);
  431. // Add a particle system component
  432. HParticleSystem particleSystem = particleSystemSO->addComponent<CParticleSystem>();
  433. // Set up the emitter
  434. SPtr<ParticleEmitter> emitter = bs_shared_ptr_new<ParticleEmitter>();
  435. // All newly spawned particles will have the size of 1cm
  436. emitter->setInitialSize(0.01f);
  437. // 400 particles will be emitted per second
  438. emitter->setEmissionRate(400.0f);
  439. // No initial speed, we'll rely purely on the vector field force to move the particles
  440. emitter->setInitialSpeed(0.0f);
  441. // Particles will live for exactly 5 seconds
  442. emitter->setInitialLifetime(5.0f);
  443. // Set up a shape that determines the position of newly spawned particles. In this case spawn particles randomly
  444. // on a surface of a sphere.
  445. PARTICLE_SPHERE_SHAPE_DESC sphereShape;
  446. // Spawn on a sphere with radius of 30 cm
  447. sphereShape.radius = 0.3f;
  448. // Assign the shape to the emitter
  449. emitter->setShape(ParticleEmitterSphereShape::create(sphereShape));
  450. // Assign the emitter to the particle system
  451. particleSystem->setEmitters({emitter});
  452. // Set up general particle system settings
  453. ParticleSystemSettings psSettings;
  454. // Orient the particles towards the camera plane (standard for billboard particles)
  455. psSettings.orientation = ParticleOrientation::ViewPlane;
  456. // But lock the Y orientation
  457. psSettings.orientationLockY = true;
  458. // Sort by distance from camera so that transparency renders properly
  459. psSettings.sortMode = ParticleSortMode::Distance;
  460. // Use an emissive material to render the particles
  461. psSettings.material = assets.litParticleEmissiveMat;
  462. // Actually enable the GPU simulation
  463. psSettings.gpuSimulation = true;
  464. // Increase the maximum particle count since we'll be emitting them quickly
  465. psSettings.maxParticles = 10000;
  466. // And actually apply the general settings
  467. particleSystem->setSettings(psSettings);
  468. // Set up settings specific to the GPU simulation
  469. ParticleGpuSimulationSettings gpuSimSettings;
  470. // Set up a vector field. Use the vector field resource we imported earlier
  471. gpuSimSettings.vectorField.vectorField = assets.vectorField;
  472. // Increase the intensity of the forces in the vector field
  473. gpuSimSettings.vectorField.intensity = 3.0f;
  474. // Setting this to zero ensures the vector field only applies forces, not velocities, to the particles
  475. gpuSimSettings.vectorField.tightness = 0.0f;
  476. // And actually apply the GPU simulation settings
  477. particleSystem->setGpuSimulationSettings(gpuSimSettings);
  478. }
  479. }
  480. /** Main entry point into the application. */
  481. #if BS_PLATFORM == BS_PLATFORM_WIN32
  482. #include <windows.h>
  483. int CALLBACK WinMain(
  484. _In_ HINSTANCE hInstance,
  485. _In_ HINSTANCE hPrevInstance,
  486. _In_ LPSTR lpCmdLine,
  487. _In_ int nCmdShow
  488. )
  489. #else
  490. int main()
  491. #endif
  492. {
  493. using namespace bs;
  494. // Initializes the application and creates a window with the specified properties
  495. VideoMode videoMode(windowResWidth, windowResHeight);
  496. Application::startUp(videoMode, "Example", false);
  497. // Registers a default set of input controls
  498. ExampleFramework::setupInputConfig();
  499. // Set up the scene with an object to render and a camera
  500. setUpScene();
  501. // Runs the main loop that does most of the work. This method will exit when user closes the main
  502. // window or exits in some other way.
  503. Application::instance().runMainLoop();
  504. // When done, clean up
  505. Application::shutDown();
  506. return 0;
  507. }