Merge pull request 'Ray casting from camera' (#156) from camera_raycasting into master
Reviewed-on: https://git.madvoxel.net/OpenVulkano/OpenVulkano/pulls/156 Reviewed-by: Georg Hagen <georg.hagen@madvoxel.com>
This commit is contained in:
@@ -33,6 +33,8 @@ namespace OpenVulkano::Input
|
||||
{
|
||||
axes[InputKey::Mouse::AXIS_X] = static_cast<float>(posX - mousePosX);
|
||||
axes[InputKey::Mouse::AXIS_Y] = static_cast<float>(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 = InputKey::Mouse::AXIS_X; i < AXES_SIZE; i++)
|
||||
{
|
||||
axis = 0;
|
||||
axes[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -75,6 +75,23 @@ namespace OpenVulkano::Input
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InputManager::GetButtonDown(InputAction* action) const
|
||||
{
|
||||
const std::vector<InputDevice*>& 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)
|
||||
@@ -85,6 +102,40 @@ namespace OpenVulkano::Input
|
||||
return false;
|
||||
}
|
||||
|
||||
InputDevice* InputManager::GetDevice(InputDeviceType type) const
|
||||
{
|
||||
if (type == InputDeviceType::UNKNOWN)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
for (InputDevice* device : devices)
|
||||
{
|
||||
if (device->GetType() == type)
|
||||
{
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<InputDevice*> InputManager::GetDevices(InputDeviceType type) const
|
||||
{
|
||||
if (type == InputDeviceType::UNKNOWN)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
std::vector<InputDevice*> 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)
|
||||
|
||||
@@ -40,8 +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<InputDevice*> GetDevices(InputDeviceType type) const;
|
||||
|
||||
[[nodiscard]] InputDevice* GetLastActiveDevice() const
|
||||
{
|
||||
return lastActiveDevice;
|
||||
|
||||
31
openVulkanoCpp/Scene/Camera.cpp
Normal file
31
openVulkanoCpp/Scene/Camera.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
namespace OpenVulkano::Scene
|
||||
{
|
||||
|
||||
Ray Camera::CastRay(const Math::Vector2i& xy) const
|
||||
{
|
||||
using namespace Math::Utils;
|
||||
|
||||
// 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(GetWorldMatrix() * rayEye);
|
||||
|
||||
Ray r(GetPosition(), rayWorld);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Node.hpp"
|
||||
#include "Math/Math.hpp"
|
||||
#include "Math/Frustum.hpp"
|
||||
#include "Scene/Ray.hpp"
|
||||
#include <array>
|
||||
|
||||
namespace OpenVulkano::Scene
|
||||
@@ -83,6 +84,8 @@ namespace OpenVulkano::Scene
|
||||
|
||||
virtual void UpdateProjectionMatrix() = 0;
|
||||
|
||||
Ray CastRay(const Math::Vector2i& xy) const;
|
||||
|
||||
void UpdateViewProjectionMatrix()
|
||||
{
|
||||
m_viewProjection = m_projection * m_view;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Base/ICloseable.hpp"
|
||||
#include "Scene/IRayIntersectable.hpp"
|
||||
#include "DrawEncoder.hpp"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -26,13 +27,14 @@ namespace OpenVulkano::Scene
|
||||
BACKGROUND = 0, MAIN, TRANSPARENT, POST
|
||||
};
|
||||
|
||||
class Drawable : public ICloseable
|
||||
class Drawable : public ICloseable, public IRayIntersectable
|
||||
{
|
||||
std::vector<Node*> 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<RayHit> 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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
18
openVulkanoCpp/Scene/IRayIntersectable.hpp
Normal file
18
openVulkanoCpp/Scene/IRayIntersectable.hpp
Normal file
@@ -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<RayHit> Intersect(const Ray& ray) const = 0;
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -67,6 +67,8 @@ namespace OpenVulkano::Scene
|
||||
|
||||
void SetMatrix(const Math::Matrix4f& mat);
|
||||
|
||||
[[nodiscard]] Node* GetRoot();
|
||||
|
||||
[[nodiscard]] Math::Matrix3f GetRotationMatrix() const { return static_cast<const Math::Matrix3f>(localMat); }
|
||||
|
||||
[[nodiscard]] const Math::Matrix4f& GetMatrix() const { return localMat; }
|
||||
|
||||
@@ -80,6 +80,11 @@ namespace OpenVulkano::Scene
|
||||
m_billboardSettings = settings;
|
||||
}
|
||||
|
||||
std::optional<RayHit> LabelDrawable::Intersect(const Ray& ray) const
|
||||
{
|
||||
return ray.IntersectAABB(m_bbox);
|
||||
}
|
||||
|
||||
void LabelDrawable::RecalculateBbox(const Math::AABB& other)
|
||||
{
|
||||
if (m_bbox.IsEmpty())
|
||||
|
||||
@@ -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<RayHit> Intersect(const Ray& ray) const override;
|
||||
private:
|
||||
void RecalculateBbox(const Math::AABB& other);
|
||||
void SetupShaders();
|
||||
|
||||
@@ -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 {};
|
||||
@@ -51,12 +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.SetDistance(d);
|
||||
hitRes.normal = normalize(cross(e, e2));
|
||||
return hitRes;
|
||||
}
|
||||
@@ -99,7 +101,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 +171,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;
|
||||
}
|
||||
@@ -179,9 +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.SetDistance(d);
|
||||
hit.point = m_origin + m_dir * d;
|
||||
hit.normal = norm;
|
||||
return hit;
|
||||
}
|
||||
@@ -214,7 +218,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 +232,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 +246,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); }
|
||||
}
|
||||
|
||||
@@ -12,14 +12,39 @@
|
||||
|
||||
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;
|
||||
}
|
||||
void SetDistance(float d)
|
||||
{
|
||||
this->distance = d;
|
||||
this->distance2 = d * d;
|
||||
}
|
||||
bool operator==(const RayHit& other) const;
|
||||
bool operator!=(const RayHit& other) const;
|
||||
private:
|
||||
mutable float distance = -1;
|
||||
};
|
||||
|
||||
struct DrawableRayHit : RayHit
|
||||
{
|
||||
DrawableRayHit() = default;
|
||||
DrawableRayHit(const RayHit& hit) : RayHit(hit) {};
|
||||
Drawable* drawable = nullptr;
|
||||
Node* node = nullptr;
|
||||
};
|
||||
|
||||
class Ray
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace OpenVulkano
|
||||
public:
|
||||
Node* root;
|
||||
std::vector<Drawable*> shapeList;
|
||||
std::vector<Drawable*> 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,17 @@ 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;
|
||||
if (!camera->scene)
|
||||
{
|
||||
this->GetRoot()->AddChild(camera->GetRoot());
|
||||
}
|
||||
}
|
||||
|
||||
Camera* GetCamera() const
|
||||
|
||||
68
openVulkanoCpp/Scene/SceneIntersectionTestController.cpp
Normal file
68
openVulkanoCpp/Scene/SceneIntersectionTestController.cpp
Normal file
@@ -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<DrawableRayHit> 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);
|
||||
}
|
||||
}
|
||||
33
openVulkanoCpp/Scene/SceneIntersectionTestController.hpp
Normal file
33
openVulkanoCpp/Scene/SceneIntersectionTestController.hpp
Normal file
@@ -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<DrawableRayHit> OnHit;
|
||||
|
||||
private:
|
||||
Input::InputAction* m_actionClick = nullptr;
|
||||
Input::InputAction* m_actionClickX = nullptr;
|
||||
Input::InputAction* m_actionClickY = nullptr;
|
||||
Camera* m_camera;
|
||||
};
|
||||
}
|
||||
@@ -5,7 +5,12 @@
|
||||
*/
|
||||
|
||||
#include "SimpleDrawable.hpp"
|
||||
#include "Scene/Geometry.hpp"
|
||||
#include "Scene/Shader/Shader.hpp"
|
||||
#include "Base/Logger.hpp"
|
||||
#include <magic_enum.hpp>
|
||||
#include <stdexcept>
|
||||
#include <cassert>
|
||||
|
||||
namespace OpenVulkano::Scene
|
||||
{
|
||||
@@ -26,4 +31,70 @@ namespace OpenVulkano::Scene
|
||||
m_uniBuffer = drawable->m_uniBuffer;
|
||||
SetShader(drawable->GetShader());
|
||||
}
|
||||
|
||||
std::optional<RayHit> SimpleDrawable::Intersect(const Ray& ray) const
|
||||
{
|
||||
if (!m_mesh || !GetShader())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
if (m_mesh->aabb.IsEmpty())
|
||||
{
|
||||
m_mesh->CalculateAABB();
|
||||
}
|
||||
auto bboxHit = ray.IntersectAABB(m_mesh->aabb);
|
||||
if (!bboxHit)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
if (GetShader()->topology == Topology::TRIANGLE_LIST)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
return hit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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 {};
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,8 @@ namespace OpenVulkano::Scene
|
||||
|
||||
void Init(SimpleDrawable* drawable);
|
||||
|
||||
std::optional<RayHit> Intersect(const Ray& ray) const override;
|
||||
|
||||
[[nodiscard]] Geometry* GetMesh() const { return m_mesh; }
|
||||
|
||||
[[nodiscard]] Material* GetMaterial() const { return m_material; }
|
||||
|
||||
@@ -150,6 +150,7 @@ namespace OpenVulkano::Scene
|
||||
return;
|
||||
}
|
||||
|
||||
m_text = text;
|
||||
auto GetActualLength = [&]()
|
||||
{
|
||||
auto begin = text.begin();
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace OpenVulkano::Scene
|
||||
Math::AABB& GetBoundingBox() { return m_bbox; }
|
||||
TextConfig& GetConfig() { return m_cfg; }
|
||||
Shader* GetShader() { return m_shader; }
|
||||
[[nodiscard]] const std::string& GetText() const { return m_text; }
|
||||
std::shared_ptr<AtlasData> GetAtlasData() { return m_atlasData; }
|
||||
private:
|
||||
Geometry m_geometry;
|
||||
@@ -59,6 +60,7 @@ namespace OpenVulkano::Scene
|
||||
std::shared_ptr<AtlasData> m_atlasData;
|
||||
Math::AABB m_bbox;
|
||||
Shader* m_shader = nullptr;
|
||||
std::string m_text;
|
||||
TextConfig m_cfg;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user