diff --git a/include/Engine/Core/Collision.h b/include/Engine/Core/Collision.h index b23b33cc..87f521bd 100644 --- a/include/Engine/Core/Collision.h +++ b/include/Engine/Core/Collision.h @@ -1,17 +1,43 @@ #ifndef Collision_h__ #define Collision_h__ +#include + #include "Core/Ray.h" #include "Core/AABB.h" +#include "Engine/Rendering/RawModel.h" namespace Collision { - +//Return true if the ray hits the box. bool RayAABBIntr(const Ray& ray, const AABB& box); bool RayVsAABB(const Ray& ray, const AABB& box); +//Return true if the ray hits the box, also outputs distance from ray origin to intersection point in [outDistance]. bool RayVsAABB(const Ray& ray, const AABB& box, float& outDistance); +//Return true if the ray hits any of the triangles in the model. Stops checking when a hit is detected. +bool RayVsModel(const Ray& ray, + const std::vector& modelVertices, + const std::vector& modelIndices); +//Return true if the ray hits any of the triangles in the model. +//Also returns the position of the intersection point. Will loop through all the whole model indices. +bool RayVsModel(const Ray& ray, + const std::vector& modelVertices, + const std::vector& modelIndices, + glm::vec3& outHitPosition); +//Return true if the ray hits any of the triangles in the model. +//Also returns the distance from the ray origin to the closest +//intersection point, and the barycentric u,v-coordinates. Will loop through all the whole model indices. +bool RayVsModel(const Ray& ray, + const std::vector& modelVertices, + const std::vector& modelIndices, + float& outDistance, + float& outUCoord, + float& outVCoord); + +//Return true if the boxes are intersecting. bool AABBVsAABB(const AABB& a, const AABB& b); + } #endif \ No newline at end of file diff --git a/src/Engine/Core/Collision.cpp b/src/Engine/Core/Collision.cpp index 07e37085..dee567e0 100644 --- a/src/Engine/Core/Collision.cpp +++ b/src/Engine/Core/Collision.cpp @@ -1,6 +1,7 @@ +#include + #include "Core/Collision.h" #include "Engine/GLM.h" -#include namespace Collision { @@ -74,4 +75,76 @@ bool AABBVsAABB(const AABB& a, const AABB& b) return (abs(aCenter[1] - bCenter[1]) <= (aHSize[1] + bHSize[1])); } -} \ No newline at end of file +bool RayVsModel(const Ray& ray, + const std::vector& modelVertices, + const std::vector& modelIndices) +{ + for (int i = 0; i < modelIndices.size(); ++i) { + glm::vec3 v0 = modelVertices[modelIndices[i]].Position; + glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0 + glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0 + glm::vec3 m = ray.Origin - v0; + glm::vec3 MxE1 = glm::cross(m, e1); + glm::vec3 DxE2 = glm::cross(ray.Direction, e2); + float DetInv = 1.0f / glm::dot(e1, DxE2); + float u = glm::dot(m, DxE2) * DetInv; + float v = glm::dot(ray.Direction, MxE1) * DetInv; + if (u < 0 && v < 0 && 1 < u + v) { + continue; + } + //Here, u and v are positive, u+v <= 1, and if distance is positive - triangle is hit. + if (0 <= glm::dot(e2, MxE1) * DetInv) { + return true; + } + } + return false; +} + +bool RayVsModel(const Ray& ray, + const std::vector& modelVertices, + const std::vector& modelIndices, + float& outDistance, + float& outUCoord, + float& outVCoord) +{ + outDistance = INFINITY; + bool hit = false; + for (int i = 0; i < modelIndices.size(); ++i) { + glm::vec3 v0 = modelVertices[modelIndices[i]].Position; + glm::vec3 e1 = modelVertices[modelIndices[++i]].Position - v0; //v1 - v0 + glm::vec3 e2 = modelVertices[modelIndices[++i]].Position - v0; //v2 - v0 + glm::vec3 m = ray.Origin - v0; + glm::vec3 MxE1 = glm::cross(m, e1); + glm::vec3 DxE2 = glm::cross(ray.Direction, e2); + float DetInv = 1.0f / glm::dot(e1, DxE2); + float dist = glm::dot(e2, MxE1) * DetInv; + if (dist >= outDistance) { + continue; + } + float u = glm::dot(m, DxE2) * DetInv; + float v = glm::dot(ray.Direction, MxE1) * DetInv; + //If u and v are positive, u+v <= 1, dist is positive, and less than closest. + if (0 <= u && 0 <= v && u + v <= 1 && 0 <= dist) { + outDistance = dist; + outUCoord = u; + outVCoord = v; + hit = true; + } + } + return hit; +} + +bool RayVsModel(const Ray& ray, + const std::vector& modelVertices, + const std::vector& modelIndices, + glm::vec3& outHitPosition) +{ + float u; + float v; + float dist; + bool hit = RayVsModel(ray, modelVertices, modelIndices, dist, u, v); + outHitPosition = ray.Origin + dist * ray.Direction; + return hit; +} + +}