added comparison

This commit is contained in:
Jorijn van der Graaf 2026-02-19 02:36:36 +01:00
commit 05fbd3685b
5 changed files with 255 additions and 82 deletions

View file

@ -1,78 +1,124 @@
/* /*
Crafter®.Math Crafter®.Math
Copyright (C) 2026 Catcrafts® Copyright (C) 2026 Catcrafts®
catcrafts.net catcrafts.net
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License version 3.0 as published by the Free Software Foundation; License version 3.0 as published by the Free Software Foundation;
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
export module Crafter.Math:Ray; export module Crafter.Math:Intersection;
import :Vector; import :Vector;
import std; import std;
namespace Crafter { namespace Crafter {
export template<typename T> export template<typename T>
constexpr T IntersectionTestRayTriangle(Vector<T, 3, 0> vert0, Vector<T, 3, 0> vert1, Vector<T, 3, 0> vert2, Vector<T, 3, 0> rayOrigin, Vector<T, 3, 0> rayDir) { constexpr T IntersectionTestRayTriangle(Vector<T, 3, 0> vert0, Vector<T, 3, 0> vert1, Vector<T, 3, 0> vert2, Vector<T, 3, 0> rayOrigin, Vector<T, 3, 0> rayDir) {
constexpr T EPSILON = 0.0000001; Vector<T, 3, 0> edge1 = vert1 - vert0;
Vector<T, 3, 0> edge1 = vert1 - vert0; Vector<T, 3, 0> edge2 = vert2 - vert0;
Vector<T, 3, 0> edge2 = vert2 - vert0;
Vector<T, 3, 0> h = Vector<T, 3, 0>::Cross(rayDir, edge2);
Vector<T, 3, 0> h = Vector<T, 3, 0>::Cross(rayDir, edge2); T determinant = Vector<T, 3, 0>::Dot(edge1, h);
T determinant = Vector<T, 3, 0>::Dot(edge1, h);
if (determinant <= std::numeric_limits<T>::epsilon()) {
if (determinant <= EPSILON) { return std::numeric_limits<T>::max();
return std::numeric_limits<T>::max(); }
}
T inverse_determinant = T(1) / determinant;
T inverse_determinant = T(1) / determinant;
Vector<T, 3, 0> origins_diff_vector = rayOrigin - vert0;
Vector<T, 3, 0> origins_diff_vector = rayOrigin - vert0; T u = Vector<T, 3, 0>::Dot(origins_diff_vector, h) * inverse_determinant;
T u = Vector<T, 3, 0>::Dot(origins_diff_vector, h) * inverse_determinant;
if (u < 0.0 || u > 1.0)
if (u < 0.0 || u > 1.0) {
{ return std::numeric_limits<T>::max();
return std::numeric_limits<T>::max(); }
}
Vector<T, 3, 0> q = Vector<T, 3, 0>::Cross(origins_diff_vector, edge1);
Vector<T, 3, 0> q = Vector<T, 3, 0>::Cross(origins_diff_vector, edge1); T v = inverse_determinant * Vector<T, 3, 0>::Dot(rayDir, q);
T v = inverse_determinant * Vector<T, 3, 0>::Dot(rayDir, q);
if (v < 0.0 || u + v > 1.0) {
if (v < 0.0 || u + v > 1.0) { return std::numeric_limits<T>::max();
return std::numeric_limits<T>::max(); }
}
return inverse_determinant * Vector<T, 3, 0>::Dot(edge2, q);
return inverse_determinant * Vector<T, 3, 0>::Dot(edge2, q); }
}
export template<typename T>
export template<typename T> constexpr T IntersectionTestRaySphere(Vector<T, 3, 0> position, T radius, Vector<T, 3, 0> rayOrigin, Vector<T, 3, 0> rayDir) {
constexpr T IntersectionTestRaySphere(Vector<T, 3, 0> position, T radius, Vector<T, 3, 0> rayOrigin, Vector<T, 3, 0> rayDir) { T a = Vector<T, 3, 0>::Dot(rayDir, rayDir);
T a = Vector<T, 3, 0>::Dot(rayDir, rayDir); T b = Vector<T, 3, 0>::Dot(rayDir, (T(2) * (rayOrigin - position)));
T b = Vector<T, 3, 0>::Dot(rayDir, (T(2) * (rayOrigin - position))); T c = Vector<T, 3, 0>::Dot(position, position) + Vector<T, 3, 0>::Dot(rayOrigin, rayOrigin) - T(2) * Vector<T, 3, 0>::Dot(rayOrigin, position) - radius * radius;
T c = Vector<T, 3, 0>::Dot(position, position) + Vector<T, 3, 0>::Dot(rayOrigin, rayOrigin) - T(2) * Vector<T, 3, 0>::Dot(rayOrigin, position) - radius * radius; T d = b * b + (T(-4)) * a * c;
T d = b * b + (T(-4)) * a * c;
if (d < 0) {
if (d < 0) { return std::numeric_limits<T>::max();
return std::numeric_limits<T>::max(); }
}
d = std::sqrt(d);
d = std::sqrt(d);
float t = (T(-0.5)) * (b + d) / a;
float t = (T(-0.5)) * (b + d) / a; if (t > T(0)) {
if (t > T(0)) { return t;
return t; } else {
} else { return std::numeric_limits<T>::max();
return std::numeric_limits<T>::max(); }
} }
}
export template<typename T>
constexpr T IntersectionTestRayOrientedBox(Vector<T, 3, 0> boxPosition, Vector<T, 3, 0> boxSize, Vector<T, 4, 0> boxRotation, Vector<T, 3, 0> rayOrigin, Vector<T, 3, 0> rayDir) {
Vector<T, 4, 0> invRot(
-boxRotation.x,
-boxRotation.y,
-boxRotation.z,
boxRotation.w
);
Vector<T, 3, 0> localOrigin = Vector<T, 3, 0>::Rotate(rayOrigin - boxPosition, invRot);
Vector<T, 3, 0> localDir = Vector<T, 3, 0>::Rotate(rayDir, invRot);
Vector<T,3,0> halfExtents = boxSize * T(0.5);
T tMin = T(0);
T tMax = std::numeric_limits<T>::max();
for (std::uint32_t i = 0; i < 3; ++i)
{
if (std::abs(localDir.v[i]) < std::numeric_limits<T>::epsilon())
{
if (localOrigin.v[i] < -halfExtents.v[i] || localOrigin.v[i] > halfExtents.v[i]) {
return std::numeric_limits<T>::max();
}
}
else
{
T invD = T(1) / localDir.v[i];
T t1 = (-halfExtents.v[i] - localOrigin.v[i]) * invD;
T t2 = ( halfExtents.v[i] - localOrigin.v[i]) * invD;
if (t1 > t2) {
std::swap(t1, t2);
}
tMin = std::max(tMin, t1);
tMax = std::min(tMax, t2);
if (tMin > tMax) {
return std::numeric_limits<T>::max();
}
}
}
return (tMin >= T(0)) ? tMin : tMax;
}
} }

View file

@ -30,7 +30,7 @@ namespace Crafter {
struct __attribute__((packed)) VectorBase<T, 1, Aligment> { struct __attribute__((packed)) VectorBase<T, 1, Aligment> {
union { union {
T v[Aligment]; T v[Aligment];
T x; T x, r;
}; };
}; };
@ -41,6 +41,9 @@ namespace Crafter {
struct __attribute__((packed)) { struct __attribute__((packed)) {
T x, y; T x, y;
}; };
struct __attribute__((packed)) {
T r, g;
};
}; };
constexpr VectorBase<T, 2, Aligment>(float x, float y): x(x), y(y) { constexpr VectorBase<T, 2, Aligment>(float x, float y): x(x), y(y) {
@ -55,6 +58,9 @@ namespace Crafter {
struct __attribute__((packed)) { struct __attribute__((packed)) {
T x, y, z; T x, y, z;
}; };
struct __attribute__((packed)) {
T r, g, b;
};
}; };
constexpr VectorBase<T, 3, Aligment>(float x, float y, float z): x(x), y(y), z(z) { constexpr VectorBase<T, 3, Aligment>(float x, float y, float z): x(x), y(y), z(z) {
@ -69,6 +75,9 @@ namespace Crafter {
struct __attribute__((packed)) { struct __attribute__((packed)) {
T x, y, z, w; T x, y, z, w;
}; };
struct __attribute__((packed)) {
T r, g, b, a;
};
}; };
constexpr VectorBase<T, 4, Aligment>(float x, float y, float z, float w): x(x), y(y), z(z), w(w) { constexpr VectorBase<T, 4, Aligment>(float x, float y, float z, float w): x(x), y(y), z(z), w(w) {
@ -85,7 +94,7 @@ namespace Crafter {
struct VectorBase<T, 1, 0> { struct VectorBase<T, 1, 0> {
union { union {
T v[1]; T v[1];
T x; T x, r;
}; };
}; };
@ -96,6 +105,9 @@ namespace Crafter {
struct { struct {
T x, y; T x, y;
}; };
struct {
T r, g;
};
}; };
constexpr VectorBase<T, 2, 0>(float x, float y): x(x), y(y) { constexpr VectorBase<T, 2, 0>(float x, float y): x(x), y(y) {
@ -110,6 +122,9 @@ namespace Crafter {
struct { struct {
T x, y, z; T x, y, z;
}; };
struct {
T r, g, b;
};
}; };
constexpr VectorBase<T, 3, 0>(float x, float y, float z): x(x), y(y), z(z) { constexpr VectorBase<T, 3, 0>(float x, float y, float z): x(x), y(y), z(z) {
@ -124,6 +139,9 @@ namespace Crafter {
struct { struct {
T x, y, z, w; T x, y, z, w;
}; };
struct {
T r, g, b, a;
};
}; };
constexpr VectorBase<T, 4, 0>(float x, float y, float z, float w): x(x), y(y), z(z), w(w) { constexpr VectorBase<T, 4, 0>(float x, float y, float z, float w): x(x), y(y), z(z), w(w) {
@ -274,6 +292,25 @@ namespace Crafter {
return returnVector; return returnVector;
} }
template <typename BT>
constexpr bool operator==(BT b) const {
for(std::uint32_t i = 0; i < Len; i++) {
if(this->v[i] != this->v[i]) {
return false;
}
}
return true;
}
template <typename BT>
constexpr bool operator!=(BT b) const {
for(std::uint32_t i = 0; i < Len; i++) {
if(this->v[i] != this->v[i]) {
return true;
}
}
return false;
}
constexpr void Normalize() { constexpr void Normalize() {
float fLength = Length(); float fLength = Length();
@ -310,6 +347,21 @@ namespace Crafter {
); );
} }
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment>
constexpr static Vector<T, Len, Aligment> Normalize(Vector<AT, Alen, AAlignment> a) requires(Len == Alen) {
Vector<T, 3, 0> returned;
float fLength = a.Length();
if (fLength > 0) {
fLength = 1.0f / fLength;
}
for(std::uint32_t i = 0; i < Len; i++) {
returned.v[i] = a.v[i] * fLength;
}
return returned;
}
template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment, typename BT, std::uint32_t Blen, std::uint32_t BAlignment> template <typename AT, std::uint32_t Alen, std::uint32_t AAlignment, typename BT, std::uint32_t Blen, std::uint32_t BAlignment>
constexpr static float Dot(Vector<AT, Alen, AAlignment> a, Vector<BT, Blen, BAlignment> b) requires(Alen >= Len && Blen >= Len) { constexpr static float Dot(Vector<AT, Alen, AAlignment> a, Vector<BT, Blen, BAlignment> b) requires(Alen >= Len && Blen >= Len) {
float accumulate = a.v[0] * b.v[0]; float accumulate = a.v[0] * b.v[0];
@ -318,6 +370,64 @@ namespace Crafter {
} }
return accumulate; return accumulate;
} }
template <typename AT, std::uint32_t AAlignment, typename BT, std::uint32_t BAlignment>
constexpr static Vector<T, 3, Aligment> Rotate(Vector<AT, 3, AAlignment> v, Vector<BT, 4, BAlignment> q) requires(Len == 3) {
Vector<T, 3, 0> qv(q.x, q.y, q.z);
Vector<T, 3, 0> t = Vector<T, 3, Aligment>::Cross(qv, v) * T(2);
return v + t * q.w + Vector<T, 3, Aligment>::Cross(qv, t);
}
template <typename AT, std::uint32_t AAlignment, typename BT, std::uint32_t BAlignment, typename CT, std::uint32_t CAlignment>
constexpr static Vector<T, 4, Aligment> QuanternionFromBasis(Vector<AT, 3, AAlignment> right, Vector<BT, 3, BAlignment> up, Vector<CT, 3, CAlignment> forward) requires(Len == 4) {
T m00 = right.x;
T m01 = up.x;
T m02 = forward.x;
T m10 = right.y;
T m11 = up.y;
T m12 = forward.y;
T m20 = right.z;
T m21 = up.z;
T m22 = forward.z;
T trace = m00 + m11 + m22;
Vector<T, 4, Aligment> q;
if (trace > std::numeric_limits<T>::epsilon()) {
T s = std::sqrt(trace + T(1)) * T(2);
q.w = T(0.25) * s;
q.x = (m21 - m12) / s;
q.y = (m02 - m20) / s;
q.z = (m10 - m01) / s;
}
else if ((m00 > m11) && (m00 > m22)) {
T s = std::sqrt(T(1) + m00 - m11 - m22) * T(2);
q.w = (m21 - m12) / s;
q.x = T(0.25) * s;
q.y = (m01 + m10) / s;
q.z = (m02 + m20) / s;
}
else if (m11 > m22) {
T s = std::sqrt(T(1) + m11 - m00 - m22) * T(2);
q.w = (m02 - m20) / s;
q.x = (m01 + m10) / s;
q.y = T(0.25) * s;
q.z = (m12 + m21) / s;
}
else {
T s = std::sqrt(T(1) + m22 - m00 - m11) * T(2);
q.w = (m10 - m01) / s;
q.x = (m02 + m20) / s;
q.y = (m12 + m21) / s;
q.z = T(0.25) * s;
}
q.Normalize();
return q;
}
}; };
} }

View file

@ -22,4 +22,4 @@ export module Crafter.Math;
export import :Basic; export import :Basic;
export import :Vector; export import :Vector;
export import :MatrixRowMajor; export import :MatrixRowMajor;
export import :Ray; export import :Intersection;

View file

@ -4,5 +4,22 @@ import std;
using namespace Crafter; using namespace Crafter;
int main() { int main() {
std::cout << IntersectionTestRaySphere<float>({0,0,0}, 10, {0,0,-100}, {0,1,0}) << std::endl; // // Test Ray-OrientedBox intersection
// Vector<float, 3, 0> boxPos(0.0f, 0.0f, 0.0f);
// Vector<float, 3, 0> boxSize(2.0f, 2.0f, 2.0f);
// Vector<float, 3, 0> boxRot(0.0f, 0.0f, 0.0f); // No rotation
// Vector<float, 3, 0> rayOrigin(0.0f, 0.0f, -5.0f);
// Vector<float, 3, 0> rayDir(0.0f, 0.0f, 1.0f);
// float hitDistance = IntersectionTestRayOrientedBox(boxPos, boxSize, boxRot, rayOrigin, rayDir);
// if (hitDistance < std::numeric_limits<float>::max()) {
// // Hit occurred
// std::cout << "Ray-OrientedBox intersection at distance: " << hitDistance << std::endl;
// } else {
// // No hit
// std::cout << "No intersection with Ray-OrientedBox" << std::endl;
// }
// return 0;
} }

View file

@ -3,7 +3,7 @@
"configurations": [ "configurations": [
{ {
"name": "base", "name": "base",
"interfaces": ["interfaces/Crafter.Math-Vector", "interfaces/Crafter.Math-Basic", "interfaces/Crafter.Math-MatrixRowMajor", "interfaces/Crafter.Math", "interfaces/Crafter.Math-Ray"], "interfaces": ["interfaces/Crafter.Math-Vector", "interfaces/Crafter.Math-Basic", "interfaces/Crafter.Math-MatrixRowMajor", "interfaces/Crafter.Math", "interfaces/Crafter.Math-Intersection"],
"implementations": [] "implementations": []
}, },
{ {