diff --git a/interfaces/Crafter.Math-Ray.cppm b/interfaces/Crafter.Math-Intersection.cppm similarity index 60% rename from interfaces/Crafter.Math-Ray.cppm rename to interfaces/Crafter.Math-Intersection.cppm index e238641..2d9bbe9 100755 --- a/interfaces/Crafter.Math-Ray.cppm +++ b/interfaces/Crafter.Math-Intersection.cppm @@ -1,78 +1,124 @@ -/* -Crafter®.Math -Copyright (C) 2026 Catcrafts® -catcrafts.net - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License version 3.0 as published by the Free Software Foundation; - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -export module Crafter.Math:Ray; -import :Vector; -import std; - -namespace Crafter { - export template - constexpr T IntersectionTestRayTriangle(Vector vert0, Vector vert1, Vector vert2, Vector rayOrigin, Vector rayDir) { - constexpr T EPSILON = 0.0000001; - Vector edge1 = vert1 - vert0; - Vector edge2 = vert2 - vert0; - - Vector h = Vector::Cross(rayDir, edge2); - T determinant = Vector::Dot(edge1, h); - - if (determinant <= EPSILON) { - return std::numeric_limits::max(); - } - - T inverse_determinant = T(1) / determinant; - - Vector origins_diff_vector = rayOrigin - vert0; - T u = Vector::Dot(origins_diff_vector, h) * inverse_determinant; - - if (u < 0.0 || u > 1.0) - { - return std::numeric_limits::max(); - } - - Vector q = Vector::Cross(origins_diff_vector, edge1); - T v = inverse_determinant * Vector::Dot(rayDir, q); - - if (v < 0.0 || u + v > 1.0) { - return std::numeric_limits::max(); - } - - return inverse_determinant * Vector::Dot(edge2, q); - } - - export template - constexpr T IntersectionTestRaySphere(Vector position, T radius, Vector rayOrigin, Vector rayDir) { - T a = Vector::Dot(rayDir, rayDir); - T b = Vector::Dot(rayDir, (T(2) * (rayOrigin - position))); - T c = Vector::Dot(position, position) + Vector::Dot(rayOrigin, rayOrigin) - T(2) * Vector::Dot(rayOrigin, position) - radius * radius; - T d = b * b + (T(-4)) * a * c; - - if (d < 0) { - return std::numeric_limits::max(); - } - - d = std::sqrt(d); - - float t = (T(-0.5)) * (b + d) / a; - if (t > T(0)) { - return t; - } else { - return std::numeric_limits::max(); - } - } +/* +Crafter®.Math +Copyright (C) 2026 Catcrafts® +catcrafts.net + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 3.0 as published by the Free Software Foundation; + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +export module Crafter.Math:Intersection; +import :Vector; +import std; + +namespace Crafter { + export template + constexpr T IntersectionTestRayTriangle(Vector vert0, Vector vert1, Vector vert2, Vector rayOrigin, Vector rayDir) { + Vector edge1 = vert1 - vert0; + Vector edge2 = vert2 - vert0; + + Vector h = Vector::Cross(rayDir, edge2); + T determinant = Vector::Dot(edge1, h); + + if (determinant <= std::numeric_limits::epsilon()) { + return std::numeric_limits::max(); + } + + T inverse_determinant = T(1) / determinant; + + Vector origins_diff_vector = rayOrigin - vert0; + T u = Vector::Dot(origins_diff_vector, h) * inverse_determinant; + + if (u < 0.0 || u > 1.0) + { + return std::numeric_limits::max(); + } + + Vector q = Vector::Cross(origins_diff_vector, edge1); + T v = inverse_determinant * Vector::Dot(rayDir, q); + + if (v < 0.0 || u + v > 1.0) { + return std::numeric_limits::max(); + } + + return inverse_determinant * Vector::Dot(edge2, q); + } + + export template + constexpr T IntersectionTestRaySphere(Vector position, T radius, Vector rayOrigin, Vector rayDir) { + T a = Vector::Dot(rayDir, rayDir); + T b = Vector::Dot(rayDir, (T(2) * (rayOrigin - position))); + T c = Vector::Dot(position, position) + Vector::Dot(rayOrigin, rayOrigin) - T(2) * Vector::Dot(rayOrigin, position) - radius * radius; + T d = b * b + (T(-4)) * a * c; + + if (d < 0) { + return std::numeric_limits::max(); + } + + d = std::sqrt(d); + + float t = (T(-0.5)) * (b + d) / a; + if (t > T(0)) { + return t; + } else { + return std::numeric_limits::max(); + } + } + + export template + constexpr T IntersectionTestRayOrientedBox(Vector boxPosition, Vector boxSize, Vector boxRotation, Vector rayOrigin, Vector rayDir) { + Vector invRot( + -boxRotation.x, + -boxRotation.y, + -boxRotation.z, + boxRotation.w + ); + + Vector localOrigin = Vector::Rotate(rayOrigin - boxPosition, invRot); + Vector localDir = Vector::Rotate(rayDir, invRot); + + Vector halfExtents = boxSize * T(0.5); + + T tMin = T(0); + T tMax = std::numeric_limits::max(); + + for (std::uint32_t i = 0; i < 3; ++i) + { + if (std::abs(localDir.v[i]) < std::numeric_limits::epsilon()) + { + if (localOrigin.v[i] < -halfExtents.v[i] || localOrigin.v[i] > halfExtents.v[i]) { + return std::numeric_limits::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::max(); + } + } + } + + return (tMin >= T(0)) ? tMin : tMax; + } } \ No newline at end of file diff --git a/interfaces/Crafter.Math-Vector.cppm b/interfaces/Crafter.Math-Vector.cppm index 2cb8378..f630f00 100755 --- a/interfaces/Crafter.Math-Vector.cppm +++ b/interfaces/Crafter.Math-Vector.cppm @@ -30,7 +30,7 @@ namespace Crafter { struct __attribute__((packed)) VectorBase { union { T v[Aligment]; - T x; + T x, r; }; }; @@ -41,6 +41,9 @@ namespace Crafter { struct __attribute__((packed)) { T x, y; }; + struct __attribute__((packed)) { + T r, g; + }; }; constexpr VectorBase(float x, float y): x(x), y(y) { @@ -55,6 +58,9 @@ namespace Crafter { struct __attribute__((packed)) { T x, y, z; }; + struct __attribute__((packed)) { + T r, g, b; + }; }; constexpr VectorBase(float x, float y, float z): x(x), y(y), z(z) { @@ -69,6 +75,9 @@ namespace Crafter { struct __attribute__((packed)) { T x, y, z, w; }; + struct __attribute__((packed)) { + T r, g, b, a; + }; }; constexpr VectorBase(float x, float y, float z, float w): x(x), y(y), z(z), w(w) { @@ -85,7 +94,7 @@ namespace Crafter { struct VectorBase { union { T v[1]; - T x; + T x, r; }; }; @@ -96,6 +105,9 @@ namespace Crafter { struct { T x, y; }; + struct { + T r, g; + }; }; constexpr VectorBase(float x, float y): x(x), y(y) { @@ -110,6 +122,9 @@ namespace Crafter { struct { T x, y, z; }; + struct { + T r, g, b; + }; }; constexpr VectorBase(float x, float y, float z): x(x), y(y), z(z) { @@ -124,6 +139,9 @@ namespace Crafter { struct { T x, y, z, w; }; + struct { + T r, g, b, a; + }; }; constexpr VectorBase(float x, float y, float z, float w): x(x), y(y), z(z), w(w) { @@ -274,6 +292,25 @@ namespace Crafter { return returnVector; } + template + 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 + 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() { float fLength = Length(); @@ -310,6 +347,21 @@ namespace Crafter { ); } + template + constexpr static Vector Normalize(Vector a) requires(Len == Alen) { + Vector 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 constexpr static float Dot(Vector a, Vector b) requires(Alen >= Len && Blen >= Len) { float accumulate = a.v[0] * b.v[0]; @@ -318,6 +370,64 @@ namespace Crafter { } return accumulate; } + + template + constexpr static Vector Rotate(Vector v, Vector q) requires(Len == 3) { + Vector qv(q.x, q.y, q.z); + Vector t = Vector::Cross(qv, v) * T(2); + return v + t * q.w + Vector::Cross(qv, t); + } + + template + constexpr static Vector QuanternionFromBasis(Vector right, Vector up, Vector 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 q; + + if (trace > std::numeric_limits::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; + } }; } diff --git a/interfaces/Crafter.Math.cppm b/interfaces/Crafter.Math.cppm index bdf48ce..9ec3653 100644 --- a/interfaces/Crafter.Math.cppm +++ b/interfaces/Crafter.Math.cppm @@ -22,4 +22,4 @@ export module Crafter.Math; export import :Basic; export import :Vector; export import :MatrixRowMajor; -export import :Ray; \ No newline at end of file +export import :Intersection; \ No newline at end of file diff --git a/interfaces/main.cpp b/interfaces/main.cpp index b2562fc..1d48464 100644 --- a/interfaces/main.cpp +++ b/interfaces/main.cpp @@ -4,5 +4,22 @@ import std; using namespace Crafter; int main() { - std::cout << IntersectionTestRaySphere({0,0,0}, 10, {0,0,-100}, {0,1,0}) << std::endl; + // // Test Ray-OrientedBox intersection + // Vector boxPos(0.0f, 0.0f, 0.0f); + // Vector boxSize(2.0f, 2.0f, 2.0f); + // Vector boxRot(0.0f, 0.0f, 0.0f); // No rotation + // Vector rayOrigin(0.0f, 0.0f, -5.0f); + // Vector rayDir(0.0f, 0.0f, 1.0f); + + // float hitDistance = IntersectionTestRayOrientedBox(boxPos, boxSize, boxRot, rayOrigin, rayDir); + + // if (hitDistance < std::numeric_limits::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; } \ No newline at end of file diff --git a/project.json b/project.json index 3ba2af5..0b7c344 100644 --- a/project.json +++ b/project.json @@ -3,7 +3,7 @@ "configurations": [ { "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": [] }, {