60 constexpr float EPSILON = std::numeric_limits<float>::epsilon();
62 glm::vec3 edge1 = v1 - v0;
63 glm::vec3 edge2 = v2 - v0;
65 glm::vec3 pvec = glm::cross(ray.
dir, edge2);
66 float det = glm::dot(edge1, pvec);
69 if (det > -EPSILON && det < EPSILON)
return std::nullopt;
71 float invDet = 1.0f / det;
73 glm::vec3 tvec = ray.
origin - v0;
74 float u = glm::dot(tvec, pvec) * invDet;
75 if (u < 0.0f || u > 1.0f)
return std::nullopt;
77 glm::vec3 qvec = glm::cross(tvec, edge1);
78 float v = glm::dot(ray.
dir, qvec) * invDet;
79 if (v < 0.0f || u + v > 1.0f)
return std::nullopt;
82 float t = glm::dot(edge2, qvec) * invDet;
83 if (t < EPSILON)
return std::nullopt;
122 const glm::mat4 &view,
123 const glm::mat4 &projection
125 float x = (2.0f * mouseX) / fbWidth - 1.0f;
126 float y = 1.0f - (2.0f * mouseY) / fbHeight;
128 glm::vec4 clip = glm::vec4(x, y, -1.0f, 1.0f);
129 glm::mat4 invProj = glm::inverse(projection);
130 glm::vec4 eye = invProj * clip;
134 glm::mat4 invView = glm::inverse(view);
135 glm::vec4 worldDir4 = invView * eye;
137 return glm::normalize(glm::vec3(worldDir4));
174 const std::vector<IPickable*>& objects,
178 float distance = std::numeric_limits<float>::infinity();
187 if (obj == priority) {
Interface for objects that support mouse-based selection and interaction.
Abstract interface for objects that can be selected and interacted with using the mouse.
virtual std::optional< float > intersectsRay(const Math::Ray &ray) const =0
Tests if a ray intersects this object's geometry.
Mathematical and geometric utility functions.
glm::vec3 origin
Starting point of the ray in world space.
glm::vec3 dir
Direction vector (should be normalized)
std::optional< float > intersectTriangle(const Ray &ray, const glm::vec3 &v0, const glm::vec3 &v1, const glm::vec3 &v2)
Tests ray-triangle intersection using Möller-Trumbore algorithm.
float distance
Distance from the ray origin to the intersection point. Infinity if no hit.
glm::vec3 screenToWorldRayDirection(double mouseX, double mouseY, int fbWidth, int fbHeight, const glm::mat4 &view, const glm::mat4 &projection)
Converts screen coordinates to a world-space ray direction.
IPickable * object
Pointer to the hit object, or nullptr if no intersection.
std::optional< HitResult > findFirstHit(const std::vector< IPickable * > &objects, const Ray &ray, IPickable *priority=nullptr)
Finds the first object intersected by a ray.
Represents the result of a ray-object intersection test.
Represents a ray in 3D space.