// Framework includes #include "BsApplication.h" #include "Resources/BsResources.h" #include "Resources/BsBuiltinResources.h" #include "Material/BsMaterial.h" #include "Components/BsCCamera.h" #include "Components/BsCRenderable.h" #include "Components/BsCSkybox.h" #include "Components/BsCPlaneCollider.h" #include "Components/BsCBoxCollider.h" #include "Components/BsCCharacterController.h" #include "Components/BsCRigidbody.h" #include "Physics/BsPhysicsMaterial.h" #include "RenderAPI/BsRenderAPI.h" #include "RenderAPI/BsRenderWindow.h" #include "Scene/BsSceneObject.h" #include "Input/BsInput.h" #include "Components/BsCDecal.h" // Example includes #include "BsExampleFramework.h" #include "BsFPSWalker.h" #include "BsFPSCamera.h" //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This example sets up a simple environment consisting of a floor and cube, and a decal projecting on both surfaces. The // example demonstrates how to set up decals, how decals are not shown on surfaces perpendicular to the decal direction, // and optionally how to use masking to only project a decal onto a certain set of surfaces. // // It also sets up necessary physical objects for collision, as well as the character collider and necessary components // for walking around the environment. // // The example first sets up the scene consisting of a floor, box and a skybox. Character controller is created next, // as well as the camera. Components for moving the character controller and the camera are attached to allow the user to // control the character. It then loads the required decal textures, sets up a decal material and initializes the actual // decal component. Finally the cursor is hidden and quit on Esc key press hooked up. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// namespace bs { constexpr float GROUND_PLANE_SCALE = 50.0f; UINT32 windowResWidth = 1280; UINT32 windowResHeight = 720; SPtr decal; /** Set up the scene used by the example, and the camera to view the world through. */ void setUpScene() { /************************************************************************/ /* ASSETS */ /************************************************************************/ // Prepare all the resources we'll be using throughout this example // Grab a couple of test textures that we'll apply to the rendered objects HTexture gridPattern = ExampleFramework::loadTexture(ExampleTexture::GridPattern); HTexture gridPattern2 = ExampleFramework::loadTexture(ExampleTexture::GridPattern2); // Grab the default PBR shader HShader shader = gBuiltinResources().getBuiltinShader(BuiltinShader::Standard); // Create a set of materials to apply to renderables used HMaterial planeMaterial = Material::create(shader); planeMaterial->setTexture("gAlbedoTex", gridPattern2); // Tile the texture so every tile covers a 2x2m area planeMaterial->setVec2("gUVTile", Vector2::ONE * GROUND_PLANE_SCALE * 0.5f); // Load meshes we'll used for our rendered objects HMesh planeMesh = gBuiltinResources().getMesh(BuiltinMesh::Quad); /************************************************************************/ /* FLOOR */ /************************************************************************/ // Set up renderable geometry for the floor plane HSceneObject floorSO = SceneObject::create("Floor"); HRenderable floorRenderable = floorSO->addComponent(); floorRenderable->setMesh(planeMesh); floorRenderable->setMaterial(planeMaterial); floorSO->setScale(Vector3(GROUND_PLANE_SCALE, 1.0f, GROUND_PLANE_SCALE)); // Add a plane collider that will prevent physical objects going through the floor HPlaneCollider planeCollider = floorSO->addComponent(); HMaterial boxMaterial = Material::create(shader); boxMaterial->setTexture("gAlbedoTex", gridPattern); HMaterial sphereMaterial = Material::create(shader); // Load meshes we'll used for our rendered objects HMesh boxMesh = gBuiltinResources().getMesh(BuiltinMesh::Box); HSceneObject boxSO = SceneObject::create("Box"); HRenderable boxRenderable = boxSO->addComponent(); boxRenderable->setMesh(boxMesh); boxRenderable->setMaterial(boxMaterial); // Set a non-default layer for the box, so we can use it for masking on which surfaces should the decal be // projected onto boxRenderable->setLayer(1 << 1); boxSO->setPosition(Vector3(0.0f, 0.5f, 0.5f)); /************************************************************************/ /* CHARACTER */ /************************************************************************/ // Add physics geometry and components for character movement and physics interaction HSceneObject characterSO = SceneObject::create("Character"); characterSO->setPosition(Vector3(0.0f, 1.0f, 5.0f)); // Add a character controller, representing the physical geometry of the character HCharacterController charController = characterSO->addComponent(); // Make the character about 1.8m high, with 0.4m radius (controller represents a capsule) charController->setHeight(1.0f); // + 0.4 * 2 radius = 1.8m height charController->setRadius(0.4f); // FPS walker uses default input controls to move the character controller attached to the same object characterSO->addComponent(); /************************************************************************/ /* CAMERA */ /************************************************************************/ // In order something to render on screen we need at least one camera. // Like before, we create a new scene object at (0, 0, 0). HSceneObject sceneCameraSO = SceneObject::create("SceneCamera"); // Get the primary render window we need for creating the camera. SPtr window = gApplication().getPrimaryWindow(); // Add a Camera component that will output whatever it sees into that window // (You could also use a render texture or another window you created). HCamera sceneCamera = sceneCameraSO->addComponent(); sceneCamera->getViewport()->setTarget(window); // Set up camera component properties // Set closest distance that is visible. Anything below that is clipped. sceneCamera->setNearClipDistance(0.005f); // Set farthest distance that is visible. Anything above that is clipped. sceneCamera->setFarClipDistance(1000); // Set aspect ratio depending on the current resolution sceneCamera->setAspectRatio(windowResWidth / (float)windowResHeight); // Add a component that allows the camera to be rotated using the mouse sceneCameraSO->setRotation(Quaternion(Degree(-10.0f), Degree(0.0f), Degree(0.0f))); HFPSCamera fpsCamera = sceneCameraSO->addComponent(); // Set the character controller on the FPS camera, so the component can apply yaw rotation to it fpsCamera->setCharacter(characterSO); // Make the camera a child of the character scene object, and position it roughly at eye level sceneCameraSO->setParent(characterSO); sceneCameraSO->setPosition(Vector3(0.0f, 1.8f * 0.5f - 0.1f, -2.0f)); /************************************************************************/ /* SKYBOX */ /************************************************************************/ // Load a skybox texture HTexture skyCubemap = ExampleFramework::loadTexture(ExampleTexture::EnvironmentDaytime, false, true, true); // Add a skybox texture for sky reflections HSceneObject skyboxSO = SceneObject::create("Skybox"); HSkybox skybox = skyboxSO->addComponent(); skybox->setTexture(skyCubemap); /************************************************************************/ /* DECAL */ /************************************************************************/ // Load the decal textures HTexture decalAlbedoTex = ExampleFramework::loadTexture(ExampleTexture::DecalAlbedo); HTexture decalNormalTex = ExampleFramework::loadTexture(ExampleTexture::DecalNormal, false); // Create a material using the built-in decal shader and assign the textures HShader decalShader = gBuiltinResources().getBuiltinShader(BuiltinShader::Decal); HMaterial decalMaterial = Material::create(decalShader); decalMaterial->setTexture("gAlbedoTex", decalAlbedoTex); decalMaterial->setTexture("gNormalTex", decalNormalTex); decalMaterial->setVariation(ShaderVariation( { // Use the default, transparent blend mode that uses traditional PBR textures to project. Normally no need // to set the default explicitly but it's done here for example purposes. See the manual for all available // modes ShaderVariation::Param("BLEND_MODE", 0) }) ); // Create the decal scene object, position and orient it, facing down HSceneObject decalSO = SceneObject::create("Decal"); decalSO->setPosition(Vector3(0.0f, 6.0f, 1.0f)); decalSO->lookAt(Vector3(0.0f, 0.0f, 1.0f)); // Set the material to project HDecal decal = decalSO->addComponent(); decal->setMaterial(decalMaterial); // Optionally set a mask to only project onto elements with layer 1 set (in this case this is the floor since we // changed the default layer for the box) // decal->setLayerMask(1); /************************************************************************/ /* INPUT */ /************************************************************************/ // Hook up input that launches a sphere when user clicks the mouse, and Esc key to quit gInput().onButtonUp.connect([=](const ButtonEvent& ev) { if(ev.buttonCode == BC_ESCAPE) { // Quit the application when Escape key is pressed gApplication().quitRequested(); } }); } } /** Main entry point into the application. */ #if BS_PLATFORM == BS_PLATFORM_WIN32 #include int CALLBACK WinMain( _In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow ) #else int main() #endif { using namespace bs; // Initializes the application and creates a window with the specified properties VideoMode videoMode(windowResWidth, windowResHeight); Application::startUp(videoMode, "Example", false); // Registers a default set of input controls ExampleFramework::setupInputConfig(); // Set up the scene with an object to render and a camera setUpScene(); // Runs the main loop that does most of the work. This method will exit when user closes the main // window or exits in some other way. Application::instance().runMainLoop(); // When done, clean up Application::shutDown(); return 0; }