mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
get glTF loader working
This commit is contained in:
parent
41b39d33fb
commit
6d726e6501
@ -20,78 +20,80 @@
|
||||
namespace engine {
|
||||
|
||||
class Application {
|
||||
public:
|
||||
Application(const char* app_name, const char* app_version,
|
||||
gfx::GraphicsSettings graphics_settings);
|
||||
~Application();
|
||||
Application(const Application&) = delete;
|
||||
Application& operator=(const Application&) = delete;
|
||||
public:
|
||||
struct Configuration {
|
||||
bool enable_frame_limiter;
|
||||
};
|
||||
|
||||
/* resource stuff */
|
||||
Application(const char* app_name, const char* app_version, gfx::GraphicsSettings graphics_settings, Configuration configuration);
|
||||
~Application();
|
||||
Application(const Application&) = delete;
|
||||
Application& operator=(const Application&) = delete;
|
||||
|
||||
template <typename T>
|
||||
void RegisterResourceManager() {
|
||||
size_t hash = typeid(T).hash_code();
|
||||
assert(resource_managers_.contains(hash) == false &&
|
||||
"Registering resource manager type more than once.");
|
||||
resource_managers_.emplace(hash, std::make_unique<ResourceManager<T>>());
|
||||
}
|
||||
/* resource stuff */
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> AddResource(const std::string& name,
|
||||
std::unique_ptr<T>&& resource) {
|
||||
auto resource_manager = GetResourceManager<T>();
|
||||
return resource_manager->Add(name, std::move(resource));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetResource(const std::string& name) {
|
||||
auto resource_manager = GetResourceManager<T>();
|
||||
return resource_manager->Get(name);
|
||||
}
|
||||
|
||||
/* methods */
|
||||
void GameLoop();
|
||||
|
||||
void SetFrameLimiter(bool on) { enable_frame_limiter_ = on; }
|
||||
|
||||
/* getters */
|
||||
Window* window() { return window_.get(); }
|
||||
InputManager* input_manager() { return input_manager_.get(); }
|
||||
SceneManager* scene_manager() { return scene_manager_.get(); }
|
||||
Renderer* renderer() { return renderer_.get(); }
|
||||
|
||||
std::string GetResourcePath(const std::string relative_path) {
|
||||
return (resources_path_ / relative_path).string();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Window> window_;
|
||||
std::unique_ptr<InputManager> input_manager_;
|
||||
std::unique_ptr<Renderer> renderer_;
|
||||
std::unordered_map<size_t, std::unique_ptr<IResourceManager>>
|
||||
resource_managers_{};
|
||||
std::filesystem::path resources_path_;
|
||||
|
||||
// Most resources and class instances in the game exist in this object
|
||||
std::unique_ptr<SceneManager> scene_manager_;
|
||||
|
||||
bool enable_frame_limiter_ = true;
|
||||
|
||||
template <typename T>
|
||||
ResourceManager<T>* GetResourceManager() {
|
||||
size_t hash = typeid(T).hash_code();
|
||||
auto it = resource_managers_.find(hash);
|
||||
if (it == resource_managers_.end()) {
|
||||
throw std::runtime_error("Cannot find resource manager.");
|
||||
template <typename T>
|
||||
void RegisterResourceManager()
|
||||
{
|
||||
size_t hash = typeid(T).hash_code();
|
||||
assert(resource_managers_.contains(hash) == false && "Registering resource manager type more than once.");
|
||||
resource_managers_.emplace(hash, std::make_unique<ResourceManager<T>>());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> AddResource(const std::string& name, std::unique_ptr<T>&& resource)
|
||||
{
|
||||
auto resource_manager = GetResourceManager<T>();
|
||||
return resource_manager->Add(name, std::move(resource));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<T> GetResource(const std::string& name)
|
||||
{
|
||||
auto resource_manager = GetResourceManager<T>();
|
||||
return resource_manager->Get(name);
|
||||
}
|
||||
|
||||
/* methods */
|
||||
void GameLoop();
|
||||
|
||||
void SetFrameLimiter(bool on) { configuration_.enable_frame_limiter = on; }
|
||||
|
||||
/* getters */
|
||||
Window* window() { return window_.get(); }
|
||||
InputManager* input_manager() { return input_manager_.get(); }
|
||||
SceneManager* scene_manager() { return scene_manager_.get(); }
|
||||
Renderer* renderer() { return renderer_.get(); }
|
||||
|
||||
std::string GetResourcePath(const std::string relative_path) const { return (resources_path_ / relative_path).string(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<Window> window_;
|
||||
std::unique_ptr<InputManager> input_manager_;
|
||||
std::unique_ptr<Renderer> renderer_;
|
||||
std::unordered_map<size_t, std::unique_ptr<IResourceManager>> resource_managers_{};
|
||||
std::filesystem::path resources_path_;
|
||||
|
||||
// Most resources and class instances in the game exist in this object
|
||||
std::unique_ptr<SceneManager> scene_manager_;
|
||||
|
||||
Configuration configuration_;
|
||||
|
||||
template <typename T>
|
||||
ResourceManager<T>* GetResourceManager()
|
||||
{
|
||||
size_t hash = typeid(T).hash_code();
|
||||
auto it = resource_managers_.find(hash);
|
||||
if (it == resource_managers_.end()) {
|
||||
throw std::runtime_error("Cannot find resource manager.");
|
||||
}
|
||||
auto ptr = it->second.get();
|
||||
auto casted_ptr = dynamic_cast<ResourceManager<T>*>(ptr);
|
||||
assert(casted_ptr != nullptr);
|
||||
return casted_ptr;
|
||||
}
|
||||
auto ptr = it->second.get();
|
||||
auto casted_ptr = dynamic_cast<ResourceManager<T>*>(ptr);
|
||||
assert(casted_ptr != nullptr);
|
||||
return casted_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace engine
|
||||
} // namespace engine
|
||||
|
||||
#endif
|
@ -37,6 +37,7 @@ struct GraphicsSettings {
|
||||
// not all GPUs/drivers support immediate present with V-sync enabled
|
||||
wait_for_present = true;
|
||||
msaa_level = MSAALevel::kOff;
|
||||
enable_anisotropy = false; // anisotropic filtering can severely affect performance on intel iGPUs
|
||||
}
|
||||
|
||||
bool enable_validation;
|
||||
@ -45,6 +46,7 @@ struct GraphicsSettings {
|
||||
// (no affect with V-sync disabled)
|
||||
bool wait_for_present;
|
||||
MSAALevel msaa_level;
|
||||
bool enable_anisotropy;
|
||||
};
|
||||
|
||||
enum class ImageFormat {
|
||||
@ -131,7 +133,7 @@ struct SamplerInfo {
|
||||
Filter minify = gfx::Filter::kLinear;
|
||||
Filter magnify = gfx::Filter::kLinear;
|
||||
Filter mipmap = gfx::Filter::kLinear;
|
||||
bool anisotropic_filtering = true;
|
||||
bool anisotropic_filtering = true; // this can be force disabled by a global setting
|
||||
|
||||
bool operator==(const SamplerInfo&) const = default;
|
||||
};
|
||||
|
@ -73,7 +73,8 @@ static std::filesystem::path getResourcesPath()
|
||||
return resourcesPath;
|
||||
}
|
||||
|
||||
Application::Application(const char* appName, const char* appVersion, gfx::GraphicsSettings graphicsSettings)
|
||||
Application::Application(const char* appName, const char* appVersion, gfx::GraphicsSettings graphicsSettings, Configuration configuration)
|
||||
: configuration_(configuration)
|
||||
{
|
||||
window_ = std::make_unique<Window>(appName, true, false);
|
||||
input_manager_ = std::make_unique<InputManager>(window_.get());
|
||||
@ -114,7 +115,7 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph
|
||||
shaderSettings.write_z = true;
|
||||
shaderSettings.render_order = 0;
|
||||
auto texturedShader = std::make_unique<Shader>(renderer(), GetResourcePath("engine/shaders/standard.vert").c_str(),
|
||||
GetResourcePath("engine/shaders/standard.frag").c_str(), shaderSettings);
|
||||
GetResourcePath("engine/shaders/standard.frag").c_str(), shaderSettings);
|
||||
GetResourceManager<Shader>()->AddPersistent("builtin.standard", std::move(texturedShader));
|
||||
}
|
||||
{
|
||||
@ -129,7 +130,7 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph
|
||||
shaderSettings.write_z = true;
|
||||
shaderSettings.render_order = 0;
|
||||
auto fancyShader = std::make_unique<Shader>(renderer(), GetResourcePath("engine/shaders/fancy.vert").c_str(),
|
||||
GetResourcePath("engine/shaders/fancy.frag").c_str(), shaderSettings);
|
||||
GetResourcePath("engine/shaders/fancy.frag").c_str(), shaderSettings);
|
||||
GetResourceManager<Shader>()->AddPersistent("builtin.fancy", std::move(fancyShader));
|
||||
}
|
||||
{
|
||||
@ -144,7 +145,7 @@ Application::Application(const char* appName, const char* appVersion, gfx::Graph
|
||||
shaderSettings.write_z = true;
|
||||
shaderSettings.render_order = 0;
|
||||
auto skyboxShader = std::make_unique<Shader>(renderer(), GetResourcePath("engine/shaders/skybox.vert").c_str(),
|
||||
GetResourcePath("engine/shaders/skybox.frag").c_str(), shaderSettings);
|
||||
GetResourcePath("engine/shaders/skybox.frag").c_str(), shaderSettings);
|
||||
GetResourceManager<Shader>()->AddPersistent("builtin.skybox", std::move(skyboxShader));
|
||||
}
|
||||
#if 0
|
||||
@ -260,8 +261,7 @@ void Application::GameLoop()
|
||||
return find_depth(parent, current_depth + 1);
|
||||
}
|
||||
};
|
||||
if (scene)
|
||||
{
|
||||
if (scene) {
|
||||
for (Entity i = 1; i < scene->next_entity_id_; ++i) {
|
||||
auto t = scene->GetComponent<TransformComponent>(i);
|
||||
std::string tabs{};
|
||||
@ -296,7 +296,7 @@ void Application::GameLoop()
|
||||
window_->GetInputAndEvents();
|
||||
|
||||
/* fps limiter */
|
||||
if (enable_frame_limiter_) {
|
||||
if (configuration_.enable_frame_limiter) {
|
||||
std::this_thread::sleep_until(endFrame);
|
||||
}
|
||||
beginFrame = endFrame;
|
||||
|
@ -233,6 +233,8 @@ static VkShaderStageFlags getShaderStageFlags(gfx::ShaderStageFlags::Flags flags
|
||||
return VK_CULL_MODE_BACK_BIT;
|
||||
case gfx::CullMode::kCullFrontAndBack:
|
||||
return VK_CULL_MODE_FRONT_AND_BACK;
|
||||
default:
|
||||
throw std::runtime_error("Unknown cull mode");
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,6 +245,8 @@ static VkFormat getImageFormat(gfx::ImageFormat format)
|
||||
return VK_FORMAT_R8G8B8A8_UNORM;
|
||||
case gfx::ImageFormat::kSRGB:
|
||||
return VK_FORMAT_R8G8B8A8_SRGB;
|
||||
default:
|
||||
throw std::runtime_error("Unknown image format");
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +356,7 @@ struct GFXDevice::Impl {
|
||||
SwapchainInfo swapchainInfo{};
|
||||
Swapchain swapchain{};
|
||||
|
||||
VkDescriptorPool descriptorPool;
|
||||
VkDescriptorPool descriptorPool = VK_NULL_HANDLE;
|
||||
|
||||
struct WriteQueues {
|
||||
std::unordered_set<gfx::UniformBuffer*> uniform_buffer_writes{};
|
||||
@ -1640,7 +1644,7 @@ const gfx::Sampler* GFXDevice::CreateSampler(const gfx::SamplerInfo& info)
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
samplerInfo.mipLodBias = 0.0f;
|
||||
samplerInfo.anisotropyEnable = info.anisotropic_filtering ? VK_TRUE : VK_FALSE;
|
||||
samplerInfo.anisotropyEnable = (info.anisotropic_filtering && pimpl->graphicsSettings.enable_anisotropy) ? VK_TRUE : VK_FALSE;
|
||||
samplerInfo.maxAnisotropy = pimpl->device.properties.limits.maxSamplerAnisotropy;
|
||||
samplerInfo.minLod = 0.0f;
|
||||
samplerInfo.maxLod = VK_LOD_CLAMP_NONE;
|
||||
|
@ -53,10 +53,10 @@ static glm::mat4 MatFromDoubleArray(const std::vector<double>& arr)
|
||||
{
|
||||
glm::mat4 mat{};
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
mat[i][0] = static_cast<float>(arr[i * 4 + 0]);
|
||||
mat[i][1] = static_cast<float>(arr[i * 4 + 1]);
|
||||
mat[i][2] = static_cast<float>(arr[i * 4 + 2]);
|
||||
mat[i][3] = static_cast<float>(arr[i * 4 + 3]);
|
||||
mat[i][0] = static_cast<float>(arr[static_cast<size_t>(i) * 4 + 0]);
|
||||
mat[i][1] = static_cast<float>(arr[static_cast<size_t>(i) * 4 + 1]);
|
||||
mat[i][2] = static_cast<float>(arr[static_cast<size_t>(i) * 4 + 2]);
|
||||
mat[i][3] = static_cast<float>(arr[static_cast<size_t>(i) * 4 + 3]);
|
||||
}
|
||||
return mat;
|
||||
}
|
||||
@ -84,8 +84,6 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
||||
throw std::runtime_error("Failed to load glTF file!");
|
||||
}
|
||||
|
||||
LOG_INFO("Loaded glTF model: {}, contains {} scenes", path, model.scenes.size());
|
||||
|
||||
// test model loading
|
||||
|
||||
if (model.scenes.size() < 1) {
|
||||
@ -210,7 +208,8 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
||||
if (material.pbrMetallicRoughness.baseColorTexture.index != -1) {
|
||||
if (material.pbrMetallicRoughness.baseColorTexture.texCoord == 0) {
|
||||
materials.back()->SetAlbedoTexture(textures.at(material.pbrMetallicRoughness.baseColorTexture.index));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
LOG_WARN("Material {} base color texture specifies a UV channel other than zero which is unsupported.");
|
||||
LOG_WARN("Material will be created with a white base color");
|
||||
}
|
||||
@ -331,11 +330,7 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
||||
std::vector<Vertex> vertices;
|
||||
vertices.reserve(num_vertices);
|
||||
for (size_t i = 0; i < num_vertices; ++i) {
|
||||
Vertex v;
|
||||
v.pos = positions[i];
|
||||
v.norm = normals[i];
|
||||
v.tangent = tangents[i];
|
||||
v.uv = uv0s[i];
|
||||
Vertex v{.pos = positions[i], .norm = normals[i], .tangent = tangents[i], .uv = uv0s[i]};
|
||||
vertices.push_back(v);
|
||||
}
|
||||
|
||||
@ -360,13 +355,76 @@ engine::Entity LoadGLTF(Scene& scene, const std::string& path, bool isStatic)
|
||||
}
|
||||
}
|
||||
|
||||
// glTF uses the Y-up convention so objects must be rotated to Z-up
|
||||
const Entity parent =
|
||||
// scene.CreateEntity("test_node", 0, glm::vec3{}, glm::quat{glm::one_over_root_two<float>(), glm::one_over_root_two<float>(), 0.0f, 0.0f});
|
||||
scene.CreateEntity("test_node", 0);
|
||||
scene.CreateEntity("test_node", 0, glm::vec3{}, glm::quat{glm::one_over_root_two<float>(), glm::one_over_root_two<float>(), 0.0f, 0.0f});
|
||||
|
||||
auto ren = scene.AddComponent<MeshRenderableComponent>(parent);
|
||||
ren->material = primitive_arrays.at(0).at(0).material;
|
||||
ren->mesh = primitive_arrays.at(0).at(0).mesh;
|
||||
std::vector<Entity> entities(model.nodes.size(), 0);
|
||||
std::function<void(Entity, const tg::Node&)> generateEntities = [&](Entity parent_entity, const tg::Node& node) -> void {
|
||||
const Entity e = scene.CreateEntity(node.name.empty() ? "anode" : node.name, parent_entity);
|
||||
|
||||
// transform
|
||||
auto t = scene.GetComponent<TransformComponent>(e);
|
||||
t->position.x = 0.0f;
|
||||
t->position.y = 0.0f;
|
||||
t->position.z = 0.0f;
|
||||
t->rotation.x = 0.0f;
|
||||
t->rotation.y = 0.0f;
|
||||
t->rotation.z = 0.0f;
|
||||
t->rotation.w = 1.0f;
|
||||
t->scale.x = 1.0f;
|
||||
t->scale.y = 1.0f;
|
||||
t->scale.z = 1.0f;
|
||||
|
||||
if (node.matrix.size() == 16) {
|
||||
const glm::mat4 matrix = MatFromDoubleArray(node.matrix);
|
||||
DecomposeTransform(matrix, t->position, t->rotation, t->scale);
|
||||
}
|
||||
else {
|
||||
if (node.translation.size() == 3) {
|
||||
t->position.x = static_cast<float>(node.translation[0]);
|
||||
t->position.y = static_cast<float>(node.translation[1]);
|
||||
t->position.z = static_cast<float>(node.translation[2]);
|
||||
}
|
||||
if (node.rotation.size() == 4) {
|
||||
t->rotation.x = static_cast<float>(node.rotation[0]);
|
||||
t->rotation.y = static_cast<float>(node.rotation[1]);
|
||||
t->rotation.z = static_cast<float>(node.rotation[2]);
|
||||
t->rotation.w = static_cast<float>(node.rotation[3]);
|
||||
}
|
||||
if (node.scale.size() == 3) {
|
||||
t->scale.x = static_cast<float>(node.scale[0]);
|
||||
t->scale.y = static_cast<float>(node.scale[1]);
|
||||
t->scale.z = static_cast<float>(node.scale[2]);
|
||||
}
|
||||
}
|
||||
|
||||
// ignoring cameras
|
||||
// ignoring skin
|
||||
// ignoring weights
|
||||
|
||||
if (node.mesh != -1) {
|
||||
const auto& primitives = primitive_arrays.at(node.mesh);
|
||||
int i = 0;
|
||||
for (const EnginePrimitive& prim : primitives) {
|
||||
auto prim_entity = scene.CreateEntity(std::string("_mesh") + std::to_string(i), e);
|
||||
auto meshren = scene.AddComponent<MeshRenderableComponent>(prim_entity);
|
||||
meshren->mesh = prim.mesh;
|
||||
meshren->material = prim.material;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i : node.children) {
|
||||
generateEntities(e, model.nodes.at(i));
|
||||
}
|
||||
};
|
||||
|
||||
for (int i : s.nodes) {
|
||||
generateEntities(parent, model.nodes.at(i));
|
||||
}
|
||||
|
||||
LOG_INFO("Loaded glTF model: {}", path);
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
BIN
test/res/models/walls_with_tangents.glb
Normal file
BIN
test/res/models/walls_with_tangents.glb
Normal file
Binary file not shown.
@ -22,22 +22,22 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
static void ConfigureInputs(engine::InputManager* input_manager)
|
||||
static void ConfigureInputs(engine::InputManager& input_manager)
|
||||
{
|
||||
// user interface mappings
|
||||
input_manager->AddInputButton("fullscreen", engine::inputs::Key::K_F11);
|
||||
input_manager->AddInputButton("exit", engine::inputs::Key::K_ESCAPE);
|
||||
input_manager.AddInputButton("fullscreen", engine::inputs::Key::K_F11);
|
||||
input_manager.AddInputButton("exit", engine::inputs::Key::K_ESCAPE);
|
||||
// game buttons
|
||||
input_manager->AddInputButton("fire", engine::inputs::MouseButton::M_LEFT);
|
||||
input_manager->AddInputButton("aim", engine::inputs::MouseButton::M_RIGHT);
|
||||
input_manager->AddInputButton("jump", engine::inputs::Key::K_SPACE);
|
||||
input_manager->AddInputButton("sprint", engine::inputs::Key::K_LSHIFT);
|
||||
input_manager.AddInputButton("fire", engine::inputs::MouseButton::M_LEFT);
|
||||
input_manager.AddInputButton("aim", engine::inputs::MouseButton::M_RIGHT);
|
||||
input_manager.AddInputButton("jump", engine::inputs::Key::K_SPACE);
|
||||
input_manager.AddInputButton("sprint", engine::inputs::Key::K_LSHIFT);
|
||||
// game movement
|
||||
input_manager->AddInputButtonAsAxis("movex", engine::inputs::Key::K_D, engine::inputs::Key::K_A);
|
||||
input_manager->AddInputButtonAsAxis("movey", engine::inputs::Key::K_W, engine::inputs::Key::K_S);
|
||||
input_manager.AddInputButtonAsAxis("movex", engine::inputs::Key::K_D, engine::inputs::Key::K_A);
|
||||
input_manager.AddInputButtonAsAxis("movey", engine::inputs::Key::K_W, engine::inputs::Key::K_S);
|
||||
// looking around
|
||||
input_manager->AddInputAxis("lookx", engine::inputs::MouseAxis::X);
|
||||
input_manager->AddInputAxis("looky", engine::inputs::MouseAxis::Y);
|
||||
input_manager.AddInputAxis("lookx", engine::inputs::MouseAxis::X);
|
||||
input_manager.AddInputAxis("looky", engine::inputs::MouseAxis::Y);
|
||||
}
|
||||
|
||||
void PlayGame(GameSettings settings)
|
||||
@ -50,11 +50,14 @@ void PlayGame(GameSettings settings)
|
||||
graphics_settings.vsync = true;
|
||||
graphics_settings.wait_for_present = false;
|
||||
graphics_settings.msaa_level = engine::gfx::MSAALevel::kOff;
|
||||
graphics_settings.enable_anisotropy = false;
|
||||
|
||||
engine::Application app(PROJECT_NAME, PROJECT_VERSION, graphics_settings);
|
||||
app.SetFrameLimiter(settings.enable_frame_limiter);
|
||||
engine::Application::Configuration configuration{};
|
||||
configuration.enable_frame_limiter = settings.enable_frame_limiter;
|
||||
|
||||
engine::Application app(PROJECT_NAME, PROJECT_VERSION, graphics_settings, configuration);
|
||||
app.window()->SetRelativeMouseMode(true);
|
||||
ConfigureInputs(app.input_manager());
|
||||
ConfigureInputs(*app.input_manager());
|
||||
|
||||
engine::Scene* my_scene = app.scene_manager()->CreateEmptyScene();
|
||||
{
|
||||
@ -201,7 +204,7 @@ void PlayGame(GameSettings settings)
|
||||
//scene2->GetComponent<engine::TransformComponent>(teapot2)->position.y += 5.0f;
|
||||
//scene2->GetComponent<engine::TransformComponent>(teapot2)->rotation = glm::angleAxis(glm::pi<float>(), glm::vec3{ 0.0f, 0.0f, 1.0f });
|
||||
//scene2->GetComponent<engine::TransformComponent>(teapot2)->rotation *= glm::angleAxis(glm::half_pi<float>(), glm::vec3{1.0f, 0.0f, 0.0f});
|
||||
//auto walls = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/walls.glb"));
|
||||
auto walls = engine::util::LoadGLTF(*scene2, app.GetResourcePath("models/walls_with_tangents.glb"));
|
||||
}
|
||||
|
||||
my_scene->GetSystem<CameraControllerSystem>()->next_scene_ = scene2;
|
||||
|
Loading…
Reference in New Issue
Block a user