From e43d86cf4fd0aeefedc0ba245ef13e2f4d73721d Mon Sep 17 00:00:00 2001 From: ohyzha Date: Mon, 4 Nov 2024 18:18:21 +0200 Subject: [PATCH 01/12] make it possible to create set app for GraphicsAppManager in deferred mode --- examples/main.cpp | 5 +- openVulkanoCpp/Host/GraphicsAppManager.cpp | 91 ++++++++++++---------- openVulkanoCpp/Host/GraphicsAppManager.hpp | 7 ++ 3 files changed, 59 insertions(+), 44 deletions(-) diff --git a/examples/main.cpp b/examples/main.cpp index 002e431..6d53bf2 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -19,6 +19,8 @@ using namespace OpenVulkano; int main(int argc, char** argv) { + GraphicsAppManager manager; + std::vector examples; for (const auto& e : EXAMPLE_APPS) { @@ -36,8 +38,7 @@ int main(int argc, char** argv) if (selectedExample >= examples.size()) throw std::runtime_error("Invalid menu selection!"); std::unique_ptr app( EXAMPLE_APPS[selectedExample].second() ); - - GraphicsAppManager manager(app.get()); + manager.SetApp(app.get()); manager.Run(); return 0; } diff --git a/openVulkanoCpp/Host/GraphicsAppManager.cpp b/openVulkanoCpp/Host/GraphicsAppManager.cpp index 8457e07..3b07ddd 100644 --- a/openVulkanoCpp/Host/GraphicsAppManager.cpp +++ b/openVulkanoCpp/Host/GraphicsAppManager.cpp @@ -24,65 +24,64 @@ namespace OpenVulkano { using clock = std::chrono::steady_clock; + GraphicsAppManager::GraphicsAppManager(RenderAPI::RenderApi renderApi) { Init(nullptr, nullptr, renderApi); } + GraphicsAppManager::GraphicsAppManager(OpenVulkano::IGraphicsApp* app, RenderAPI::RenderApi renderApi) : app(app), renderApi(renderApi) - { - Utils::SetThreadName("Main"); -#ifdef HAS_TRACY - ZoneScoped; -#endif - - - Logger::SetupLogger(); - if (!app) - { - constexpr auto msg = "The app must not be null!"; - Logger::MANAGER->error(msg); - throw std::runtime_error(msg); - } - platform = std::unique_ptr(PlatformProducer::CreatePlatform(renderApi)); - window = platform->MakeWindow(); - renderer = std::unique_ptr(PlatformProducer::CreateRenderManager(renderApi)); - app->SetGraphicsAppManager(this); - window->SetWindowHandler(this); - inputManager = Input::InputManager::GetInstance(); - engineConfig = EngineConfiguration::GetEngineConfiguration(); - engineConfig->OnFpsCapChanged += EventHandler(this, &GraphicsAppManager::UpdateCappedFpsInfo); - // set initial values - if (engineConfig->GetFpsCap() > 0) - { - UpdateCappedFpsInfo(engineConfig->GetFpsCap()); - } + { + Init(app, nullptr, renderApi); } - + GraphicsAppManager::GraphicsAppManager(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi) : app(app), renderApi(renderApi) + { + Init(app, window, renderApi); + } + + void GraphicsAppManager::SetApp(IGraphicsApp* app) + { + this->app = app; + app->SetGraphicsAppManager(this); + } + + void GraphicsAppManager::Init(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi) { Utils::SetThreadName("Main"); #ifdef HAS_TRACY ZoneScoped; #endif - Logger::SetupLogger(); - if (!app) - { - constexpr auto msg = "The app must not be null!"; - Logger::MANAGER->error(msg); - throw std::runtime_error(msg); - } - //platform = std::unique_ptr(PlatformProducer::CreatePlatform(renderApi)); - this->window = window; + Logger::MANAGER->info("Initializing graphics app manager ..."); + this->renderApi = renderApi; + platform = std::unique_ptr(PlatformProducer::CreatePlatform(renderApi)); renderer = std::unique_ptr(PlatformProducer::CreateRenderManager(renderApi)); - app->SetGraphicsAppManager(this); - window->SetWindowHandler(this); - inputManager = OpenVulkano::Input::InputManager::GetInstance(); - engineConfig = OpenVulkano::EngineConfiguration::GetEngineConfiguration(); + inputManager = Input::InputManager::GetInstance(); + engineConfig = EngineConfiguration::GetEngineConfiguration(); engineConfig->OnFpsCapChanged += EventHandler(this, &GraphicsAppManager::UpdateCappedFpsInfo); + if (window) + { + this->window = window; + } + else + { + this->window = platform->MakeWindow(); + } + if (app) + { + app->SetGraphicsAppManager(this); + } + this->window->SetWindowHandler(this); + // set initial values if (engineConfig->GetFpsCap() > 0) { UpdateCappedFpsInfo(engineConfig->GetFpsCap()); } + if (platform) + { + platform->Init(); + } + Logger::MANAGER->info("Initialized..."); } void GraphicsAppManager::UpdateCappedFpsInfo(int32_t newFpsCap) @@ -144,6 +143,12 @@ namespace OpenVulkano void GraphicsAppManager::StartUp() { + if (!app) + { + constexpr auto msg = "The app must not be null!"; + Logger::MANAGER->error(msg); + throw std::runtime_error(msg); + } #ifdef HAS_TRACY ZoneScoped; #endif @@ -151,7 +156,9 @@ namespace OpenVulkano { Logger::MANAGER->info("Initializing ..."); app->Init(); - if (platform) platform->Init(); + + //if (platform) platform->Init(); + window->Init(renderApi); //TODO restore window settings if there are any set renderer->Init(static_cast(this), window); diff --git a/openVulkanoCpp/Host/GraphicsAppManager.hpp b/openVulkanoCpp/Host/GraphicsAppManager.hpp index d48704a..d07b626 100644 --- a/openVulkanoCpp/Host/GraphicsAppManager.hpp +++ b/openVulkanoCpp/Host/GraphicsAppManager.hpp @@ -48,10 +48,17 @@ namespace OpenVulkano void OnCappedFPS(const auto& frameStartTime); void UpdateCappedFpsInfo(int32_t newFpsCap); public: + + GraphicsAppManager(RenderAPI::RenderApi renderApi = RenderAPI::Vulkan); + explicit GraphicsAppManager(IGraphicsApp* app, RenderAPI::RenderApi renderApi = RenderAPI::Vulkan); explicit GraphicsAppManager(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi = RenderAPI::Vulkan); + void SetApp(IGraphicsApp* app); + + void Init(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi); + ~GraphicsAppManager() noexcept override; public: // Getter From 4f3336014a405450fd383f9c931075151822f462 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Mon, 4 Nov 2024 18:19:20 +0200 Subject: [PATCH 02/12] store text of text drawable --- openVulkanoCpp/Scene/TextDrawable.cpp | 1 + openVulkanoCpp/Scene/TextDrawable.hpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/openVulkanoCpp/Scene/TextDrawable.cpp b/openVulkanoCpp/Scene/TextDrawable.cpp index 5413368..be09db9 100644 --- a/openVulkanoCpp/Scene/TextDrawable.cpp +++ b/openVulkanoCpp/Scene/TextDrawable.cpp @@ -150,6 +150,7 @@ namespace OpenVulkano::Scene return; } + m_text = text; auto GetActualLength = [&]() { auto begin = text.begin(); diff --git a/openVulkanoCpp/Scene/TextDrawable.hpp b/openVulkanoCpp/Scene/TextDrawable.hpp index 2d50129..ae7f8b5 100644 --- a/openVulkanoCpp/Scene/TextDrawable.hpp +++ b/openVulkanoCpp/Scene/TextDrawable.hpp @@ -51,6 +51,7 @@ namespace OpenVulkano::Scene Math::AABB& GetBoundingBox() { return m_bbox; } TextConfig& GetConfig() { return m_cfg; } Shader* GetShader() { return m_shader; } + std::string& GetText() { return m_text; } std::shared_ptr GetAtlasData() { return m_atlasData; } private: Geometry m_geometry; @@ -59,6 +60,7 @@ namespace OpenVulkano::Scene std::shared_ptr m_atlasData; Math::AABB m_bbox; Shader* m_shader = nullptr; + std::string m_text; TextConfig m_cfg; }; } From 4956884d5ff11ad3ff1e65304ebd20b5f4d94eb3 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Mon, 4 Nov 2024 18:20:32 +0200 Subject: [PATCH 03/12] introduce intersectable interface --- openVulkanoCpp/Scene/Drawable.hpp | 10 +++- openVulkanoCpp/Scene/IRayIntersectable.hpp | 18 ++++++ .../Scene/Prefabs/LabelDrawable.cpp | 5 ++ .../Scene/Prefabs/LabelDrawable.hpp | 1 + openVulkanoCpp/Scene/SimpleDrawable.cpp | 60 +++++++++++++++++++ openVulkanoCpp/Scene/SimpleDrawable.hpp | 2 + 6 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 openVulkanoCpp/Scene/IRayIntersectable.hpp diff --git a/openVulkanoCpp/Scene/Drawable.hpp b/openVulkanoCpp/Scene/Drawable.hpp index 5f58614..2c24b0d 100644 --- a/openVulkanoCpp/Scene/Drawable.hpp +++ b/openVulkanoCpp/Scene/Drawable.hpp @@ -7,6 +7,7 @@ #pragma once #include "Base/ICloseable.hpp" +#include "Scene/IRayIntersectable.hpp" #include "DrawEncoder.hpp" #include #include @@ -26,13 +27,14 @@ namespace OpenVulkano::Scene BACKGROUND = 0, MAIN, TRANSPARENT, POST }; - class Drawable : public ICloseable + class Drawable : public ICloseable, public IRayIntersectable { std::vector m_nodes; Scene* m_scene = nullptr; Shader* m_shader = nullptr; const DrawEncoder m_encoder; const DrawPhase m_drawPhase; + bool m_isHittable = false; public: explicit Drawable(const DrawEncoder& encoder, @@ -45,6 +47,12 @@ namespace OpenVulkano::Scene void SetShader(Shader* shader) { m_shader = shader; } + std::optional Intersect(const Ray& ray) const override { return {}; } + + void SetIsHittable(bool hittable) { m_isHittable = hittable; } + + bool IsHittable() const { return m_isHittable; } + [[nodiscard]] Scene* GetScene() const { return m_scene; } [[nodiscard]] const auto& GetNodes() const { return m_nodes; } diff --git a/openVulkanoCpp/Scene/IRayIntersectable.hpp b/openVulkanoCpp/Scene/IRayIntersectable.hpp new file mode 100644 index 0000000..0deaf91 --- /dev/null +++ b/openVulkanoCpp/Scene/IRayIntersectable.hpp @@ -0,0 +1,18 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Scene/Ray.hpp" + +namespace OpenVulkano::Scene +{ + class IRayIntersectable + { + public: + virtual std::optional Intersect(const Ray& ray) const = 0; + }; +} diff --git a/openVulkanoCpp/Scene/Prefabs/LabelDrawable.cpp b/openVulkanoCpp/Scene/Prefabs/LabelDrawable.cpp index 4ca1aff..e1ddfef 100644 --- a/openVulkanoCpp/Scene/Prefabs/LabelDrawable.cpp +++ b/openVulkanoCpp/Scene/Prefabs/LabelDrawable.cpp @@ -80,6 +80,11 @@ namespace OpenVulkano::Scene m_billboardSettings = settings; } + std::optional LabelDrawable::Intersect(const Ray& ray) const + { + return ray.IntersectAABB(m_bbox); + } + void LabelDrawable::RecalculateBbox(const Math::AABB& other) { if (m_bbox.IsEmpty()) diff --git a/openVulkanoCpp/Scene/Prefabs/LabelDrawable.hpp b/openVulkanoCpp/Scene/Prefabs/LabelDrawable.hpp index c8269fb..ce29ae7 100644 --- a/openVulkanoCpp/Scene/Prefabs/LabelDrawable.hpp +++ b/openVulkanoCpp/Scene/Prefabs/LabelDrawable.hpp @@ -61,6 +61,7 @@ namespace OpenVulkano::Scene Math::Vector3f& GetPosition() { return m_position; } bool IsBillboard() const { return m_isBillboard; } const Math::AABB& GetBoundingBox() const { return m_bbox; } + std::optional Intersect(const Ray& ray) const override; private: void RecalculateBbox(const Math::AABB& other); void SetupShaders(); diff --git a/openVulkanoCpp/Scene/SimpleDrawable.cpp b/openVulkanoCpp/Scene/SimpleDrawable.cpp index 0920971..cc2de23 100644 --- a/openVulkanoCpp/Scene/SimpleDrawable.cpp +++ b/openVulkanoCpp/Scene/SimpleDrawable.cpp @@ -5,6 +5,9 @@ */ #include "SimpleDrawable.hpp" +#include "Scene/Geometry.hpp" +#include "Scene/Shader/Shader.hpp" +#include "Base/Logger.hpp" #include namespace OpenVulkano::Scene @@ -26,4 +29,61 @@ namespace OpenVulkano::Scene m_uniBuffer = drawable->m_uniBuffer; SetShader(drawable->GetShader()); } + + std::optional SimpleDrawable::Intersect(const Ray& ray) const + { + if (!m_mesh || !GetShader()) + { + return {}; + } + if (m_mesh->aabb.IsEmpty()) + { + m_mesh->CalculateAABB(); + } + if (ray.IntersectAABB(m_mesh->aabb)) + { + if (GetShader()->topology == Topology::TRIANGLE_LIST) + { + if (m_mesh->indexCount != 0) + { + for (int i = 0; i < m_mesh->indexCount / 3; i++) + { + if (m_mesh->indexType == VertexIndexType::UINT16) + { + uint16_t* indices = m_mesh->GetIndices16(); + if (auto hit = ray.IntersectTriangle(m_mesh->vertices[indices[i * 3]].position, + m_mesh->vertices[indices[i * 3 + 1]].position, + m_mesh->vertices[indices[i * 3 + 2]].position)) + { + return hit; + } + } + else + { + uint32_t* indices = m_mesh->GetIndices32(); + if (auto hit = ray.IntersectTriangle(m_mesh->vertices[indices[i * 3]].position, + m_mesh->vertices[indices[i * 3 + 1]].position, + m_mesh->vertices[indices[i * 3 + 2]].position)) + { + return hit; + } + } + } + } + else + { + for (int i = 0; i < m_mesh->vertexCount / 3; i++) + { + if (auto hit = ray.IntersectTriangle(m_mesh->vertices[i * 3].position, + m_mesh->vertices[i * 3 + 1].position, + m_mesh->vertices[i * 3 + 2].position)) + { + return hit; + } + } + } + } + } + return {}; + } } \ No newline at end of file diff --git a/openVulkanoCpp/Scene/SimpleDrawable.hpp b/openVulkanoCpp/Scene/SimpleDrawable.hpp index 231a87b..f78139b 100644 --- a/openVulkanoCpp/Scene/SimpleDrawable.hpp +++ b/openVulkanoCpp/Scene/SimpleDrawable.hpp @@ -44,6 +44,8 @@ namespace OpenVulkano::Scene void Init(SimpleDrawable* drawable); + std::optional Intersect(const Ray& ray) const override; + [[nodiscard]] Geometry* GetMesh() const { return m_mesh; } [[nodiscard]] Material* GetMaterial() const { return m_material; } From 7febb370a80357657c9937ed0056b2c196e12960 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Mon, 4 Nov 2024 18:22:40 +0200 Subject: [PATCH 04/12] implement ray casting events --- .../Controller/CameraController.cpp | 40 +++++++++++ .../Controller/CameraController.hpp | 20 ++++-- .../Controller/FreeCamCameraController.cpp | 4 ++ openVulkanoCpp/Input/InputDeviceMouse.hpp | 4 ++ openVulkanoCpp/Input/InputManager.cpp | 12 ++++ openVulkanoCpp/Input/InputManager.hpp | 2 + .../Input/Touch/InputDeviceTouch.hpp | 1 + openVulkanoCpp/Scene/Camera.cpp | 68 +++++++++++++++++++ openVulkanoCpp/Scene/Camera.hpp | 30 ++++++++ 9 files changed, 176 insertions(+), 5 deletions(-) create mode 100644 openVulkanoCpp/Controller/CameraController.cpp create mode 100644 openVulkanoCpp/Scene/Camera.cpp diff --git a/openVulkanoCpp/Controller/CameraController.cpp b/openVulkanoCpp/Controller/CameraController.cpp new file mode 100644 index 0000000..81ba2e1 --- /dev/null +++ b/openVulkanoCpp/Controller/CameraController.cpp @@ -0,0 +1,40 @@ +#include "CameraController.hpp" +#include "Scene/Camera.hpp" +#include "Input/InputDeviceMouse.hpp" +#include "Input/InputDeviceController.hpp" +#include "Input/InputManager.hpp" +#include "Input/Touch/InputDeviceTouch.hpp" + + +namespace OpenVulkano +{ + CameraController::CameraController(Scene::Camera* camera) + { + m_inputManager = Input::InputManager::GetInstance(); + m_camera = camera; + m_actionCastRay = m_inputManager->GetAction("cast ray"); + m_actionCastRay->BindKey(Input::InputKey::Mouse::BUTTON_1); + // BIND FOR TOUCH + m_actionCastRay->BindKey(Input::InputKey::Touch::AXIS_TAP_X); + m_actionCastRay->BindKey(Input::InputKey::Touch::AXIS_TAP_X); + } + + void CameraController::Tick() + { + Input::InputDeviceMouse* mouse = static_cast(m_inputManager->GetDevice(Input::InputDeviceType::MOUSE)); + Input::InputDeviceTouch* touch = static_cast(m_inputManager->GetDevice(Input::InputDeviceType::TOUCH)); + if (m_camera->CanCastRay() && m_inputManager->GetButton(m_actionCastRay)) + { + if (mouse && mouse->GetButtonDown(Input::InputKey::Mouse::BUTTON_1)) + { + Math::Vector2i pos = mouse->GetMousePosition(); + mouse->onLeftButtonClick.NotifyAll(pos); + } + else if (touch) + { + Math::Vector2i pos = touch->GetTapPosition(); + touch->OnTap.NotifyAll(pos); + } + } + } +} diff --git a/openVulkanoCpp/Controller/CameraController.hpp b/openVulkanoCpp/Controller/CameraController.hpp index 80bfa2d..9650b04 100644 --- a/openVulkanoCpp/Controller/CameraController.hpp +++ b/openVulkanoCpp/Controller/CameraController.hpp @@ -11,6 +11,12 @@ namespace OpenVulkano { + namespace Input + { + class InputAction; + class InputManager; + } + namespace Scene { class Camera; @@ -18,22 +24,26 @@ namespace OpenVulkano class CameraController : public ITickable, ICloseable { - Scene::Camera* m_camera; - protected: - CameraController(Scene::Camera* camera = nullptr) - : m_camera(camera) - {} + Scene::Camera* m_camera; + Input::InputAction* m_actionCastRay; + Input::InputManager* m_inputManager; + + CameraController(Scene::Camera* camera = nullptr); public: ~CameraController() override = default; + void Tick() override; + virtual void Init(Scene::Camera* camera) { m_camera = camera; } void Close() override { m_camera = nullptr; } void SetCamera(Scene::Camera* camera) { m_camera = camera; } + Input::InputAction* GetActionCastRay() { return m_actionCastRay; } + Scene::Camera* GetCamera() { return m_camera; } virtual void SetActive() {} diff --git a/openVulkanoCpp/Controller/FreeCamCameraController.cpp b/openVulkanoCpp/Controller/FreeCamCameraController.cpp index 8f94d3e..7f0a082 100644 --- a/openVulkanoCpp/Controller/FreeCamCameraController.cpp +++ b/openVulkanoCpp/Controller/FreeCamCameraController.cpp @@ -8,6 +8,7 @@ #include "Base/FrameMetadata.hpp" #include "Scene/Camera.hpp" #include "Input/InputManager.hpp" +#include "Input/InputDeviceMouse.hpp" #include "Input/InputKey.hpp" namespace OpenVulkano @@ -39,6 +40,8 @@ namespace OpenVulkano vec *= m_boostFactor; } + CameraController::Tick(); + m_yaw -= input->GetAxis(m_actionLookSide) * timeScale / 2.0f; m_pitch -= input->GetAxis(m_actionLookUp) * timeScale / 2.0f; m_pitch = std::min(1.4f, std::max(-1.4f, m_pitch)); @@ -48,6 +51,7 @@ namespace OpenVulkano Math::Matrix4f camTransformation = Math::Utils::toMat4(rot); camTransformation[3] = Math::Vector4f(m_position, 1); GetCamera()->SetMatrix(camTransformation); + //CameraController::Tick(); CURRENT_FRAME.needsRedraw = true; } diff --git a/openVulkanoCpp/Input/InputDeviceMouse.hpp b/openVulkanoCpp/Input/InputDeviceMouse.hpp index d3a320b..29f2cf1 100644 --- a/openVulkanoCpp/Input/InputDeviceMouse.hpp +++ b/openVulkanoCpp/Input/InputDeviceMouse.hpp @@ -8,6 +8,7 @@ #include "InputDevice.hpp" #include "Math/Math.hpp" +#include "Base/Event.hpp" namespace OpenVulkano { @@ -143,6 +144,9 @@ namespace OpenVulkano { return window == lastWindow; } + + Event onLeftButtonClick; + }; } } \ No newline at end of file diff --git a/openVulkanoCpp/Input/InputManager.cpp b/openVulkanoCpp/Input/InputManager.cpp index 5e36010..af918a3 100644 --- a/openVulkanoCpp/Input/InputManager.cpp +++ b/openVulkanoCpp/Input/InputManager.cpp @@ -85,6 +85,18 @@ namespace OpenVulkano::Input return false; } + InputDevice* InputManager::GetDevice(InputDeviceType type) const + { + for (InputDevice* device: devices) + { + if (device->GetType() == type && type != InputDeviceType::UNKNOWN) + { + return device; + } + } + return nullptr; + } + void InputManager::Tick() { for(InputDevice* device : devices) diff --git a/openVulkanoCpp/Input/InputManager.hpp b/openVulkanoCpp/Input/InputManager.hpp index d2aa6dc..774b65c 100644 --- a/openVulkanoCpp/Input/InputManager.hpp +++ b/openVulkanoCpp/Input/InputManager.hpp @@ -42,6 +42,8 @@ namespace OpenVulkano::Input [[nodiscard]] bool GetButton(InputKey key) const; + [[nodiscard]] InputDevice* GetDevice(InputDeviceType type) const; + [[nodiscard]] InputDevice* GetLastActiveDevice() const { return lastActiveDevice; diff --git a/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp b/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp index 7d0dfa7..8fde139 100644 --- a/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp +++ b/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp @@ -84,5 +84,6 @@ namespace OpenVulkano::Input [[nodiscard]] bool IsMultiTouch() const { return m_multiTouch; } Event OnTouchAdded, OnTouchDown, OnTouchUp, OnTouchMoved, OnTouchRemoved; + Event OnTap; }; } diff --git a/openVulkanoCpp/Scene/Camera.cpp b/openVulkanoCpp/Scene/Camera.cpp new file mode 100644 index 0000000..6253937 --- /dev/null +++ b/openVulkanoCpp/Scene/Camera.cpp @@ -0,0 +1,68 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "Camera.hpp" +#include "Scene/Scene.hpp" +#include "Scene/SimpleDrawable.hpp" +#include "Scene/Geometry.hpp" +#include "Scene/Shader/Shader.hpp" +#include "Scene/TextDrawable.hpp" +#include "Scene/Prefabs/LabelDrawable.hpp" +#include "Scene/Ray.hpp" +#include "Scene/TextDrawable.hpp" + +namespace OpenVulkano::Scene +{ + + std::optional PerspectiveCamera::CastRay(const Math::Vector2i& xy) const + { + using namespace Math::Utils; + + auto scene = GetScene(); + + // nds + float ndsX = (2.f * xy.x) / m_width - 1.0f; + float ndsY = (2.f * xy.y) / m_height - 1.0f; + + Math::Vector4f rayClip = { ndsX, ndsY, 0, 1.f }; + + Math::Vector4f rayEye = inverse(m_projection) * rayClip; + rayEye.z = -1; + rayEye.a = 0; + + Math::Vector3f rayWorld = normalize(inverse(m_view) * rayEye); + + std::optional res; + for (Drawable* d: scene->rayHittableDrawables) + { + const auto& m = d->GetNodes()[0]->GetWorldMatrix(); + const Math::Vector3f rayLocalDir = normalize(inverse(m) * Math::Vector4f(rayWorld, 0)); + const Math::Vector4f rayLocalPos = inverse(m) * m_camPosition; + const Ray ray(rayLocalPos, rayLocalDir); + if (auto hit = d->Intersect(ray)) + { + // choose the closest one + if (!res || (hit->distance < res->distance)) + { + res = hit; + res->drawable = d; + } + } + } + if (res) + { + if (SimpleDrawable* sd = dynamic_cast(res->drawable)) + { + Logger::APP->info("Ray intersects object {}", sd->GetMesh()->name); + } + else if (LabelDrawable* sd = dynamic_cast(res->drawable)) + { + Logger::APP->info("Ray intersects label {}", sd->GetTexts().front().GetText()); + } + } + return res; + } +} diff --git a/openVulkanoCpp/Scene/Camera.hpp b/openVulkanoCpp/Scene/Camera.hpp index f755ded..2788cf6 100644 --- a/openVulkanoCpp/Scene/Camera.hpp +++ b/openVulkanoCpp/Scene/Camera.hpp @@ -9,6 +9,10 @@ #include "Node.hpp" #include "Math/Math.hpp" #include "Math/Frustum.hpp" +#include "Input/InputDeviceMouse.hpp" +#include "Input/Touch/InputDeviceTouch.hpp" +#include "Input/InputManager.hpp" +#include "Base/Logger.hpp" #include namespace OpenVulkano::Scene @@ -27,6 +31,7 @@ namespace OpenVulkano::Scene float m_contentScaleFactor = 1, m_zoom = 1; // For use with ortho camera float m_interfaceOrientation = 0; float m_padding = 0; //Unused + bool m_canCastRay = true; Camera() : m_nearPlane(0), m_farPlane(0), m_width(0), m_height(0) {} @@ -45,6 +50,20 @@ namespace OpenVulkano::Scene m_farPlane = farPlane; Node::Init(); UpdateProjectionMatrix(); + if (m_canCastRay) + { + Input::InputDeviceMouse* mouse = static_cast(Input::InputManager::GetInstance()->GetDevice(Input::InputDeviceType::MOUSE)); + Input::InputDeviceTouch* touch = static_cast(Input::InputManager::GetInstance()->GetDevice(Input::InputDeviceType::TOUCH)); + if (mouse) + { + mouse->onLeftButtonClick += EventHandler(this, &Camera::CastRay); + } + else if (touch) + { + touch->OnTap += EventHandler(this, &Camera::CastRay); + } + } + } public: @@ -66,6 +85,8 @@ namespace OpenVulkano::Scene [[nodiscard]] float FarPlane() const { return m_farPlane; } + [[nodiscard]] bool CanCastRay() const { return m_canCastRay; } + void SetContentScaleFactor(float contentScale = 1) { m_contentScaleFactor = 1.0f / contentScale; @@ -83,6 +104,8 @@ namespace OpenVulkano::Scene virtual void UpdateProjectionMatrix() = 0; + virtual std::optional CastRay(const Math::Vector2i& xy) const = 0; + void UpdateViewProjectionMatrix() { m_viewProjection = m_projection * m_view; @@ -241,6 +264,8 @@ namespace OpenVulkano::Scene SetProjectionMatrix(Math::Utils::perspectiveRH_ZO(m_fov, m_aspect, m_nearPlane, m_farPlane)); } + std::optional CastRay(const Math::Vector2i& xy) const override; + [[nodiscard]] bool IsPerspective() const override { return true; } }; @@ -254,6 +279,11 @@ namespace OpenVulkano::Scene SetProjectionMatrix(Math::Utils::orthoRH_ZO(-widthHalf, widthHalf, -heightHalf, heightHalf, m_nearPlane, m_farPlane)); } + std::optional CastRay(const Math::Vector2i& xy) const override + { + throw std::runtime_error("Not implemented yet"); + } + [[nodiscard]] bool IsOrtho() const override { return true; } }; } From 4c9f0ab2ee65cf1c510007a1d8e19f8a9ca76c3b Mon Sep 17 00:00:00 2001 From: ohyzha Date: Mon, 4 Nov 2024 18:23:10 +0200 Subject: [PATCH 05/12] ray hit with drawable --- openVulkanoCpp/Scene/Ray.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openVulkanoCpp/Scene/Ray.hpp b/openVulkanoCpp/Scene/Ray.hpp index 080766c..044c14a 100644 --- a/openVulkanoCpp/Scene/Ray.hpp +++ b/openVulkanoCpp/Scene/Ray.hpp @@ -12,6 +12,7 @@ namespace OpenVulkano::Scene { + class Drawable; struct RayHit { @@ -22,6 +23,13 @@ namespace OpenVulkano::Scene bool operator!=(const RayHit& other) const = default; }; + struct DrawableRayHit : RayHit + { + DrawableRayHit() = default; + DrawableRayHit(const RayHit& hit) : RayHit(hit) {}; + Drawable* drawable = nullptr; + }; + class Ray { public: From 4c67b94bc6bd7bd86204f3dcd814f1a585e49504 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Mon, 4 Nov 2024 18:23:43 +0200 Subject: [PATCH 06/12] store ray hittable drawables in the scene --- openVulkanoCpp/Scene/Scene.hpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/openVulkanoCpp/Scene/Scene.hpp b/openVulkanoCpp/Scene/Scene.hpp index 84aadb1..c4babf5 100644 --- a/openVulkanoCpp/Scene/Scene.hpp +++ b/openVulkanoCpp/Scene/Scene.hpp @@ -20,6 +20,7 @@ namespace OpenVulkano public: Node* root; std::vector shapeList; + std::vector rayHittableDrawables; Camera* camera; public: @@ -55,11 +56,21 @@ namespace OpenVulkano return root; } + void RegisterHittableDrawable(Drawable* drawable) + { + drawable->SetIsHittable(true); + RegisterDrawable(drawable); + } + void RegisterDrawable(Drawable* drawable) { if (drawable->GetScene() != this) drawable->SetScene(this); if (Utils::Contains(shapeList, drawable)) return; // Prevent duplicate entries shapeList.push_back(drawable); + if (drawable->IsHittable()) + { + rayHittableDrawables.push_back(drawable); + } if (shapeList.size() > 1 && shapeList[shapeList.size() - 2]->GetDrawPhase() < drawable->GetDrawPhase()) { std::sort(shapeList.begin(), shapeList.end(), @@ -70,12 +81,14 @@ namespace OpenVulkano void RemoveDrawable(Drawable* drawable) { Utils::Remove(shapeList, drawable); + Utils::Remove(rayHittableDrawables, drawable); drawable->SetScene(nullptr); } virtual void SetCamera(Camera* camera) { this->camera = camera; + camera->scene = this; } Camera* GetCamera() const From 645fac1964ba314a7869fbccb2f9c84c7b1fd08e Mon Sep 17 00:00:00 2001 From: ohyzha Date: Mon, 4 Nov 2024 18:24:23 +0200 Subject: [PATCH 07/12] geometry no longer can be freed if object is hittable --- openVulkanoCpp/Scene/Geometry.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openVulkanoCpp/Scene/Geometry.hpp b/openVulkanoCpp/Scene/Geometry.hpp index df2d101..c5c1159 100644 --- a/openVulkanoCpp/Scene/Geometry.hpp +++ b/openVulkanoCpp/Scene/Geometry.hpp @@ -30,8 +30,10 @@ namespace OpenVulkano Vertex* vertices = nullptr; void* indices = nullptr; VertexIndexType indexType = VertexIndexType::UINT16; - bool ownsMemory = true, freeAfterUpload = true; + // handle freeAfterUpload better. we can't free this memory if object is hittable + bool ownsMemory = true, freeAfterUpload = false; Math::AABB aabb; + std::string name; public: Geometry() = default; Geometry(const Geometry& other); From 3d96889778e5fcb03626f6c9a51dd3ea72ef8504 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Mon, 4 Nov 2024 18:24:31 +0200 Subject: [PATCH 08/12] extend examples --- examples/ExampleApps/LabelDrawableExampleApp.cpp | 1 + examples/ExampleApps/MovingCubeApp.cpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/examples/ExampleApps/LabelDrawableExampleApp.cpp b/examples/ExampleApps/LabelDrawableExampleApp.cpp index 1ca40b7..72271d8 100644 --- a/examples/ExampleApps/LabelDrawableExampleApp.cpp +++ b/examples/ExampleApps/LabelDrawableExampleApp.cpp @@ -88,6 +88,7 @@ namespace OpenVulkano label.AddText("Additional text" + std::to_string(j)); } } + m_drawablesPool[i].SetIsHittable(true); m_scene.GetRoot()->AddChild(&m_nodesPool[i]); m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(-5 + std::rand() % 5, -5 + std::rand() % 5, -std::rand() % 10))); m_nodesPool[i].AddDrawable(&m_drawablesPool[i]); diff --git a/examples/ExampleApps/MovingCubeApp.cpp b/examples/ExampleApps/MovingCubeApp.cpp index 1f637b0..a866e9f 100644 --- a/examples/ExampleApps/MovingCubeApp.cpp +++ b/examples/ExampleApps/MovingCubeApp.cpp @@ -71,6 +71,8 @@ namespace OpenVulkano void CompleteSceneElement(SceneElement *dest) { dest->m_drawable.Init(&m_shader, &dest->m_geometry, &m_material); + dest->m_drawable.SetIsHittable(true); + //dest->m_geometry.freeAfterUpload = false; dest->m_node.Init(); m_scene.GetRoot()->AddChild(&dest->m_node); dest->m_node.SetUpdateFrequency(Scene::UpdateFrequency::Always); @@ -81,24 +83,28 @@ namespace OpenVulkano void CreateSceneElement(SceneElement *dest, const Math::Vector4f &color, float scale) { dest->m_geometry = Scene::GeometryFactory::MakeCube(scale, scale, scale, color); + dest->m_geometry.name = fmt::format("Cube {} {} {}", color.r, color.g, color.b); CompleteSceneElement(dest); } void CreatePlane(SceneElement *dest, const Math::Vector4f &color) { dest->m_geometry = Scene::GeometryFactory::MakePlane(1, 1, color); + dest->m_geometry.name = "Plane"; CompleteSceneElement(dest); } void CreateSphere(SceneElement *dest, const Math::Vector4f &color) { dest->m_geometry = Scene::GeometryFactory::MakeSphere(1, 32, 16, color); + dest->m_geometry.name = "Sphere"; CompleteSceneElement(dest); } void CreateHemisphere(SceneElement *dest, const Math::Vector4f &color) { dest->m_geometry = Scene::GeometryFactory::MakeHemisphere(1, 16, 16, color); + dest->m_geometry.name = "Hemisphere"; CompleteSceneElement(dest); } @@ -106,18 +112,21 @@ namespace OpenVulkano { dest->m_geometry = Scene::GeometryFactory::MakeTriangle( Math::Vector3f(0.5, 0., 0.), Math::Vector3f(0., 0.5, 0.), Math::Vector3f(-0.5, 0., 0.), color); + dest->m_geometry.name = "Triangle"; CompleteSceneElement(dest); } void CreateCylinder(SceneElement *dest, const Math::Vector4f &color) { dest->m_geometry = Scene::GeometryFactory::MakeCylinder(1, 3, 64, color); + dest->m_geometry.name = "Cylinder"; CompleteSceneElement(dest); } void CreatePyramid(SceneElement *dest, const Math::Vector4f &color) { dest->m_geometry = Scene::GeometryFactory::MakePyramid(0.5, 2, color); + dest->m_geometry.name = "Pyramid"; CompleteSceneElement(dest); } From e2df88ca226b24554ac14b938b9fb1e920ac80ab Mon Sep 17 00:00:00 2001 From: ohyzha Date: Mon, 4 Nov 2024 22:48:35 +0200 Subject: [PATCH 09/12] code refactoring --- .../Controller/CameraController.cpp | 7 +- openVulkanoCpp/Scene/Camera.cpp | 22 +++--- openVulkanoCpp/Scene/Node.cpp | 9 +++ openVulkanoCpp/Scene/Node.hpp | 2 + openVulkanoCpp/Scene/Scene.hpp | 5 +- openVulkanoCpp/Scene/SimpleDrawable.cpp | 69 +++++++++++-------- openVulkanoCpp/Scene/TextDrawable.hpp | 2 +- 7 files changed, 71 insertions(+), 45 deletions(-) diff --git a/openVulkanoCpp/Controller/CameraController.cpp b/openVulkanoCpp/Controller/CameraController.cpp index 81ba2e1..1a8d195 100644 --- a/openVulkanoCpp/Controller/CameraController.cpp +++ b/openVulkanoCpp/Controller/CameraController.cpp @@ -14,9 +14,8 @@ namespace OpenVulkano m_camera = camera; m_actionCastRay = m_inputManager->GetAction("cast ray"); m_actionCastRay->BindKey(Input::InputKey::Mouse::BUTTON_1); - // BIND FOR TOUCH - m_actionCastRay->BindKey(Input::InputKey::Touch::AXIS_TAP_X); m_actionCastRay->BindKey(Input::InputKey::Touch::AXIS_TAP_X); + m_actionCastRay->BindKey(Input::InputKey::Touch::AXIS_TAP_Y); } void CameraController::Tick() @@ -30,7 +29,9 @@ namespace OpenVulkano Math::Vector2i pos = mouse->GetMousePosition(); mouse->onLeftButtonClick.NotifyAll(pos); } - else if (touch) + // not sure about second condition here, but here should be something + else if (touch && (touch->GetAxis(Input::InputKey::Touch::AXIS_TAP_X) != 0 + || touch->GetAxis(Input::InputKey::Touch::AXIS_TAP_Y) != 0)) { Math::Vector2i pos = touch->GetTapPosition(); touch->OnTap.NotifyAll(pos); diff --git a/openVulkanoCpp/Scene/Camera.cpp b/openVulkanoCpp/Scene/Camera.cpp index 6253937..34d4533 100644 --- a/openVulkanoCpp/Scene/Camera.cpp +++ b/openVulkanoCpp/Scene/Camera.cpp @@ -52,17 +52,17 @@ namespace OpenVulkano::Scene } } } - if (res) - { - if (SimpleDrawable* sd = dynamic_cast(res->drawable)) - { - Logger::APP->info("Ray intersects object {}", sd->GetMesh()->name); - } - else if (LabelDrawable* sd = dynamic_cast(res->drawable)) - { - Logger::APP->info("Ray intersects label {}", sd->GetTexts().front().GetText()); - } - } + //if (res) + //{ + // if (SimpleDrawable* sd = dynamic_cast(res->drawable)) + // { + // Logger::APP->info("Ray intersects object {}", sd->GetMesh()->name); + // } + // else if (LabelDrawable* sd = dynamic_cast(res->drawable)) + // { + // Logger::APP->info("Ray intersects label {}", sd->GetTexts().front().GetText()); + // } + //} return res; } } diff --git a/openVulkanoCpp/Scene/Node.cpp b/openVulkanoCpp/Scene/Node.cpp index c362f43..344d669 100644 --- a/openVulkanoCpp/Scene/Node.cpp +++ b/openVulkanoCpp/Scene/Node.cpp @@ -110,6 +110,15 @@ namespace OpenVulkano::Scene UpdateWorldMatrix(parent ? parent->GetWorldMatrix() : Math::Matrix4f(1)); } + Node* Node::GetRoot() + { + if (IsRoot() || !parent) + { + return this; + } + return parent->GetRoot(); + } + void Node::UpdateWorldMatrix(const Math::Matrix4f& parentWorldMat) { worldMat = parentWorldMat * localMat; diff --git a/openVulkanoCpp/Scene/Node.hpp b/openVulkanoCpp/Scene/Node.hpp index 70bb07f..abcdcff 100644 --- a/openVulkanoCpp/Scene/Node.hpp +++ b/openVulkanoCpp/Scene/Node.hpp @@ -67,6 +67,8 @@ namespace OpenVulkano::Scene void SetMatrix(const Math::Matrix4f& mat); + [[nodiscard]] Node* GetRoot(); + [[nodiscard]] Math::Matrix3f GetRotationMatrix() const { return static_cast(localMat); } [[nodiscard]] const Math::Matrix4f& GetMatrix() const { return localMat; } diff --git a/openVulkanoCpp/Scene/Scene.hpp b/openVulkanoCpp/Scene/Scene.hpp index c4babf5..a3dc720 100644 --- a/openVulkanoCpp/Scene/Scene.hpp +++ b/openVulkanoCpp/Scene/Scene.hpp @@ -88,7 +88,10 @@ namespace OpenVulkano virtual void SetCamera(Camera* camera) { this->camera = camera; - camera->scene = this; + if (!camera->scene) + { + this->GetRoot()->AddChild(camera->GetRoot()); + } } Camera* GetCamera() const diff --git a/openVulkanoCpp/Scene/SimpleDrawable.cpp b/openVulkanoCpp/Scene/SimpleDrawable.cpp index cc2de23..2d8aa99 100644 --- a/openVulkanoCpp/Scene/SimpleDrawable.cpp +++ b/openVulkanoCpp/Scene/SimpleDrawable.cpp @@ -8,7 +8,9 @@ #include "Scene/Geometry.hpp" #include "Scene/Shader/Shader.hpp" #include "Base/Logger.hpp" +#include #include +#include namespace OpenVulkano::Scene { @@ -40,49 +42,58 @@ namespace OpenVulkano::Scene { m_mesh->CalculateAABB(); } - if (ray.IntersectAABB(m_mesh->aabb)) + auto bboxHit = ray.IntersectAABB(m_mesh->aabb); + if (!bboxHit) { - if (GetShader()->topology == Topology::TRIANGLE_LIST) + return {}; + } + if (GetShader()->topology == Topology::TRIANGLE_LIST) + { + if (m_mesh->indexCount != 0) { - if (m_mesh->indexCount != 0) + assert(m_mesh->indexCount % 3 == 0 && "Topology is TRIANGLE_LIST but index count is not divisible by 3"); + for (int i = 0; i < m_mesh->indexCount; i += 3) { - for (int i = 0; i < m_mesh->indexCount / 3; i++) + if (m_mesh->indexType == VertexIndexType::UINT16) { - if (m_mesh->indexType == VertexIndexType::UINT16) + uint16_t* indices = m_mesh->GetIndices16(); + if (auto hit = ray.IntersectTriangle(m_mesh->vertices[indices[i]].position, + m_mesh->vertices[indices[i + 1]].position, + m_mesh->vertices[indices[i + 2]].position)) { - uint16_t* indices = m_mesh->GetIndices16(); - if (auto hit = ray.IntersectTriangle(m_mesh->vertices[indices[i * 3]].position, - m_mesh->vertices[indices[i * 3 + 1]].position, - m_mesh->vertices[indices[i * 3 + 2]].position)) - { - return hit; - } - } - else - { - uint32_t* indices = m_mesh->GetIndices32(); - if (auto hit = ray.IntersectTriangle(m_mesh->vertices[indices[i * 3]].position, - m_mesh->vertices[indices[i * 3 + 1]].position, - m_mesh->vertices[indices[i * 3 + 2]].position)) - { - return hit; - } + return hit; } } - } - else - { - for (int i = 0; i < m_mesh->vertexCount / 3; i++) + else { - if (auto hit = ray.IntersectTriangle(m_mesh->vertices[i * 3].position, - m_mesh->vertices[i * 3 + 1].position, - m_mesh->vertices[i * 3 + 2].position)) + uint32_t* indices = m_mesh->GetIndices32(); + if (auto hit = ray.IntersectTriangle(m_mesh->vertices[indices[i]].position, + m_mesh->vertices[indices[i + 1]].position, + m_mesh->vertices[indices[i + 2]].position)) { return hit; } } } } + else + { + assert(m_mesh->indexCount % 3 == 0 && "Topology is TRIANGLE_LIST but vertex count is not divisible by 3"); + for (int i = 0; i < m_mesh->vertexCount; i += 3) + { + if (auto hit = ray.IntersectTriangle(m_mesh->vertices[i].position, + m_mesh->vertices[i + 1].position, + m_mesh->vertices[i + 2].position)) + { + return hit; + } + } + } + } + else + { + Logger::APP->debug("Bbox is hit, but intersection check for topology {} is not implemented", magic_enum::enum_name(GetShader()->topology)); + return bboxHit; } return {}; } diff --git a/openVulkanoCpp/Scene/TextDrawable.hpp b/openVulkanoCpp/Scene/TextDrawable.hpp index ae7f8b5..3896651 100644 --- a/openVulkanoCpp/Scene/TextDrawable.hpp +++ b/openVulkanoCpp/Scene/TextDrawable.hpp @@ -51,7 +51,7 @@ namespace OpenVulkano::Scene Math::AABB& GetBoundingBox() { return m_bbox; } TextConfig& GetConfig() { return m_cfg; } Shader* GetShader() { return m_shader; } - std::string& GetText() { return m_text; } + [[nodiscard]] const std::string& GetText() const { return m_text; } std::shared_ptr GetAtlasData() { return m_atlasData; } private: Geometry m_geometry; From 3521ddeb1df05b1c488bf3f006c9f9e4eef32b3e Mon Sep 17 00:00:00 2001 From: ohyzha Date: Wed, 6 Nov 2024 09:48:53 +0200 Subject: [PATCH 10/12] rework API --- .clang-format | 2 +- examples/ExampleApps/MovingCubeApp.cpp | 20 +++++ examples/main.cpp | 5 +- .../Controller/CameraController.cpp | 41 --------- .../Controller/CameraController.hpp | 18 +--- .../Controller/FreeCamCameraController.cpp | 4 - openVulkanoCpp/Host/GraphicsAppManager.cpp | 87 +++++++++---------- openVulkanoCpp/Host/GraphicsAppManager.hpp | 7 -- openVulkanoCpp/Input/InputDeviceMouse.cpp | 6 +- openVulkanoCpp/Input/InputDeviceMouse.hpp | 7 +- openVulkanoCpp/Input/InputKey.hpp | 4 +- openVulkanoCpp/Input/InputManager.cpp | 43 ++++++++- openVulkanoCpp/Input/InputManager.hpp | 4 + .../Input/Touch/InputDeviceTouch.hpp | 1 - openVulkanoCpp/Scene/Camera.cpp | 45 +--------- openVulkanoCpp/Scene/Camera.hpp | 31 +------ openVulkanoCpp/Scene/Ray.cpp | 25 ++++-- openVulkanoCpp/Scene/Ray.hpp | 19 +++- .../Scene/SceneIntersectionTestController.cpp | 68 +++++++++++++++ .../Scene/SceneIntersectionTestController.hpp | 33 +++++++ tests/RayTests.cpp | 56 +++++++----- 21 files changed, 296 insertions(+), 230 deletions(-) delete mode 100644 openVulkanoCpp/Controller/CameraController.cpp create mode 100644 openVulkanoCpp/Scene/SceneIntersectionTestController.cpp create mode 100644 openVulkanoCpp/Scene/SceneIntersectionTestController.hpp diff --git a/.clang-format b/.clang-format index 0a4a8f9..ed47f3a 100644 --- a/.clang-format +++ b/.clang-format @@ -37,7 +37,7 @@ SortIncludes: Never SortUsingDeclarations: Never SpaceAfterCStyleCast: true SpaceAfterTemplateKeyword: false -SpaceBeforeRangeBasedForLoopColon: false +SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyBlock: false SpacesInAngles: false SpacesInContainerLiterals: false diff --git a/examples/ExampleApps/MovingCubeApp.cpp b/examples/ExampleApps/MovingCubeApp.cpp index a866e9f..d33dcd8 100644 --- a/examples/ExampleApps/MovingCubeApp.cpp +++ b/examples/ExampleApps/MovingCubeApp.cpp @@ -19,11 +19,15 @@ #include "Scene/MorphableCameraController.hpp" #include "Scene/PlaneCameraController.hpp" #include "Scene/UI/PerformanceInfo.hpp" +#include "Scene/SceneIntersectionTestController.hpp" #include "Input/InputManager.hpp" #include "Host/GraphicsAppManager.hpp" #include "Base/EngineConfiguration.hpp" #include "Base/Logger.hpp" #include "Controller/FreeCamCameraController.hpp" +#include "Scene/Prefabs/LabelDrawable.hpp" +#include "Scene/SimpleDrawable.hpp" +#include "Scene/Ray.hpp" #define USE_PLANE_CAM_CONTROL 0 @@ -54,6 +58,7 @@ namespace OpenVulkano Scene::SimpleAnimationController m_simpleAnimationController; Scene::SequenceAnimationController m_sequenceAnimationController; + Scene::SceneIntersectionTestController intersectionTestController; Scene::UI::SimpleUi m_ui; std::shared_ptr m_perfInfo; @@ -154,6 +159,10 @@ namespace OpenVulkano m_shader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/basic"); m_shader.AddVertexInputDescription(Vertex::GetVertexInputDescription()); + intersectionTestController.OnHit += EventHandler(this, &MovingCubeAppImpl::OnRayHit); + intersectionTestController.SetCamera(&m_camera); + intersectionTestController.SetDefaultKeybindings(); + GetGraphicsAppManager()->GetRenderer()->SetScene(&m_scene); #if USE_PLANE_CAM_CONTROL m_cameraControl.Init(&m_camera, PLANE_NORMAL); @@ -219,12 +228,23 @@ namespace OpenVulkano anim->Reset(); } + void OnRayHit(const Scene::DrawableRayHit &hit) + { + using namespace Scene; + Drawable *d = hit.drawable; + if (SimpleDrawable *sd = dynamic_cast(d)) + { + Logger::APP->info("Ray intersects object {}", sd->GetMesh()->name); + } + } + void Tick() override { m_cameraControl.Tick(); m_morphableCameraControl.Tick(); m_simpleAnimationController.Tick(); m_sequenceAnimationController.Tick(); + intersectionTestController.Tick(); } void Close() override {} diff --git a/examples/main.cpp b/examples/main.cpp index 6d53bf2..002e431 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -19,8 +19,6 @@ using namespace OpenVulkano; int main(int argc, char** argv) { - GraphicsAppManager manager; - std::vector examples; for (const auto& e : EXAMPLE_APPS) { @@ -38,7 +36,8 @@ int main(int argc, char** argv) if (selectedExample >= examples.size()) throw std::runtime_error("Invalid menu selection!"); std::unique_ptr app( EXAMPLE_APPS[selectedExample].second() ); - manager.SetApp(app.get()); + + GraphicsAppManager manager(app.get()); manager.Run(); return 0; } diff --git a/openVulkanoCpp/Controller/CameraController.cpp b/openVulkanoCpp/Controller/CameraController.cpp deleted file mode 100644 index 1a8d195..0000000 --- a/openVulkanoCpp/Controller/CameraController.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "CameraController.hpp" -#include "Scene/Camera.hpp" -#include "Input/InputDeviceMouse.hpp" -#include "Input/InputDeviceController.hpp" -#include "Input/InputManager.hpp" -#include "Input/Touch/InputDeviceTouch.hpp" - - -namespace OpenVulkano -{ - CameraController::CameraController(Scene::Camera* camera) - { - m_inputManager = Input::InputManager::GetInstance(); - m_camera = camera; - m_actionCastRay = m_inputManager->GetAction("cast ray"); - m_actionCastRay->BindKey(Input::InputKey::Mouse::BUTTON_1); - m_actionCastRay->BindKey(Input::InputKey::Touch::AXIS_TAP_X); - m_actionCastRay->BindKey(Input::InputKey::Touch::AXIS_TAP_Y); - } - - void CameraController::Tick() - { - Input::InputDeviceMouse* mouse = static_cast(m_inputManager->GetDevice(Input::InputDeviceType::MOUSE)); - Input::InputDeviceTouch* touch = static_cast(m_inputManager->GetDevice(Input::InputDeviceType::TOUCH)); - if (m_camera->CanCastRay() && m_inputManager->GetButton(m_actionCastRay)) - { - if (mouse && mouse->GetButtonDown(Input::InputKey::Mouse::BUTTON_1)) - { - Math::Vector2i pos = mouse->GetMousePosition(); - mouse->onLeftButtonClick.NotifyAll(pos); - } - // not sure about second condition here, but here should be something - else if (touch && (touch->GetAxis(Input::InputKey::Touch::AXIS_TAP_X) != 0 - || touch->GetAxis(Input::InputKey::Touch::AXIS_TAP_Y) != 0)) - { - Math::Vector2i pos = touch->GetTapPosition(); - touch->OnTap.NotifyAll(pos); - } - } - } -} diff --git a/openVulkanoCpp/Controller/CameraController.hpp b/openVulkanoCpp/Controller/CameraController.hpp index 9650b04..80bfa2d 100644 --- a/openVulkanoCpp/Controller/CameraController.hpp +++ b/openVulkanoCpp/Controller/CameraController.hpp @@ -11,12 +11,6 @@ namespace OpenVulkano { - namespace Input - { - class InputAction; - class InputManager; - } - namespace Scene { class Camera; @@ -24,26 +18,22 @@ namespace OpenVulkano class CameraController : public ITickable, ICloseable { - protected: Scene::Camera* m_camera; - Input::InputAction* m_actionCastRay; - Input::InputManager* m_inputManager; - CameraController(Scene::Camera* camera = nullptr); + protected: + CameraController(Scene::Camera* camera = nullptr) + : m_camera(camera) + {} public: ~CameraController() override = default; - void Tick() override; - virtual void Init(Scene::Camera* camera) { m_camera = camera; } void Close() override { m_camera = nullptr; } void SetCamera(Scene::Camera* camera) { m_camera = camera; } - Input::InputAction* GetActionCastRay() { return m_actionCastRay; } - Scene::Camera* GetCamera() { return m_camera; } virtual void SetActive() {} diff --git a/openVulkanoCpp/Controller/FreeCamCameraController.cpp b/openVulkanoCpp/Controller/FreeCamCameraController.cpp index 7f0a082..8f94d3e 100644 --- a/openVulkanoCpp/Controller/FreeCamCameraController.cpp +++ b/openVulkanoCpp/Controller/FreeCamCameraController.cpp @@ -8,7 +8,6 @@ #include "Base/FrameMetadata.hpp" #include "Scene/Camera.hpp" #include "Input/InputManager.hpp" -#include "Input/InputDeviceMouse.hpp" #include "Input/InputKey.hpp" namespace OpenVulkano @@ -40,8 +39,6 @@ namespace OpenVulkano vec *= m_boostFactor; } - CameraController::Tick(); - m_yaw -= input->GetAxis(m_actionLookSide) * timeScale / 2.0f; m_pitch -= input->GetAxis(m_actionLookUp) * timeScale / 2.0f; m_pitch = std::min(1.4f, std::max(-1.4f, m_pitch)); @@ -51,7 +48,6 @@ namespace OpenVulkano Math::Matrix4f camTransformation = Math::Utils::toMat4(rot); camTransformation[3] = Math::Vector4f(m_position, 1); GetCamera()->SetMatrix(camTransformation); - //CameraController::Tick(); CURRENT_FRAME.needsRedraw = true; } diff --git a/openVulkanoCpp/Host/GraphicsAppManager.cpp b/openVulkanoCpp/Host/GraphicsAppManager.cpp index 3b07ddd..8457e07 100644 --- a/openVulkanoCpp/Host/GraphicsAppManager.cpp +++ b/openVulkanoCpp/Host/GraphicsAppManager.cpp @@ -24,64 +24,65 @@ namespace OpenVulkano { using clock = std::chrono::steady_clock; - GraphicsAppManager::GraphicsAppManager(RenderAPI::RenderApi renderApi) { Init(nullptr, nullptr, renderApi); } - GraphicsAppManager::GraphicsAppManager(OpenVulkano::IGraphicsApp* app, RenderAPI::RenderApi renderApi) : app(app), renderApi(renderApi) - { - Init(app, nullptr, renderApi); - } - - GraphicsAppManager::GraphicsAppManager(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi) - : app(app), renderApi(renderApi) - { - Init(app, window, renderApi); - } - - void GraphicsAppManager::SetApp(IGraphicsApp* app) - { - this->app = app; - app->SetGraphicsAppManager(this); - } - - void GraphicsAppManager::Init(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi) { Utils::SetThreadName("Main"); #ifdef HAS_TRACY ZoneScoped; #endif + + Logger::SetupLogger(); - Logger::MANAGER->info("Initializing graphics app manager ..."); - this->renderApi = renderApi; + if (!app) + { + constexpr auto msg = "The app must not be null!"; + Logger::MANAGER->error(msg); + throw std::runtime_error(msg); + } platform = std::unique_ptr(PlatformProducer::CreatePlatform(renderApi)); + window = platform->MakeWindow(); renderer = std::unique_ptr(PlatformProducer::CreateRenderManager(renderApi)); + app->SetGraphicsAppManager(this); + window->SetWindowHandler(this); inputManager = Input::InputManager::GetInstance(); engineConfig = EngineConfiguration::GetEngineConfiguration(); engineConfig->OnFpsCapChanged += EventHandler(this, &GraphicsAppManager::UpdateCappedFpsInfo); - if (window) - { - this->window = window; - } - else - { - this->window = platform->MakeWindow(); - } - if (app) - { - app->SetGraphicsAppManager(this); - } - this->window->SetWindowHandler(this); - // set initial values if (engineConfig->GetFpsCap() > 0) { UpdateCappedFpsInfo(engineConfig->GetFpsCap()); } - if (platform) + } + + GraphicsAppManager::GraphicsAppManager(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi) + : app(app), renderApi(renderApi) + { + Utils::SetThreadName("Main"); +#ifdef HAS_TRACY + ZoneScoped; +#endif + + Logger::SetupLogger(); + if (!app) { - platform->Init(); + constexpr auto msg = "The app must not be null!"; + Logger::MANAGER->error(msg); + throw std::runtime_error(msg); + } + //platform = std::unique_ptr(PlatformProducer::CreatePlatform(renderApi)); + this->window = window; + renderer = std::unique_ptr(PlatformProducer::CreateRenderManager(renderApi)); + app->SetGraphicsAppManager(this); + window->SetWindowHandler(this); + inputManager = OpenVulkano::Input::InputManager::GetInstance(); + engineConfig = OpenVulkano::EngineConfiguration::GetEngineConfiguration(); + engineConfig->OnFpsCapChanged += EventHandler(this, &GraphicsAppManager::UpdateCappedFpsInfo); + // set initial values + if (engineConfig->GetFpsCap() > 0) + { + UpdateCappedFpsInfo(engineConfig->GetFpsCap()); } - Logger::MANAGER->info("Initialized..."); } void GraphicsAppManager::UpdateCappedFpsInfo(int32_t newFpsCap) @@ -143,12 +144,6 @@ namespace OpenVulkano void GraphicsAppManager::StartUp() { - if (!app) - { - constexpr auto msg = "The app must not be null!"; - Logger::MANAGER->error(msg); - throw std::runtime_error(msg); - } #ifdef HAS_TRACY ZoneScoped; #endif @@ -156,9 +151,7 @@ namespace OpenVulkano { Logger::MANAGER->info("Initializing ..."); app->Init(); - - //if (platform) platform->Init(); - + if (platform) platform->Init(); window->Init(renderApi); //TODO restore window settings if there are any set renderer->Init(static_cast(this), window); diff --git a/openVulkanoCpp/Host/GraphicsAppManager.hpp b/openVulkanoCpp/Host/GraphicsAppManager.hpp index d07b626..d48704a 100644 --- a/openVulkanoCpp/Host/GraphicsAppManager.hpp +++ b/openVulkanoCpp/Host/GraphicsAppManager.hpp @@ -48,17 +48,10 @@ namespace OpenVulkano void OnCappedFPS(const auto& frameStartTime); void UpdateCappedFpsInfo(int32_t newFpsCap); public: - - GraphicsAppManager(RenderAPI::RenderApi renderApi = RenderAPI::Vulkan); - explicit GraphicsAppManager(IGraphicsApp* app, RenderAPI::RenderApi renderApi = RenderAPI::Vulkan); explicit GraphicsAppManager(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi = RenderAPI::Vulkan); - void SetApp(IGraphicsApp* app); - - void Init(IGraphicsApp* app, IWindow* window, RenderAPI::RenderApi renderApi); - ~GraphicsAppManager() noexcept override; public: // Getter diff --git a/openVulkanoCpp/Input/InputDeviceMouse.cpp b/openVulkanoCpp/Input/InputDeviceMouse.cpp index 626e905..a320e89 100644 --- a/openVulkanoCpp/Input/InputDeviceMouse.cpp +++ b/openVulkanoCpp/Input/InputDeviceMouse.cpp @@ -33,6 +33,8 @@ namespace OpenVulkano::Input { axes[InputKey::Mouse::AXIS_X] = static_cast(posX - mousePosX); axes[InputKey::Mouse::AXIS_Y] = static_cast(posY - mousePosY); + axes[InputKey::Mouse::AXIS_X_ABS] = posX; + axes[InputKey::Mouse::AXIS_Y_ABS] = posY; mousePosX = posX; mousePosY = posY; Logger::INPUT->trace("Mouse moved posX: {0} posY: {1}, relativeX: {2}, relativeY: {3}", posX, posY, axes[InputKey::Mouse::AXIS_X], axes[InputKey::Mouse::AXIS_Y]); @@ -53,9 +55,9 @@ namespace OpenVulkano::Input void InputDeviceMouse::ClearAxes() { - for (float& axis : axes) + for (int i = 2; i < AXES_SIZE; i++) { - axis = 0; + axes[i] = 0; } } } \ No newline at end of file diff --git a/openVulkanoCpp/Input/InputDeviceMouse.hpp b/openVulkanoCpp/Input/InputDeviceMouse.hpp index 29f2cf1..21a5944 100644 --- a/openVulkanoCpp/Input/InputDeviceMouse.hpp +++ b/openVulkanoCpp/Input/InputDeviceMouse.hpp @@ -8,7 +8,6 @@ #include "InputDevice.hpp" #include "Math/Math.hpp" -#include "Base/Event.hpp" namespace OpenVulkano { @@ -18,7 +17,8 @@ namespace OpenVulkano { class InputDeviceMouse : public InputDevice { - float axes[InputKey::Mouse::Axis::AXIS_LAST + 2] = { 0 }; + static constexpr int AXES_SIZE = InputKey::Mouse::Axis::AXIS_LAST + 2; + float axes[AXES_SIZE] = { 0 }; uint8_t pressedButtons = 0, lastPressedButtons = 0; double mousePosX = 0, mousePosY = 0; IWindow* lastWindow = nullptr; @@ -144,9 +144,6 @@ namespace OpenVulkano { return window == lastWindow; } - - Event onLeftButtonClick; - }; } } \ No newline at end of file diff --git a/openVulkanoCpp/Input/InputKey.hpp b/openVulkanoCpp/Input/InputKey.hpp index 7640e4a..8e37b7b 100644 --- a/openVulkanoCpp/Input/InputKey.hpp +++ b/openVulkanoCpp/Input/InputKey.hpp @@ -177,7 +177,9 @@ namespace OpenVulkano::Input enum Axis : int16_t { - AXIS_X = 0, + AXIS_X_ABS = 0, + AXIS_Y_ABS, + AXIS_X, AXIS_Y, AXIS_WHEEL_X, AXIS_WHEEL_Y, diff --git a/openVulkanoCpp/Input/InputManager.cpp b/openVulkanoCpp/Input/InputManager.cpp index af918a3..b93efbd 100644 --- a/openVulkanoCpp/Input/InputManager.cpp +++ b/openVulkanoCpp/Input/InputManager.cpp @@ -75,6 +75,23 @@ namespace OpenVulkano::Input return false; } + bool InputManager::GetButtonDown(InputAction* action) const + { + const std::vector& testDevices = action->GetDevices().empty() ? devices : action->GetDevices(); + for (const InputDevice* device : testDevices) + { + for (const KeyBinding binding : action->GetKeys()) + { + if (binding.key.GetInputDeviceType() != device->GetType()) + { + continue; + } + return device->GetButtonDown(binding.key); + } + } + return false; + } + bool InputManager::GetButton(InputKey key) const { for(const InputDevice* device : devices) @@ -87,9 +104,13 @@ namespace OpenVulkano::Input InputDevice* InputManager::GetDevice(InputDeviceType type) const { - for (InputDevice* device: devices) + if (type == InputDeviceType::UNKNOWN) { - if (device->GetType() == type && type != InputDeviceType::UNKNOWN) + return nullptr; + } + for (InputDevice* device : devices) + { + if (device->GetType() == type) { return device; } @@ -97,6 +118,24 @@ namespace OpenVulkano::Input return nullptr; } + std::vector InputManager::GetDevices(InputDeviceType type) const + { + if (type == InputDeviceType::UNKNOWN) + { + return {}; + } + std::vector devices; + devices.reserve(this->devices.size()); + for (InputDevice* device : this->devices) + { + if (device->GetType() == type) + { + devices.push_back(device); + } + } + return devices; + } + void InputManager::Tick() { for(InputDevice* device : devices) diff --git a/openVulkanoCpp/Input/InputManager.hpp b/openVulkanoCpp/Input/InputManager.hpp index 774b65c..116effb 100644 --- a/openVulkanoCpp/Input/InputManager.hpp +++ b/openVulkanoCpp/Input/InputManager.hpp @@ -40,10 +40,14 @@ namespace OpenVulkano::Input [[nodiscard]] bool GetButton(InputAction* action) const; + [[nodiscard]] bool GetButtonDown(InputAction* action) const; + [[nodiscard]] bool GetButton(InputKey key) const; [[nodiscard]] InputDevice* GetDevice(InputDeviceType type) const; + [[nodiscard]] std::vector GetDevices(InputDeviceType type) const; + [[nodiscard]] InputDevice* GetLastActiveDevice() const { return lastActiveDevice; diff --git a/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp b/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp index 8fde139..7d0dfa7 100644 --- a/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp +++ b/openVulkanoCpp/Input/Touch/InputDeviceTouch.hpp @@ -84,6 +84,5 @@ namespace OpenVulkano::Input [[nodiscard]] bool IsMultiTouch() const { return m_multiTouch; } Event OnTouchAdded, OnTouchDown, OnTouchUp, OnTouchMoved, OnTouchRemoved; - Event OnTap; }; } diff --git a/openVulkanoCpp/Scene/Camera.cpp b/openVulkanoCpp/Scene/Camera.cpp index 34d4533..a0d45b8 100644 --- a/openVulkanoCpp/Scene/Camera.cpp +++ b/openVulkanoCpp/Scene/Camera.cpp @@ -5,24 +5,14 @@ */ #include "Camera.hpp" -#include "Scene/Scene.hpp" -#include "Scene/SimpleDrawable.hpp" -#include "Scene/Geometry.hpp" -#include "Scene/Shader/Shader.hpp" -#include "Scene/TextDrawable.hpp" -#include "Scene/Prefabs/LabelDrawable.hpp" -#include "Scene/Ray.hpp" -#include "Scene/TextDrawable.hpp" namespace OpenVulkano::Scene { - std::optional PerspectiveCamera::CastRay(const Math::Vector2i& xy) const + Ray Camera::CastRay(const Math::Vector2i& xy) const { using namespace Math::Utils; - auto scene = GetScene(); - // nds float ndsX = (2.f * xy.x) / m_width - 1.0f; float ndsY = (2.f * xy.y) / m_height - 1.0f; @@ -34,35 +24,8 @@ namespace OpenVulkano::Scene rayEye.a = 0; Math::Vector3f rayWorld = normalize(inverse(m_view) * rayEye); - - std::optional res; - for (Drawable* d: scene->rayHittableDrawables) - { - const auto& m = d->GetNodes()[0]->GetWorldMatrix(); - const Math::Vector3f rayLocalDir = normalize(inverse(m) * Math::Vector4f(rayWorld, 0)); - const Math::Vector4f rayLocalPos = inverse(m) * m_camPosition; - const Ray ray(rayLocalPos, rayLocalDir); - if (auto hit = d->Intersect(ray)) - { - // choose the closest one - if (!res || (hit->distance < res->distance)) - { - res = hit; - res->drawable = d; - } - } - } - //if (res) - //{ - // if (SimpleDrawable* sd = dynamic_cast(res->drawable)) - // { - // Logger::APP->info("Ray intersects object {}", sd->GetMesh()->name); - // } - // else if (LabelDrawable* sd = dynamic_cast(res->drawable)) - // { - // Logger::APP->info("Ray intersects label {}", sd->GetTexts().front().GetText()); - // } - //} - return res; + + Ray r(GetPosition(), rayWorld); + return r; } } diff --git a/openVulkanoCpp/Scene/Camera.hpp b/openVulkanoCpp/Scene/Camera.hpp index 2788cf6..3735dfe 100644 --- a/openVulkanoCpp/Scene/Camera.hpp +++ b/openVulkanoCpp/Scene/Camera.hpp @@ -9,10 +9,7 @@ #include "Node.hpp" #include "Math/Math.hpp" #include "Math/Frustum.hpp" -#include "Input/InputDeviceMouse.hpp" -#include "Input/Touch/InputDeviceTouch.hpp" -#include "Input/InputManager.hpp" -#include "Base/Logger.hpp" +#include "Scene/Ray.hpp" #include namespace OpenVulkano::Scene @@ -31,7 +28,6 @@ namespace OpenVulkano::Scene float m_contentScaleFactor = 1, m_zoom = 1; // For use with ortho camera float m_interfaceOrientation = 0; float m_padding = 0; //Unused - bool m_canCastRay = true; Camera() : m_nearPlane(0), m_farPlane(0), m_width(0), m_height(0) {} @@ -50,20 +46,6 @@ namespace OpenVulkano::Scene m_farPlane = farPlane; Node::Init(); UpdateProjectionMatrix(); - if (m_canCastRay) - { - Input::InputDeviceMouse* mouse = static_cast(Input::InputManager::GetInstance()->GetDevice(Input::InputDeviceType::MOUSE)); - Input::InputDeviceTouch* touch = static_cast(Input::InputManager::GetInstance()->GetDevice(Input::InputDeviceType::TOUCH)); - if (mouse) - { - mouse->onLeftButtonClick += EventHandler(this, &Camera::CastRay); - } - else if (touch) - { - touch->OnTap += EventHandler(this, &Camera::CastRay); - } - } - } public: @@ -85,8 +67,6 @@ namespace OpenVulkano::Scene [[nodiscard]] float FarPlane() const { return m_farPlane; } - [[nodiscard]] bool CanCastRay() const { return m_canCastRay; } - void SetContentScaleFactor(float contentScale = 1) { m_contentScaleFactor = 1.0f / contentScale; @@ -104,7 +84,7 @@ namespace OpenVulkano::Scene virtual void UpdateProjectionMatrix() = 0; - virtual std::optional CastRay(const Math::Vector2i& xy) const = 0; + Ray CastRay(const Math::Vector2i& xy) const; void UpdateViewProjectionMatrix() { @@ -264,8 +244,6 @@ namespace OpenVulkano::Scene SetProjectionMatrix(Math::Utils::perspectiveRH_ZO(m_fov, m_aspect, m_nearPlane, m_farPlane)); } - std::optional CastRay(const Math::Vector2i& xy) const override; - [[nodiscard]] bool IsPerspective() const override { return true; } }; @@ -279,11 +257,6 @@ namespace OpenVulkano::Scene SetProjectionMatrix(Math::Utils::orthoRH_ZO(-widthHalf, widthHalf, -heightHalf, heightHalf, m_nearPlane, m_farPlane)); } - std::optional CastRay(const Math::Vector2i& xy) const override - { - throw std::runtime_error("Not implemented yet"); - } - [[nodiscard]] bool IsOrtho() const override { return true; } }; } diff --git a/openVulkanoCpp/Scene/Ray.cpp b/openVulkanoCpp/Scene/Ray.cpp index c082328..289e46d 100644 --- a/openVulkanoCpp/Scene/Ray.cpp +++ b/openVulkanoCpp/Scene/Ray.cpp @@ -41,7 +41,7 @@ namespace OpenVulkano::Scene RayHit hitRes; if (intersectRaySphere(m_origin, m_dir, center, radius, hitRes.point, hitRes.normal)) { - hitRes.distance = distance(m_origin, hitRes.point); + hitRes.distance2 = distance2(m_origin, hitRes.point); return hitRes; } return {}; @@ -57,6 +57,7 @@ namespace OpenVulkano::Scene Math::Vector3f e = v1 - v0; Math::Vector3f e2 = v2 - v0; // triangle normal. won't work if triangle is smoothly shaded. use other overloaded method instead. + hitRes.distance2 = distance2(m_origin, hitRes.point); hitRes.normal = normalize(cross(e, e2)); return hitRes; } @@ -99,7 +100,7 @@ namespace OpenVulkano::Scene case 1: return h1; case 2: - return (h1.distance < h2.distance) ? h1 : h2; + return (h1.distance2 < h2.distance2) ? h1 : h2; } return {}; } @@ -169,8 +170,8 @@ namespace OpenVulkano::Scene p1.point = m_origin + txmin * m_dir; p2.point = m_origin + txmax * m_dir; - p1.distance = distance(m_origin, p1.point); - p2.distance = distance(m_origin, p2.point); + p1.distance2 = distance2(m_origin, p1.point); + p2.distance2 = distance2(m_origin, p2.point); p1.normal = p2.normal = Math::Vector3f(0); return intersections; } @@ -182,6 +183,7 @@ namespace OpenVulkano::Scene if (intersectRayPlane(m_origin, m_dir, pOrigin, pNorm, hit.distance)) { hit.point = m_origin + m_dir * hit.distance; + hit.distance2 = distance2(m_origin, hit.point); hit.normal = norm; return hit; } @@ -214,7 +216,7 @@ namespace OpenVulkano::Scene return 0; } p1.point = m_origin + x1 * m_dir; - p1.distance = distance(m_origin, p1.point); + p1.distance2 = distance2(m_origin, p1.point); p1.normal = normalize(p1.point - center); p2 = p1; } @@ -228,10 +230,10 @@ namespace OpenVulkano::Scene if (x1 >= 0 && x2 >= 0) { p1.point = m_origin + x1 * m_dir; - p1.distance = distance(m_origin, p1.point); + p1.distance2 = distance2(m_origin, p1.point); p1.normal = normalize(p1.point - center); p2.point = m_origin + x2 * m_dir; - p2.distance = distance(m_origin, p2.point); + p2.distance2 = distance2(m_origin, p2.point); p2.normal = normalize(p2.point - center); } else @@ -242,11 +244,18 @@ namespace OpenVulkano::Scene x1 = x2; } p1.point = m_origin + x1 * m_dir; - p1.distance = distance(m_origin, p1.point); + p1.distance2 = distance2(m_origin, p1.point); p1.normal = normalize(p1.point - center); p2 = p1; } } return roots; } + + bool RayHit::operator==(const RayHit& other) const + { + return distance2 == other.distance2 && point == other.point && normal == other.normal; + } + + bool RayHit::operator!=(const RayHit& other) const { return !(*this == other); } } diff --git a/openVulkanoCpp/Scene/Ray.hpp b/openVulkanoCpp/Scene/Ray.hpp index 044c14a..6413eaa 100644 --- a/openVulkanoCpp/Scene/Ray.hpp +++ b/openVulkanoCpp/Scene/Ray.hpp @@ -13,14 +13,26 @@ namespace OpenVulkano::Scene { class Drawable; + class Node; struct RayHit { Math::Vector3f point; Math::Vector3f normal; - float distance; - bool operator==(const RayHit& other) const = default; - bool operator!=(const RayHit& other) const = default; + float distance2; + [[nodiscard]] float GetDistance() const + { + if (distance == -1) + { + distance = std::sqrt(distance2); + } + return distance; + } + bool operator==(const RayHit& other) const; + bool operator!=(const RayHit& other) const; + friend class Ray; + private: + mutable float distance = -1; }; struct DrawableRayHit : RayHit @@ -28,6 +40,7 @@ namespace OpenVulkano::Scene DrawableRayHit() = default; DrawableRayHit(const RayHit& hit) : RayHit(hit) {}; Drawable* drawable = nullptr; + Node* node = nullptr; }; class Ray diff --git a/openVulkanoCpp/Scene/SceneIntersectionTestController.cpp b/openVulkanoCpp/Scene/SceneIntersectionTestController.cpp new file mode 100644 index 0000000..bb18d68 --- /dev/null +++ b/openVulkanoCpp/Scene/SceneIntersectionTestController.cpp @@ -0,0 +1,68 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "Input/InputManager.hpp" +#include "SceneIntersectionTestController.hpp" +#include "Scene.hpp" +#include "SimpleDrawable.hpp" +#include "Prefabs/LabelDrawable.hpp" + +namespace OpenVulkano::Scene +{ + void SceneIntersectionTestController::Tick() + { + Input::InputManager* input = Input::InputManager::GetInstance(); + if (input->GetButtonDown(m_actionClick)) + { + const float x = input->GetAxis(m_actionClickX); + const float y = input->GetAxis(m_actionClickY); + const Ray ray = m_camera->CastRay(Math::Vector2i(x, y)); + const auto& camPos = m_camera->GetPosition(); + const auto scene = m_camera->GetScene(); + std::optional res; + for (Drawable* d : scene->rayHittableDrawables) + { + for (Node* n : d->GetNodes()) + { + const auto& m = n->GetWorldMatrix(); + const Math::Vector3f rayLocalDir = normalize(inverse(m) * Math::Vector4f(ray.GetDir(), 0)); + const Math::Vector4f rayLocalPos = inverse(m) * camPos; + const Ray ray(rayLocalPos, rayLocalDir); + if (auto hit = d->Intersect(ray)) + { + // choose the closest one + if (!res || (hit->distance2 < res->distance2)) + { + res = hit; + res->drawable = d; + res->node = n; + } + } + } + } + + if (res) + { + OnHit.NotifyAll(*res); + } + } + } + + void SceneIntersectionTestController::SetDefaultKeybindings() + { + auto input = Input::InputManager::GetInstance(); + m_actionClick = input->GetAction("ClickIntersection"); + m_actionClick->BindKey(Input::InputKey::Mouse::BUTTON_1); + m_actionClick->BindKey(Input::InputKey::Touch::BUTTON_TAP); + + m_actionClickX = input->GetAction("ClickIntersectionPosX"); + m_actionClickX->BindKey(Input::InputKey::Touch::Axis::AXIS_TAP_X); + m_actionClickX->BindKey(Input::InputKey::Mouse::Axis::AXIS_X_ABS); + m_actionClickY = input->GetAction("ClickIntersectionPosY"); + m_actionClickY->BindKey(Input::InputKey::Touch::Axis::AXIS_TAP_Y); + m_actionClickY->BindKey(Input::InputKey::Mouse::Axis::AXIS_Y_ABS); + } +} \ No newline at end of file diff --git a/openVulkanoCpp/Scene/SceneIntersectionTestController.hpp b/openVulkanoCpp/Scene/SceneIntersectionTestController.hpp new file mode 100644 index 0000000..f731c8c --- /dev/null +++ b/openVulkanoCpp/Scene/SceneIntersectionTestController.hpp @@ -0,0 +1,33 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#pragma once + +#include "Base/ITickable.hpp" +#include "Base/Event.hpp" +#include "Scene/Ray.hpp" +#include "Input/InputAction.hpp" +#include "Camera.hpp" + +namespace OpenVulkano::Scene +{ + class SceneIntersectionTestController : public ITickable + { + public: + SceneIntersectionTestController() = default; + SceneIntersectionTestController(Camera* camera) : m_camera(camera) {} + void SetCamera(Camera* camera) { m_camera = camera; } + [[nodiscard]] Camera* GetCamera() const { return m_camera; } + void Tick() override; + void SetDefaultKeybindings(); + Event OnHit; + + private: + Input::InputAction* m_actionClick = nullptr; + Input::InputAction* m_actionClickX = nullptr; + Input::InputAction* m_actionClickY = nullptr; + Camera* m_camera; + }; +} \ No newline at end of file diff --git a/tests/RayTests.cpp b/tests/RayTests.cpp index 0f25abd..73a6eca 100644 --- a/tests/RayTests.cpp +++ b/tests/RayTests.cpp @@ -28,48 +28,56 @@ namespace TEST_CASE("RaySphereIntersection") { auto sphere = GeometryFactory::MakeSphere(1, 32, 16); - RayHit h1, h2; // 2 intersections { + RayHit h1, h2; Ray ray(Vector3f(0, 0, -5), Vector3f(0, 0, 1)); REQUIRE(ray.IntersectSphere(Vector3f(0), 1, h1, h2) == 2); REQUIRE((h1.point == Vector3f(0, 0, -1) && h2.point == Vector3f(0, 0, 1))); REQUIRE((h1.normal == Vector3f(0, 0, -1) && h2.normal == Vector3f(0, 0, 1))); - REQUIRE(h1.distance < h2.distance); - REQUIRE((h1.distance == distance(ray.GetOrigin(), h1.point) && h2.distance == distance(ray.GetOrigin(), h2.point))); + REQUIRE(h1.distance2 < h2.distance2); + REQUIRE((h1.GetDistance() == distance(ray.GetOrigin(), h1.point) + && h2.GetDistance() == distance(ray.GetOrigin(), h2.point))); + REQUIRE_THAT(h1.GetDistance(), Catch::Matchers::WithinRel(std::sqrt(h1.distance2))); // this returns just closest point if (auto opt = ray.IntersectSphere(Vector3f(0), 1)) { + opt->GetDistance(); REQUIRE(opt.value() == h1); } } // 1 intersection { + RayHit h1, h2; Ray ray(Vector3f(1, 0, -1), Vector3f(0, 0, 1)); REQUIRE(ray.IntersectSphere(Vector3f(0), 1, h1, h2) == 1); REQUIRE(h1 == h2); REQUIRE(h1.point == Vector3f(1, 0, 0)); - REQUIRE(ray.IntersectSphere(Vector3f(0), 1).value() == h1); + REQUIRE(ray.IntersectSphere(Vector3f(0), 1) == h1); } // 0 intersections { + RayHit h1, h2; Ray ray(Vector3f(2, 0, -1), Vector3f(0, 0, 1)); REQUIRE(ray.IntersectSphere(Vector3f(0), 1, h1, h2) == 0); REQUIRE(!ray.IntersectSphere(Vector3f(0), 1).has_value()); } // ray is inside sphere { + RayHit h1, h2; Ray ray(Vector3f(0, 0, 0), Vector3f(0.5, 0.5, 1)); REQUIRE(ray.IntersectSphere(Vector3f(0), 1, h1, h2) == 1); REQUIRE(h1 == h2); ::CompareVec3Approx(h1.normal, h1.point); auto value = ray.IntersectSphere(Vector3f(0), 1); - REQUIRE(value->distance == h1.distance); + REQUIRE(value->GetDistance() == h1.GetDistance()); + REQUIRE_THAT(value->distance2, Catch::Matchers::WithinRel(h1.distance2)); ::CompareVec3Approx(value->normal, h1.normal); ::CompareVec3Approx(value->point, h1.point); } // ray intersects sphere behind the origin { + RayHit h1, h2; Ray ray(Vector3f(0, 0, 3), Vector3f(0, 0, 1)); REQUIRE(ray.IntersectSphere(Vector3f(0), 1, h1, h2) == 0); REQUIRE(!ray.IntersectSphere(Vector3f(0), 1).has_value()); @@ -79,31 +87,30 @@ TEST_CASE("RaySphereIntersection") TEST_CASE("RayTriangleIntersection") { auto tri = GeometryFactory::MakeTriangle(Vector3f(0), Vector3f(3, 0, 0), Vector3f(1.5, 2, 0)); - std::optional hit; // intersects { Ray ray(Vector3f(1.5, 2, -5), Vector3f(0, 0, 1)); - hit = ray.IntersectTriangle(tri.vertices[0].position, tri.vertices[1].position, tri.vertices[2].position); + std::optional hit = ray.IntersectTriangle(tri.vertices[0].position, tri.vertices[1].position, tri.vertices[2].position); REQUIRE(hit.has_value()); - REQUIRE(hit->distance == distance(ray.GetOrigin(), hit->point)); + REQUIRE(hit->GetDistance() == distance(ray.GetOrigin(), hit->point)); REQUIRE(hit->point == Vector3f(1.5, 2, 0)); } { Ray ray(Vector3f(1.5, 1, -1), Vector3f(0, 0, 1)); - hit = ray.IntersectTriangle(tri.vertices[0].position, tri.vertices[1].position, tri.vertices[2].position); + std::optional hit = ray.IntersectTriangle(tri.vertices[0].position, tri.vertices[1].position, tri.vertices[2].position); REQUIRE(hit.has_value()); - REQUIRE(hit->distance == distance(ray.GetOrigin(), hit->point)); + REQUIRE(hit->GetDistance() == distance(ray.GetOrigin(), hit->point)); REQUIRE(hit->point == Vector3f(1.5, 1, 0)); } // no intersections { Ray ray(Vector3f(5, 0, 0), Vector3f(0, 0, 1)); - hit = ray.IntersectTriangle(tri.vertices[0].position, tri.vertices[1].position, tri.vertices[2].position); + std::optional hit = ray.IntersectTriangle(tri.vertices[0].position, tri.vertices[1].position, tri.vertices[2].position); REQUIRE(!hit.has_value()); } { Ray ray(Vector3f(1.5, 1, 0.5), Vector3f(0, 0, 1)); - hit = ray.IntersectTriangle(tri.vertices[0].position, tri.vertices[1].position, tri.vertices[2].position); + std::optional hit = ray.IntersectTriangle(tri.vertices[0].position, tri.vertices[1].position, tri.vertices[2].position); REQUIRE(!hit.has_value()); } } @@ -141,52 +148,59 @@ TEST_CASE("RayAABBIntersection") auto sphere = GeometryFactory::MakeSphere(1, 32, 16); sphere.CalculateAABB(); std::optional hit; - RayHit h1, h2; // intersects { + RayHit h1, h2; Ray ray(Vector3f(0, 0, -2), Vector3f(0, 0, 1)); REQUIRE(ray.IntersectAABB(sphere.aabb, h1, h2) == 2); - REQUIRE(h1.distance < h2.distance); + REQUIRE(h1.distance2 < h2.distance2); REQUIRE(h1.point == Vector3f(0, 0, -1)); REQUIRE(h2.point == Vector3f(0, 0, 1)); auto p = ray.IntersectAABB(sphere.aabb); REQUIRE(p->point == h1.point); - REQUIRE(p->distance == h1.distance); + REQUIRE(p->distance2 == h1.distance2); + REQUIRE(p->GetDistance() == h1.GetDistance()); } { + RayHit h1, h2; Ray ray(Vector3f(0, 0, 1), Vector3f(0, 0, 1)); REQUIRE(ray.IntersectAABB(sphere.aabb, h1, h2) == 1); - REQUIRE(h1.distance == h2.distance); + REQUIRE(h1.distance2 == h2.distance2); CompareVec3Approx(h1.point, h2.point); REQUIRE(h1.point == Vector3f(0, 0, 1)); - REQUIRE(ray.IntersectAABB(sphere.aabb)->distance == h1.distance); + REQUIRE(ray.IntersectAABB(sphere.aabb)->distance2 == h1.distance2); } { + RayHit h1, h2; // inside sphere Ray ray(Vector3f(0), Vector3f(0.3)); REQUIRE(ray.IntersectAABB(sphere.aabb, h1, h2) == 1); REQUIRE(h1 == h2); auto val = ray.IntersectAABB(sphere.aabb); REQUIRE(val.has_value()); - REQUIRE_THAT(val->distance, Catch::Matchers::WithinRel(h1.distance)); + REQUIRE_THAT(val->distance2, Catch::Matchers::WithinRel(h1.distance2)); CompareVec3Approx(val->point, h1.point); } { + RayHit h1, h2; Ray ray(Vector3f(2, -0.5, 1.5), Vector3f(-2, 0.5, -1.5)); REQUIRE(ray.IntersectAABB(sphere.aabb, h1, h2) == 2); - REQUIRE(h1.distance < h2.distance); + REQUIRE(h1.distance2 < h2.distance2); auto val = ray.IntersectAABB(sphere.aabb); REQUIRE(val.has_value()); - REQUIRE(val->distance == h1.distance); + REQUIRE(val->distance2 == h1.distance2); + REQUIRE_THAT(val->GetDistance(), Catch::Matchers::WithinRel(h1.GetDistance())); CompareVec3Approx(val->point, h1.point); } // no intersections { + RayHit h1, h2; Ray ray(Vector3f(3, 0, 1), Vector3f(0, 0, 1)); REQUIRE(ray.IntersectAABB(sphere.aabb, h1, h2) == 0); REQUIRE(!ray.IntersectAABB(sphere.aabb).has_value()); } { + RayHit h1, h2; Ray ray(Vector3f(0, 0, 1.1), Vector3f(0, 0, 1)); REQUIRE(ray.IntersectAABB(sphere.aabb, h1, h2) == 0); REQUIRE(!ray.IntersectAABB(sphere.aabb).has_value()); @@ -202,7 +216,7 @@ TEST_CASE("RayPlaneIntersection") auto hit = ray.IntersectPlane(pOrigin, pNorm); REQUIRE(hit.has_value()); REQUIRE(hit->normal == pNorm); - REQUIRE(hit->distance == 2.f); + REQUIRE(hit->GetDistance() == 2.f); REQUIRE(hit->point == Vector3f(2, 0, 2)); } { From 04a705456e218f1d1f3e361cb4a7b2a7db0e0ee2 Mon Sep 17 00:00:00 2001 From: ohyzha Date: Thu, 7 Nov 2024 17:33:39 +0200 Subject: [PATCH 11/12] cleanup --- openVulkanoCpp/Input/InputDeviceMouse.cpp | 2 +- openVulkanoCpp/Scene/Camera.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openVulkanoCpp/Input/InputDeviceMouse.cpp b/openVulkanoCpp/Input/InputDeviceMouse.cpp index a320e89..632ab1d 100644 --- a/openVulkanoCpp/Input/InputDeviceMouse.cpp +++ b/openVulkanoCpp/Input/InputDeviceMouse.cpp @@ -55,7 +55,7 @@ namespace OpenVulkano::Input void InputDeviceMouse::ClearAxes() { - for (int i = 2; i < AXES_SIZE; i++) + for (int i = InputKey::Mouse::AXIS_X; i < AXES_SIZE; i++) { axes[i] = 0; } diff --git a/openVulkanoCpp/Scene/Camera.cpp b/openVulkanoCpp/Scene/Camera.cpp index a0d45b8..55844d1 100644 --- a/openVulkanoCpp/Scene/Camera.cpp +++ b/openVulkanoCpp/Scene/Camera.cpp @@ -23,7 +23,7 @@ namespace OpenVulkano::Scene rayEye.z = -1; rayEye.a = 0; - Math::Vector3f rayWorld = normalize(inverse(m_view) * rayEye); + Math::Vector3f rayWorld = normalize(GetWorldMatrix() * rayEye); Ray r(GetPosition(), rayWorld); return r; From 04b700ae824dc8cfdb41cc95319c6e88b4935e9c Mon Sep 17 00:00:00 2001 From: ohyzha Date: Thu, 7 Nov 2024 17:52:39 +0200 Subject: [PATCH 12/12] distance setter --- openVulkanoCpp/Scene/Ray.cpp | 12 +++++++----- openVulkanoCpp/Scene/Ray.hpp | 6 +++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/openVulkanoCpp/Scene/Ray.cpp b/openVulkanoCpp/Scene/Ray.cpp index 289e46d..7e2a30c 100644 --- a/openVulkanoCpp/Scene/Ray.cpp +++ b/openVulkanoCpp/Scene/Ray.cpp @@ -51,13 +51,14 @@ namespace OpenVulkano::Scene const Math::Vector3f& v2) const { RayHit hitRes; - if (intersectRayTriangle(m_origin, m_dir, v0, v1, v2, m_baryPos, hitRes.distance) && hitRes.distance >= 0) + float d; + if (intersectRayTriangle(m_origin, m_dir, v0, v1, v2, m_baryPos, d) && d >= 0) { hitRes.point = (1.f - m_baryPos.x - m_baryPos.y) * v0 + m_baryPos.x * v1 + m_baryPos.y * v2; Math::Vector3f e = v1 - v0; Math::Vector3f e2 = v2 - v0; // triangle normal. won't work if triangle is smoothly shaded. use other overloaded method instead. - hitRes.distance2 = distance2(m_origin, hitRes.point); + hitRes.SetDistance(d); hitRes.normal = normalize(cross(e, e2)); return hitRes; } @@ -180,10 +181,11 @@ namespace OpenVulkano::Scene { RayHit hit; Math::Vector3f norm = normalize(pNorm); - if (intersectRayPlane(m_origin, m_dir, pOrigin, pNorm, hit.distance)) + float d; + if (intersectRayPlane(m_origin, m_dir, pOrigin, pNorm, d)) { - hit.point = m_origin + m_dir * hit.distance; - hit.distance2 = distance2(m_origin, hit.point); + hit.SetDistance(d); + hit.point = m_origin + m_dir * d; hit.normal = norm; return hit; } diff --git a/openVulkanoCpp/Scene/Ray.hpp b/openVulkanoCpp/Scene/Ray.hpp index 6413eaa..999888b 100644 --- a/openVulkanoCpp/Scene/Ray.hpp +++ b/openVulkanoCpp/Scene/Ray.hpp @@ -28,9 +28,13 @@ namespace OpenVulkano::Scene } return distance; } + void SetDistance(float d) + { + this->distance = d; + this->distance2 = d * d; + } bool operator==(const RayHit& other) const; bool operator!=(const RayHit& other) const; - friend class Ray; private: mutable float distance = -1; };