feat: add debug rendering for other types of colliders / split game into more logical functions / files
This commit is contained in:
@@ -0,0 +1,292 @@
|
||||
// Old scene setup experiments, moved here from LightKeeper::customInit as reference.
|
||||
// They were written against older APIs (scene.Add, gfxDevice.loadImageFromFile, ...) and the locals
|
||||
// of customInit (planeModel, staticModelOptions, sphereMesh, ...), so they don't compile as is.
|
||||
#if 0
|
||||
|
||||
// ---- Skybox images that were tried --------------------------------------------------------------
|
||||
|
||||
// scene.Add(testCube);
|
||||
|
||||
// const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/skybox.jpg");
|
||||
// const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/mars.jpg");
|
||||
// const auto skyboxID = AssetFS::GetInstance().GetCookedPathForFile("game://starmap_2020_4k.exr");
|
||||
//
|
||||
// const auto skyboxID = AssetFS::GetInstance().GetFullPath("engine://textures/test-skybox.png");
|
||||
|
||||
// ---- Capybara texture -----------------------------------------------------------------------------
|
||||
|
||||
// const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
|
||||
|
||||
// ---- Multi mesh model, one GameObject per primitive ----------------------------------------------
|
||||
|
||||
// ModelDoc::LoadOptions options{};
|
||||
// options.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
|
||||
//
|
||||
// auto model = ModelDoc::LoadModel(
|
||||
// AssetFS::GetInstance()
|
||||
// .GetFullPath("engine://multiple_object_test.fbx")
|
||||
// .generic_string(),
|
||||
// options
|
||||
// );
|
||||
//
|
||||
// ModelDocUtils::LogModelDocSummary(model, "engine://multiple_object_test.fbx");
|
||||
//
|
||||
// auto root = std::make_shared<GameObject>("MultiMeshModel");
|
||||
// root->GetTransform().SetWorldPosition(glm::vec3(0.1f, 0.1f, 0.1f));
|
||||
// scene.Add(root);
|
||||
//
|
||||
// for (std::size_t i = 0; i < model.primitives.size(); ++i) {
|
||||
// const auto &primitive = model.primitives[i];
|
||||
//
|
||||
// const auto meshID = meshCache.addMesh(gfxDevice, primitive.mesh);
|
||||
//
|
||||
// const auto texturePath = ModelDocUtils::PickTexturePath(
|
||||
// model,
|
||||
// primitive,
|
||||
// AssetFS::GetInstance().GetFullPath("engine://textures/white.png")
|
||||
// );
|
||||
//
|
||||
// const auto textureID = gfxDevice.loadImageFromFile(texturePath);
|
||||
//
|
||||
// const auto materialID = materialCache.addMaterial(gfxDevice, {
|
||||
// .baseColor = ModelDocUtils::GetImportedBaseColor(
|
||||
// model, primitive),
|
||||
// .diffuseTexture = textureID,
|
||||
// .name = ModelDocUtils::GetImportedMaterialName(
|
||||
// model,
|
||||
// primitive,
|
||||
// primitive.mesh.name + "_Material"
|
||||
// ),
|
||||
// });
|
||||
//
|
||||
// auto part = std::make_shared<GameObject>(
|
||||
// primitive.mesh.name.empty()
|
||||
// ? "Primitive_" + std::to_string(i)
|
||||
// : primitive.mesh.name
|
||||
// );
|
||||
//
|
||||
// auto meshComp = part->AddComponent<MeshRendererComponent>();
|
||||
// meshComp->SetMeshID(meshID);
|
||||
// meshComp->SetMaterialID(materialID);
|
||||
//
|
||||
// scene.Add(part);
|
||||
// }
|
||||
|
||||
// ---- characterMedium with run.fbx animations -----------------------------------------------------
|
||||
|
||||
// {
|
||||
// const auto CharObj = scene.CreateGameObject("Character");
|
||||
//
|
||||
// ModelDoc::LoadOptions characterOptions{};
|
||||
// characterOptions.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
|
||||
// characterOptions.loadMaterials = true;
|
||||
// characterOptions.loadSkeleton = true;
|
||||
// characterOptions.loadAnimations = false;
|
||||
//
|
||||
// auto charModel = AssetManager::GetInstance().LoadModel("engine://characterMedium.fbx", characterOptions);
|
||||
//
|
||||
// const auto& charPrimitive =
|
||||
// ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
|
||||
// charModel,
|
||||
// "engine://characterMedium.fbx"
|
||||
// );
|
||||
//
|
||||
// const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
|
||||
//
|
||||
// const auto charTextureID = resources.loadImageFromFile(gfxDevice,
|
||||
// AssetFS::GetInstance().GetFullPath("engine://textures/criminalMaleA.png")
|
||||
// );
|
||||
//
|
||||
// const auto charMaterialID = resources.materials().addMaterial({
|
||||
// .baseColor = ModelDocUtils::GetImportedBaseColor(
|
||||
// charModel, charPrimitive),
|
||||
// .diffuseTexture = charTextureID,
|
||||
// .name = ModelDocUtils::GetImportedMaterialName(
|
||||
// charModel,
|
||||
// charPrimitive,
|
||||
// "CharacterMaterial"
|
||||
// ),
|
||||
// });
|
||||
//
|
||||
// const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
|
||||
// charMeshComp->SetMeshID(charMeshID);
|
||||
// charMeshComp->SetMaterialID(charMaterialID);
|
||||
//
|
||||
// const auto animator = CharObj->AddComponent<Animator>();
|
||||
// animator->setSkeleton(charModel.skeleton);
|
||||
//
|
||||
// auto runClips = AssetManager::GetInstance().LoadAnimationClips(
|
||||
// "engine://run.fbx",
|
||||
// charModel.skeleton
|
||||
// );
|
||||
//
|
||||
// for (auto& clip : runClips)
|
||||
// {
|
||||
// spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
|
||||
// animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
|
||||
// }
|
||||
//
|
||||
// if (!runClips.empty())
|
||||
// {
|
||||
// animator->play("Root|Run");
|
||||
// }
|
||||
//
|
||||
// CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f));
|
||||
// CharObj->GetTransform().SetWorldPosition(glm::vec3(5, 0, 0));
|
||||
// }
|
||||
|
||||
// ---- Physics cube stacks -------------------------------------------------------------------------
|
||||
|
||||
// auto cubeModel = ModelDoc::LoadModel(
|
||||
// AssetFS::GetInstance()
|
||||
// .GetFullPath("engine://cube.fbx")
|
||||
// .generic_string(),
|
||||
// staticModelOptions
|
||||
// );
|
||||
// ModelDocUtils::LogModelDocSummary(cubeModel, "cube.fbx");
|
||||
//
|
||||
// const auto& cubePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(cubeModel, "game://cube.fbx");
|
||||
//
|
||||
//
|
||||
// const auto eliasTextuerPath = ModelDocUtils::PickTexturePath(
|
||||
// cubeModel,
|
||||
// cubePrimitive,
|
||||
// AssetFS::GetInstance().GetFullPath("game://grass.png")
|
||||
// );
|
||||
//
|
||||
// const auto eliasTextueID = resources.loadImageFromFile(gfxDevice, eliasTextuerPath);
|
||||
// const auto eliasMaterialID = resources.materials().addMaterial({
|
||||
// .baseColor = ModelDocUtils::GetImportedBaseColor(
|
||||
// planeModel, planePrimitive),
|
||||
// .textureFilteringMode =
|
||||
// TextureFilteringMode::Anisotropic,
|
||||
// .diffuseTexture = eliasTextueID,
|
||||
// .name = ModelDocUtils::GetImportedMaterialName(
|
||||
// planeModel, planePrimitive, "GroundPlaneMaterial"),
|
||||
// });
|
||||
//
|
||||
// const auto cubeMeshID = resources.meshes().addMesh(gfxDevice, cubePrimitive.mesh);
|
||||
// //
|
||||
// // for (int i{0}; i < 100; i++)
|
||||
// // {
|
||||
// // auto cube = std::make_shared<GameObject>("Cube");
|
||||
// //
|
||||
// // cube->AddComponent<BoxCollider>(glm::vec3{0.5f});
|
||||
// // cube->AddComponent<Rigidbody>();
|
||||
// //
|
||||
// // auto meshComp = cube->AddComponent<MeshRendererComponent>();
|
||||
// // meshComp->SetMeshID(cubeMeshID);
|
||||
// // meshComp->SetMaterialID(eliasMaterialID);
|
||||
// //
|
||||
// // cube->GetTransform().SetWorldPosition(glm::vec3(0.0f, i, 0.0f));
|
||||
// // cube->GetTransform().SetWorldScale(glm::vec3(0.005f));
|
||||
// //
|
||||
// // scene.Add(cube);
|
||||
// // scene.GetPhysics().RegisterGameObject(*cube);
|
||||
// // }
|
||||
//
|
||||
// // const int cubeCount = 10;
|
||||
// // const float spacing = 1.0f;
|
||||
// //
|
||||
// // for (int x = 0; x < cubeCount; x++)
|
||||
// // {
|
||||
// // for (int y = 0; y < 3; y++)
|
||||
// // {
|
||||
// // for (int z = 0; z < cubeCount; z++)
|
||||
// // {
|
||||
// // auto cube = std::make_shared<GameObject>("Cube");
|
||||
// //
|
||||
// // cube->AddComponent<BoxCollider>(glm::vec3{0.5f});
|
||||
// // cube->AddComponent<Rigidbody>();
|
||||
// //
|
||||
// // auto meshComp = cube->AddComponent<MeshRendererComponent>();
|
||||
// // meshComp->SetMeshID(cubeMeshID);
|
||||
// // meshComp->SetMaterialID(eliasMaterialID);
|
||||
// //
|
||||
// // cube->GetTransform().SetWorldPosition(glm::vec3(
|
||||
// // (x - cubeCount / 2.0f) * spacing,
|
||||
// // y * spacing + 0,
|
||||
// // (z - cubeCount / 2.0f) * spacing
|
||||
// // ));
|
||||
// //
|
||||
// // cube->GetTransform().SetWorldScale(glm::vec3(0.005f));
|
||||
// //
|
||||
// // scene.Add(cube);
|
||||
// // scene.GetPhysics().RegisterGameObject(*cube);
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
|
||||
// ---- Textured sphere material --------------------------------------------------------------------
|
||||
|
||||
// const auto sphereTexturePath = ModelDocUtils::PickTexturePath(
|
||||
// sphereModel,
|
||||
// spherePrimitive,
|
||||
// AssetFS::GetInstance().GetFullPath("game://238882.png")
|
||||
// );
|
||||
//
|
||||
// const auto sphereTextureID = resources.loadImageFromFile(gfxDevice, sphereTexturePath);
|
||||
// sphereMaterial = resources.materials().addMaterial({
|
||||
// .baseColor = ModelDocUtils::GetImportedBaseColor(planeModel, planePrimitive),
|
||||
// .textureFilteringMode =TextureFilteringMode::Anisotropic,
|
||||
// .diffuseTexture = sphereTextureID,
|
||||
// .name = ModelDocUtils::GetImportedMaterialName(
|
||||
// planeModel, planePrimitive,
|
||||
// "GroundPlaneMaterial"),
|
||||
// });
|
||||
|
||||
// ---- Forward+ test lights: a dim sun and a ring of colored point lights orbiting the origin -------
|
||||
|
||||
// auto sunObj = scene.CreateGameObject("Sun");
|
||||
// auto* sun = sunObj->AddComponent<LightComponent>(LightType::Directional);
|
||||
// sun->SetColor(glm::vec3{1.0f, 0.95f, 0.85f});
|
||||
// sun->SetIntensity(1.0f);
|
||||
// sun->SetCastShadows(true);
|
||||
// sunObj->GetTransform().SetWorldRotation(glm::vec3{-50.0f, 30.0f, 0.0f});
|
||||
//
|
||||
// // static shadow casters, so the sun's shadows are visible without spawning balls
|
||||
// for (int i = 0; i < 3; i++)
|
||||
// {
|
||||
// auto casterObj = scene.CreateGameObject("ShadowCaster " + std::to_string(i));
|
||||
// auto* casterMesh = casterObj->AddComponent<MeshRendererComponent>();
|
||||
// casterMesh->SetMeshID(sphereMesh);
|
||||
// casterMesh->SetMaterialID(sphereMaterial);
|
||||
// casterObj->GetTransform().SetWorldPosition(glm::vec3{-4.0f + 4.0f * static_cast<float>(i), 0.5f, 3.0f});
|
||||
// casterObj->GetTransform().SetWorldScale(glm::vec3{0.015f});
|
||||
// }
|
||||
//
|
||||
// constexpr int pointLightCount = 32;
|
||||
// constexpr float pointLightRingRadius = 6.0f;
|
||||
// for (int i = 0; i < pointLightCount; i++)
|
||||
// {
|
||||
// const float t = static_cast<float>(i) / static_cast<float>(pointLightCount);
|
||||
// const float angle = t * glm::two_pi<float>();
|
||||
//
|
||||
// auto lightObj = scene.CreateGameObject("PointLight " + std::to_string(i));
|
||||
// lightObj->GetTransform().SetWorldPosition(glm::vec3{
|
||||
// std::cos(angle) * pointLightRingRadius,
|
||||
// -0.25f,
|
||||
// std::sin(angle) * pointLightRingRadius
|
||||
// });
|
||||
//
|
||||
// auto* light = lightObj->AddComponent<LightComponent>(LightType::Point);
|
||||
// light->SetColor(glm::vec3{
|
||||
// 0.5f + 0.5f * std::cos(glm::two_pi<float>() * t),
|
||||
// 0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.33f)),
|
||||
// 0.5f + 0.5f * std::cos(glm::two_pi<float>() * (t + 0.67f))
|
||||
// });
|
||||
// light->SetIntensity(1.0f);
|
||||
// light->SetRange(3.0f);
|
||||
//
|
||||
// auto* orbit = lightObj->AddComponent<Rotator>(pointLightRingRadius, 0.5f);
|
||||
// orbit->SetAxis(glm::vec3{0.0f, 1.0f, 0.0f});
|
||||
// orbit->SetPivotPosition(glm::vec3{0.0f, -0.25f, 0.0f});
|
||||
// }
|
||||
|
||||
// ---- customCleanup ---------------------------------------------------------------------------------
|
||||
|
||||
// auto device = gfxDevice.getDevice().device;
|
||||
|
||||
// vkDeviceWaitIdle(device);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,289 @@
|
||||
#include <scenes/MainScene.h>
|
||||
|
||||
#include <destrum/Assets/AssetManager.h>
|
||||
#include <destrum/Components/Animator.h>
|
||||
#include <destrum/Components/LightComponent.h>
|
||||
#include <destrum/Components/MeshRendererComponent.h>
|
||||
#include <destrum/Components/Physics/BoxCollider.h>
|
||||
#include <destrum/Components/Physics/CapsuleCollider.h>
|
||||
#include <destrum/Components/Physics/Rigidbody.h>
|
||||
#include <destrum/FS/AssetFS.h>
|
||||
#include <destrum/Graphics/RenderResources.h>
|
||||
#include <destrum/Graphics/Resources/PrimitiveMeshes.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/Scene/ModelSpawner.h>
|
||||
#include <destrum/Scene/Scene.h>
|
||||
#include <destrum/Util/ModelDocUtils.h>
|
||||
|
||||
#include <components/FirstPersonController.h>
|
||||
#include <components/TriggerLoggerComponent.h>
|
||||
|
||||
#include <glm/gtc/constants.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
// The visible ground plane is at y = -1
|
||||
constexpr float GroundHeight = -1.0f;
|
||||
|
||||
ModelDoc::LoadOptions StaticModelOptions()
|
||||
{
|
||||
ModelDoc::LoadOptions options{};
|
||||
options.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
|
||||
options.loadMaterials = true;
|
||||
options.loadSkeleton = false;
|
||||
options.loadAnimations = false;
|
||||
return options;
|
||||
}
|
||||
|
||||
void CreateSun(Scene& scene)
|
||||
{
|
||||
// Directional lights shine down their local -Z: tilt it 50 degrees down, then turn it around the up axis
|
||||
GameObject* sunObj = scene.CreateGameObject("Sun");
|
||||
sunObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 10.f, 0.f));
|
||||
sunObj->GetTransform().SetWorldRotation(
|
||||
glm::angleAxis(glm::radians(35.f), glm::vec3{0.f, 1.f, 0.f}) *
|
||||
glm::angleAxis(glm::radians(-50.f), glm::vec3{1.f, 0.f, 0.f}));
|
||||
|
||||
auto* sun = sunObj->AddComponent<LightComponent>(LightType::Directional);
|
||||
sun->SetColor(glm::vec3{1.0f, 0.95f, 0.85f});
|
||||
sun->SetIntensity(3.0f);
|
||||
sun->SetCastShadows(true);
|
||||
}
|
||||
|
||||
void CreateGround(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources)
|
||||
{
|
||||
const auto planeModel = AssetManager::GetInstance().LoadModel("game://plane.glb", StaticModelOptions());
|
||||
ModelDocUtils::LogModelDocSummary(planeModel, "plane.glb");
|
||||
const auto& planePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(planeModel, "game://plane.glb");
|
||||
|
||||
const auto planeTexturePath = ModelDocUtils::PickTexturePath(
|
||||
planeModel,
|
||||
planePrimitive,
|
||||
AssetFS::GetInstance().GetCookedPathForFile("engine://grass.jpg"));
|
||||
|
||||
const MaterialID planeMaterialID = resources.materials().addMaterial({
|
||||
.baseColor = ModelDocUtils::GetImportedBaseColor(planeModel, planePrimitive),
|
||||
.textureFilteringMode = TextureFilteringMode::Nearest,
|
||||
.diffuseTexture = resources.loadImageFromFile(gfxDevice, planeTexturePath),
|
||||
.name = ModelDocUtils::GetImportedMaterialName(planeModel, planePrimitive, "GroundPlaneMaterial"),
|
||||
});
|
||||
|
||||
GameObject* planeObj = scene.CreateGameObject("GroundPlane");
|
||||
auto* planeMeshComp = planeObj->AddComponent<MeshRendererComponent>();
|
||||
planeMeshComp->SetMeshID(resources.meshes().addMesh(gfxDevice, planePrimitive.mesh));
|
||||
planeMeshComp->SetMaterialID(planeMaterialID);
|
||||
planeObj->GetTransform().SetWorldPosition(glm::vec3(0.f, GroundHeight, 0.f));
|
||||
planeObj->GetTransform().SetWorldScale(glm::vec3(10.f, 1.f, 10.f));
|
||||
|
||||
// The plane mesh is flat, so the floor collider sits right below it
|
||||
GameObject* groundObj = scene.CreateGameObject("GroundCollider");
|
||||
groundObj->GetTransform().SetWorldPosition(glm::vec3(0.f, GroundHeight - 0.5f, 0.f));
|
||||
groundObj->AddComponent<BoxCollider>(glm::vec3{10.0f, 0.5f, 10.0f});
|
||||
groundObj->AddComponent<Rigidbody>()->SetType(RigidbodyType::Static);
|
||||
scene.GetPhysics().RegisterGameObject(*groundObj);
|
||||
}
|
||||
|
||||
// Kenney prototype textures, texture_01 is a 1 x 1 meter grid
|
||||
MaterialID AddPrototypeMaterial(GfxDevice& gfxDevice, RenderResources& resources,
|
||||
const std::string& color, float roughness)
|
||||
{
|
||||
Material material = Material::SimpleColor(glm::vec3{1.0f}, "Prototype" + color);
|
||||
material.roughnessFactor = roughness;
|
||||
material.textureFilteringMode = TextureFilteringMode::Anisotropic;
|
||||
material.diffuseTexture = resources.loadImageFromFile(
|
||||
gfxDevice, AssetFS::GetInstance().GetFullPath("engine://kenny/" + color + "/texture_01.png"));
|
||||
return resources.materials().addMaterial(std::move(material));
|
||||
}
|
||||
|
||||
GameObject* CreateBox(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources,
|
||||
const std::string& name, const glm::vec3& position, const glm::vec3& size,
|
||||
MaterialID materialID, RigidbodyType type)
|
||||
{
|
||||
GameObject* box = scene.CreateGameObject(name);
|
||||
box->GetTransform().SetWorldPosition(position);
|
||||
|
||||
auto* boxMeshComp = box->AddComponent<MeshRendererComponent>();
|
||||
boxMeshComp->SetMeshID(resources.meshes().addMesh(gfxDevice, PrimitiveMeshes::MakeBox(size)));
|
||||
boxMeshComp->SetMaterialID(materialID);
|
||||
|
||||
box->AddComponent<BoxCollider>(size * 0.5f);
|
||||
auto* boxRb = box->AddComponent<Rigidbody>();
|
||||
boxRb->SetType(type);
|
||||
boxRb->SetMass(10.0f);
|
||||
scene.GetPhysics().RegisterGameObject(*box);
|
||||
return box;
|
||||
}
|
||||
|
||||
// Every platform is reachable with a jump from the previous one
|
||||
void CreateParkourCourse(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources)
|
||||
{
|
||||
const MaterialID platformMaterial = AddPrototypeMaterial(gfxDevice, resources, "Orange", 0.6f);
|
||||
const MaterialID goalMaterial = AddPrototypeMaterial(gfxDevice, resources, "Green", 0.6f);
|
||||
const MaterialID wallMaterial = AddPrototypeMaterial(gfxDevice, resources, "Dark", 0.9f);
|
||||
const MaterialID crateMaterial = AddPrototypeMaterial(gfxDevice, resources, "Purple", 0.35f);
|
||||
|
||||
// Platforms stand on the ground and are given by their top height
|
||||
const auto createPlatform = [&](const std::string& name, const glm::vec2& center, float top,
|
||||
const glm::vec2& footprint, MaterialID materialID)
|
||||
{
|
||||
const float height = top - GroundHeight;
|
||||
CreateBox(scene, gfxDevice, resources, name,
|
||||
glm::vec3{center.x, top - height * 0.5f, center.y},
|
||||
glm::vec3{footprint.x, height, footprint.y},
|
||||
materialID, RigidbodyType::Static);
|
||||
};
|
||||
createPlatform("Parkour_Step", {0.0f, 4.0f}, -0.5f, {2.0f, 2.0f}, platformMaterial);
|
||||
createPlatform("Parkour_Block", {0.0f, 7.0f}, 0.4f, {2.0f, 2.0f}, platformMaterial);
|
||||
createPlatform("Parkour_Pillar1", {3.5f, 8.5f}, 1.2f, {1.5f, 1.5f}, platformMaterial);
|
||||
createPlatform("Parkour_Pillar2", {6.5f, 7.5f}, 2.0f, {1.2f, 1.2f}, platformMaterial);
|
||||
CreateBox(scene, gfxDevice, resources, "Parkour_Beam", {6.5f, 1.85f, 4.0f}, {0.6f, 0.3f, 5.0f},
|
||||
platformMaterial, RigidbodyType::Static);
|
||||
createPlatform("Parkour_Goal", {6.5f, -0.5f}, 2.8f, {2.5f, 2.5f}, goalMaterial);
|
||||
|
||||
CreateBox(scene, gfxDevice, resources, "Wall", {-5.0f, 0.5f, 0.0f}, {0.5f, 3.0f, 8.0f},
|
||||
wallMaterial, RigidbodyType::Static);
|
||||
CreateBox(scene, gfxDevice, resources, "LowWall", {-2.5f, -0.6f, -4.0f}, {4.0f, 0.8f, 0.4f},
|
||||
wallMaterial, RigidbodyType::Static);
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
CreateBox(scene, gfxDevice, resources, "Crate" + std::to_string(i),
|
||||
{-2.5f, -0.6f + 0.81f * static_cast<float>(i), 2.0f},
|
||||
glm::vec3{0.8f}, crateMaterial, RigidbodyType::Dynamic);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateFlightHelmet(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources)
|
||||
{
|
||||
GameObject* helmetObj = ModelSpawner::SpawnStaticModel(
|
||||
scene, gfxDevice, resources,
|
||||
"engine://flight-helmet/FlightHelmet.gltf",
|
||||
StaticModelOptions(),
|
||||
"FlightHelmet");
|
||||
helmetObj->GetTransform().SetWorldPosition(glm::vec3(2.f, GroundHeight, 0.f));
|
||||
helmetObj->GetTransform().SetWorldScale(glm::vec3(2.f));
|
||||
}
|
||||
|
||||
void CreateTree(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources)
|
||||
{
|
||||
constexpr float scale = 3.0f;
|
||||
GameObject* treeObj = ModelSpawner::SpawnStaticModel(
|
||||
scene, gfxDevice, resources,
|
||||
"engine://tree/base.obj",
|
||||
StaticModelOptions(),
|
||||
"Tree");
|
||||
treeObj->GetTransform().SetWorldPosition(glm::vec3(-7.f, GroundHeight + scale, 7.f));
|
||||
treeObj->GetTransform().SetWorldScale(glm::vec3(scale));
|
||||
|
||||
// The trunk is about 0.14 units thick and runs up through the foliage, colliders are in world units
|
||||
treeObj->AddComponent<CapsuleCollider>(0.15f * scale, 2.0f * scale);
|
||||
treeObj->AddComponent<Rigidbody>()->SetType(RigidbodyType::Static);
|
||||
scene.GetPhysics().RegisterGameObject(*treeObj);
|
||||
}
|
||||
|
||||
void CreateCapybara(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources)
|
||||
{
|
||||
constexpr auto modelReference = "engine://cotw-capybara-male/source/capybara.fbx";
|
||||
|
||||
ModelDoc::LoadOptions options{};
|
||||
options.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
|
||||
options.loadMaterials = true;
|
||||
options.loadSkeleton = true;
|
||||
options.loadAnimations = true;
|
||||
|
||||
auto charModel = AssetManager::GetInstance().LoadModel(modelReference, options);
|
||||
ModelDocUtils::LogModelDocSummary(charModel, "capybara.fbx");
|
||||
|
||||
const auto& charPrimitive = ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(charModel, modelReference);
|
||||
|
||||
// The model stores an absolute texture path from another machine, so fall back to the shipped texture
|
||||
const auto charTexturePath = ModelDocUtils::PickTexturePath(
|
||||
charModel,
|
||||
charPrimitive,
|
||||
AssetFS::GetInstance().GetFullPath(
|
||||
"engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs"));
|
||||
|
||||
const MaterialID charMaterialID = resources.materials().addMaterial({
|
||||
.baseColor = ModelDocUtils::GetImportedBaseColor(charModel, charPrimitive),
|
||||
.diffuseTexture = resources.loadImageFromFile(gfxDevice, charTexturePath),
|
||||
.name = ModelDocUtils::GetImportedMaterialName(charModel, charPrimitive, "CharacterMaterial"),
|
||||
});
|
||||
|
||||
GameObject* charObj = scene.CreateGameObject("Character");
|
||||
auto* charMeshComp = charObj->AddComponent<MeshRendererComponent>();
|
||||
charMeshComp->SetMeshID(resources.meshes().addMesh(gfxDevice, charPrimitive.mesh));
|
||||
charMeshComp->SetMaterialID(charMaterialID);
|
||||
|
||||
auto* animator = charObj->AddComponent<Animator>();
|
||||
animator->setSkeleton(std::move(charModel.skeleton));
|
||||
for (auto& clip : charModel.animations)
|
||||
{
|
||||
spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
|
||||
animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
|
||||
}
|
||||
animator->play("capybara_canter_fwd_01|capybara_canter_fwd_01|run");
|
||||
|
||||
charObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
|
||||
charObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f);
|
||||
}
|
||||
|
||||
// Logs everything that enters or leaves it, spheres from the "Spawn ball" button fall through it
|
||||
void CreateTriggerZone(Scene& scene)
|
||||
{
|
||||
GameObject* triggerObj = scene.CreateGameObject("TriggerBox");
|
||||
triggerObj->AddComponent<BoxCollider>(glm::vec3{3.0f, 3.0f, 3.0f})->SetTrigger(true);
|
||||
triggerObj->AddComponent<Rigidbody>()->SetType(RigidbodyType::Static);
|
||||
triggerObj->AddComponent<TriggerLoggerComponent>();
|
||||
triggerObj->GetTransform().SetWorldPosition({0.0f, 0.0f, 0.0f});
|
||||
}
|
||||
|
||||
void CreatePlayer(Scene& scene, MainSceneObjects& objects)
|
||||
{
|
||||
GameObject* playerObj = scene.CreateGameObject("Player");
|
||||
playerObj->GetTransform().SetWorldPosition(glm::vec3(0.0f, 0.0f, -6.0f));
|
||||
playerObj->AddComponent<CapsuleCollider>(0.4f, 1.8f);
|
||||
playerObj->AddComponent<Rigidbody>();
|
||||
|
||||
// Facing the parkour course
|
||||
auto* controller = playerObj->AddComponent<FirstPersonController>();
|
||||
controller->SetYaw(glm::half_pi<float>());
|
||||
scene.GetPhysics().RegisterGameObject(*playerObj);
|
||||
|
||||
objects.player = playerObj;
|
||||
objects.playerController = controller;
|
||||
}
|
||||
|
||||
void LoadSpawnBallResources(GfxDevice& gfxDevice, RenderResources& resources, MainSceneObjects& objects)
|
||||
{
|
||||
const auto sphereModel = AssetManager::GetInstance().LoadModel("engine://sphere.fbx", StaticModelOptions());
|
||||
ModelDocUtils::LogModelDocSummary(sphereModel, "sphere.fbx");
|
||||
const auto& spherePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(sphereModel, "engine://sphere.fbx");
|
||||
|
||||
objects.sphereMesh = resources.meshes().addMesh(gfxDevice, spherePrimitive.mesh);
|
||||
objects.sphereMaterial = resources.materials().addSimpleColorMaterial({0.5f, 0.3f, 0.8f}, "Blue");
|
||||
}
|
||||
}
|
||||
|
||||
MainSceneObjects BuildMainScene(Scene& scene, GfxDevice& gfxDevice, RenderResources& resources)
|
||||
{
|
||||
MainSceneObjects objects{};
|
||||
|
||||
scene.GetEnvironment().fogDensity = 0.01f;
|
||||
|
||||
CreateSun(scene);
|
||||
CreateGround(scene, gfxDevice, resources);
|
||||
CreateParkourCourse(scene, gfxDevice, resources);
|
||||
CreateFlightHelmet(scene, gfxDevice, resources);
|
||||
CreateTree(scene, gfxDevice, resources);
|
||||
CreateCapybara(scene, gfxDevice, resources);
|
||||
CreateTriggerZone(scene);
|
||||
CreatePlayer(scene, objects);
|
||||
LoadSpawnBallResources(gfxDevice, resources, objects);
|
||||
|
||||
return objects;
|
||||
}
|
||||
Reference in New Issue
Block a user