diff --git a/include/nbl/builtin/hlsl/cpp_compat/matrix.hlsl b/include/nbl/builtin/hlsl/cpp_compat/matrix.hlsl index 712ce5e979..c0b5023990 100644 --- a/include/nbl/builtin/hlsl/cpp_compat/matrix.hlsl +++ b/include/nbl/builtin/hlsl/cpp_compat/matrix.hlsl @@ -28,8 +28,15 @@ struct matrix final : private glm::mat return *this; } - friend matrix operator+(matrix const& lhs, matrix const& rhs){ return matrix(reinterpret_cast(lhs) + reinterpret_cast(rhs)); } - friend matrix operator-(matrix const& lhs, matrix const& rhs){ return matrix(reinterpret_cast(lhs) - reinterpret_cast(rhs)); } + // not sure how to forward this + //inline friend matrix operator*(matrix const& lhs, T rhs) {return matrix(reinterpret_cast(lhs)*rhs);} + + // scalar compound assignment multiply and divide + inline matrix& operator*=(const T rhs) {return reinterpret_cast(Base::template operator*=(rhs));} + inline matrix& operator/=(const T rhs) {return reinterpret_cast(Base::template operator/=(rhs));} + + inline friend matrix operator+(matrix const& lhs, matrix const& rhs){ return matrix(reinterpret_cast(lhs) + reinterpret_cast(rhs)); } + inline friend matrix operator-(matrix const& lhs, matrix const& rhs){ return matrix(reinterpret_cast(lhs) - reinterpret_cast(rhs)); } template inline friend matrix mul(matrix const& lhs, matrix const& rhs) diff --git a/include/nbl/builtin/hlsl/ieee754.hlsl b/include/nbl/builtin/hlsl/ieee754.hlsl index a3930a362a..af23d6f07d 100644 --- a/include/nbl/builtin/hlsl/ieee754.hlsl +++ b/include/nbl/builtin/hlsl/ieee754.hlsl @@ -204,12 +204,12 @@ struct flipSign_helper +template struct flipSignIfRHSNegative_helper; template NBL_PARTIAL_REQ_TOP(concepts::FloatingPointLikeScalar) -struct flipSignIfRHSNegative_helper) > +struct flipSignIfRHSNegative_helper) > { static FloatingPoint __call(FloatingPoint val, FloatingPoint flip) { @@ -222,7 +222,7 @@ struct flipSignIfRHSNegative_helper NBL_PARTIAL_REQ_TOP(concepts::FloatingPointLikeVectorial) -struct flipSignIfRHSNegative_helper) > +struct flipSignIfRHSNegative_helper) > { static Vectorial __call(Vectorial val, Vectorial flip) { @@ -232,7 +232,29 @@ struct flipSignIfRHSNegative_helper::__call(getter_v(val, i), getter_v(flip, i))); + setter(output, i, flipSignIfRHSNegative_helper::__call(getter_v(val, i), getter_v(flip, i))); + + return output; + } +}; + +template +NBL_PARTIAL_REQ_TOP(concepts::FloatingPointLikeVectorial && concepts::FloatingPointLikeScalar) +struct flipSignIfRHSNegative_helper && concepts::FloatingPointLikeScalar) > +{ + static Vectorial __call(Vectorial val, FloatingPoint flip) + { + using traits_v = hlsl::vector_traits; + array_get getter_v; + array_set setter; + + using AsFloat = typename float_of_size::type; + using AsUint = typename unsigned_integer_of_size::type; + const AsUint signBitFlip = ieee754::traits::signMask & ieee754::impl::bitCastToUintType(flip); + + Vectorial output; + for (uint32_t i = 0; i < traits_v::Dimension; ++i) + setter(output, i, bit_cast(ieee754::impl::bitCastToUintType(getter_v(val, i)) ^ signBitFlip)); return output; } @@ -245,10 +267,10 @@ NBL_CONSTEXPR_FUNC T flipSign(T val, U flip) return impl::flipSign_helper::__call(val, flip); } -template -NBL_CONSTEXPR_FUNC T flipSignIfRHSNegative(T val, T flip) +template +NBL_CONSTEXPR_FUNC T flipSignIfRHSNegative(T val, U flip) { - return impl::flipSignIfRHSNegative_helper::__call(val, flip); + return impl::flipSignIfRHSNegative_helper::__call(val, flip); } template ) diff --git a/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl b/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl new file mode 100644 index 0000000000..dc74c45ddd --- /dev/null +++ b/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl @@ -0,0 +1,68 @@ +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. +// This file is part of the "Nabla Engine". +// For conditions of distribution and use, see copyright notice in nabla.h +#ifndef _NBL_BUILTIN_HLSL_MATH_LINALG_MATRIX_RUNTIME_TRAITS_INCLUDED_ +#define _NBL_BUILTIN_HLSL_MATH_LINALG_MATRIX_RUNTIME_TRAITS_INCLUDED_ + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#include "nbl/builtin/hlsl/tgmath.hlsl" +#include "nbl/builtin/hlsl/testing/relative_approx_compare.hlsl" +#include "nbl/builtin/hlsl/concepts/matrix.hlsl" +#include "nbl/builtin/hlsl/matrix_utils/matrix_traits.hlsl" + +namespace nbl +{ +namespace hlsl +{ +namespace math +{ +namespace linalg +{ + +template && matrix_traits::Square) +struct RuntimeTraits +{ + using matrix_t = T; + using scalar_t = typename matrix_traits::scalar_type; + NBL_CONSTEXPR_STATIC_INLINE uint16_t N = matrix_traits::RowCount; + + static RuntimeTraits create(const matrix_t m) + { + RuntimeTraits retval; + retval.invertible = !testing::relativeApproxCompare(hlsl::determinant(m), scalar_t(0.0), 1e-5); + { + bool orthogonal = true; + NBL_UNROLL for (uint16_t i = 0; i < N; i++) + orthogonal = orthogonal && testing::relativeApproxCompare(hlsl::dot(m[i], m[(i+1)%N]), scalar_t(0.0), 1e-4); + retval.orthogonal = orthogonal; + } + { + const matrix_t m_T = hlsl::transpose(m); + scalar_t uniformScaleSq = hlsl::dot(m_T[0], m_T[0]); + NBL_UNROLL for (uint16_t i = 1; i < N; i++) + { + if (!testing::relativeApproxCompare(hlsl::dot(m_T[i], m_T[i]), uniformScaleSq, 1e-4)) + { + uniformScaleSq = bit_cast(numeric_limits::quiet_NaN); + break; + } + } + + retval.uniformScaleSq = uniformScaleSq; + retval.orthonormal = retval.orthogonal && testing::relativeApproxCompare(uniformScaleSq, scalar_t(1.0), 1e-5); + } + return retval; + } + + bool invertible; + bool orthogonal; + scalar_t uniformScaleSq; + bool orthonormal; +}; + +} +} +} +} + +#endif diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 8d50202f4e..2d294cd4be 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -1,4 +1,4 @@ -// Copyright (C) 2018-2023 - DevSH Graphics Programming Sp. z O.O. +// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. // This file is part of the "Nabla Engine". // For conditions of distribution and use, see copyright notice in nabla.h #ifndef _NBL_BUILTIN_HLSL_MATH_QUATERNIONS_INCLUDED_ @@ -6,6 +6,7 @@ #include "nbl/builtin/hlsl/cpp_compat.hlsl" #include "nbl/builtin/hlsl/tgmath.hlsl" +#include "nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl" namespace nbl { @@ -14,6 +15,23 @@ namespace hlsl namespace math { +template +struct truncated_quaternion +{ + using this_t = truncated_quaternion; + using scalar_type = T; + using data_type = vector; + + static this_t create() + { + this_t q; + q.data = data_type(0.0, 0.0, 0.0); + return q; + } + + data_type data; +}; + template struct quaternion { @@ -23,28 +41,191 @@ struct quaternion using vector3_type = vector; using matrix_type = matrix; - static this_t createFromTruncated(const vector3_type first3Components) + using AsUint = typename unsigned_integer_of_size::type; + + static this_t create() + { + this_t q; + q.data = data_type(0.0, 0.0, 0.0, 1.0); + return q; + } + + // angle: Rotation angle expressed in radians. + // axis: Rotation axis, must be normalized. + template) + static this_t create(const U axis, const typename vector_traits::scalar_type angle, const typename vector_traits::scalar_type uniformScale = typename vector_traits::scalar_type(1.0)) + { + using scalar_t = typename vector_traits::scalar_type; + this_t q; + const scalar_t halfAngle = angle * scalar_t(0.5); + const scalar_t sinTheta = hlsl::sin(halfAngle); + const scalar_t cosTheta = hlsl::cos(halfAngle); + q.data = data_type(axis * sinTheta, cosTheta) * uniformScale; + return q; + } + + // applies rotation equivalent to 3x3 matrix in order of pitch * yaw * roll (X * Y * Z) -- mul(roll,mul(yaw,mul(pitch,v))) + template NBL_FUNC_REQUIRES(is_same_v,U>) + static this_t create(const U halfPitchCosSin, const U halfYawCosSin, const U halfRollCosSin) + { + const scalar_type cp = halfPitchCosSin.x; + const scalar_type sp = halfPitchCosSin.y; + + const scalar_type cy = halfYawCosSin.x; + const scalar_type sy = halfYawCosSin.y; + + const scalar_type cr = halfRollCosSin.x; + const scalar_type sr = halfRollCosSin.y; + + this_t q; + q.data[0] = cr * sp * cy + sr * cp * sy; // x + q.data[1] = cr * cp * sy - sr * sp * cy; // y + q.data[2] = sr * cp * cy - cr * sp * sy; // z + q.data[3] = cr * cp * cy + sr * sp * sy; // w + + return q; + } + + template) + static this_t create(const U pitch, const U yaw, const U roll) + { + const scalar_type halfPitch = pitch * scalar_type(0.5); + const scalar_type halfYaw = yaw * scalar_type(0.5); + const scalar_type halfRoll = roll * scalar_type(0.5); + + return create( + vector(hlsl::cos(halfPitch), hlsl::sin(halfPitch)), + vector(hlsl::cos(halfYaw), hlsl::sin(halfYaw)), + vector(hlsl::cos(halfRoll), hlsl::sin(halfRoll)) + ); + } + + static this_t create(NBL_CONST_REF_ARG(matrix_type) _m, const bool dontAssertValidMatrix=false) + { + scalar_type uniformScaleSq; + { + // only orthogonal and uniform scale mats can be converted + linalg::RuntimeTraits traits = linalg::RuntimeTraits::create(_m); + bool valid = traits.orthogonal && !hlsl::isnan(traits.uniformScaleSq); + uniformScaleSq = traits.uniformScaleSq; + + if (dontAssertValidMatrix) + if (!valid) + { + this_t retval; + retval.data = hlsl::promote(bit_cast(numeric_limits::quiet_NaN)); + return retval; + } + else + assert(valid); + } + if (uniformScaleSq < numeric_limits::min) + { + this_t retval; + retval.data = hlsl::promote(bit_cast(numeric_limits::quiet_NaN)); + return retval; + } + + const scalar_type uniformScale = hlsl::sqrt(uniformScaleSq); + matrix_type m = _m; + m /= uniformScale; + + const scalar_type m00 = m[0][0], m11 = m[1][1], m22 = m[2][2]; + const scalar_type neg_m00 = -m00; + const scalar_type neg_m11 = -m11; + const scalar_type neg_m22 = -m22; + const data_type Qx = data_type(m00, m00, neg_m00, neg_m00); + const data_type Qy = data_type(m11, neg_m11, m11, neg_m11); + const data_type Qz = data_type(m22, neg_m22, neg_m22, m22); + + const data_type tmp = Qx + Qy + Qz; + + // TODO: speed this up + this_t retval; + if (tmp.x > scalar_type(0.0)) + { + const scalar_type scales = hlsl::sqrt(tmp.x + scalar_type(1.0)); + const scalar_type invscales = scalar_type(0.5) / scales; + retval.data.x = (m[1][2] - m[2][1]) * invscales; + retval.data.y = (m[2][0] - m[0][2]) * invscales; + retval.data.z = (m[0][1] - m[1][0]) * invscales; + retval.data.w = scales * scalar_type(0.5); + } + else + { + if (tmp.y > scalar_type(0.0)) + { + const scalar_type scales = hlsl::sqrt(tmp.y + scalar_type(1.0)); + const scalar_type invscales = scalar_type(0.5) / scales; + retval.data.x = scales * scalar_type(0.5); + retval.data.y = (m[1][0] + m[0][1]) * invscales; + retval.data.z = (m[0][2] + m[2][0]) * invscales; + retval.data.w = (m[1][2] - m[2][1]) * invscales; + } + else if (tmp.z > scalar_type(0.0)) + { + const scalar_type scales = hlsl::sqrt(tmp.z + scalar_type(1.0)); + const scalar_type invscales = scalar_type(0.5) / scales; + retval.data.x = (m[1][0] + m[0][1]) * invscales; + retval.data.y = scales * scalar_type(0.5); + retval.data.z = (m[2][1] + m[1][2]) * invscales; + retval.data.w = (m[2][0] - m[0][2]) * invscales; + } + else + { + const scalar_type scales = hlsl::sqrt(tmp.w + scalar_type(1.0)); + const scalar_type invscales = scalar_type(0.5) / scales; + retval.data.x = (m[2][0] + m[0][2]) * invscales; + retval.data.y = (m[2][1] + m[1][2]) * invscales; + retval.data.z = scales * scalar_type(0.5); + retval.data.w = (m[0][1] - m[1][0]) * invscales; + } + } + + retval.data = retval.data * uniformScale; // restore uniform scale + return retval; + } + + this_t operator*(scalar_type scalar) NBL_CONST_MEMBER_FUNC + { + this_t output; + output.data = data * scalar; + return output; + } + + this_t operator*(NBL_CONST_REF_ARG(this_t) other) NBL_CONST_MEMBER_FUNC { this_t retval; - retval.data.xyz = first3Components; - retval.data.w = hlsl::sqrt(scalar_type(1.0) - hlsl::dot(first3Components, first3Components)); + retval.data = data_type( + data.w * other.data.x + data.x * other.data.w + data.y * other.data.z - data.z * other.data.y, + data.w * other.data.y - data.x * other.data.z + data.y * other.data.w + data.z * other.data.x, + data.w * other.data.z + data.x * other.data.y - data.y * other.data.x + data.z * other.data.w, + data.w * other.data.w - data.x * other.data.x - data.y * other.data.y - data.z * other.data.z + ); return retval; } - static this_t lerp(const this_t start, const this_t end, const scalar_type fraction, const scalar_type totalPseudoAngle) + static this_t unnormLerp(const this_t start, const this_t end, const scalar_type fraction, const scalar_type totalPseudoAngle) { - using AsUint = typename unsigned_integer_of_size::type; - const AsUint negationMask = hlsl::bit_cast(totalPseudoAngle) & AsUint(0x80000000u); - const data_type adjEnd = hlsl::bit_cast(hlsl::bit_cast(end.data) ^ negationMask); + assert(testing::relativeApproxCompare(hlsl::length(start.data), scalar_type(1.0), scalar_type(1e-4))); + assert(testing::relativeApproxCompare(hlsl::length(end.data), scalar_type(1.0), scalar_type(1e-4))); + const data_type adjEnd = ieee754::flipSignIfRHSNegative(end.data, totalPseudoAngle); this_t retval; - retval.data = hlsl::mix(start.data, adjEnd, fraction); + retval.data = hlsl::mix(start.data, adjEnd, hlsl::promote(fraction)); return retval; } + static this_t unnormLerp(const this_t start, const this_t end, const scalar_type fraction) + { + return unnormLerp(start, end, fraction, hlsl::dot(start.data, end.data)); + } + static this_t lerp(const this_t start, const this_t end, const scalar_type fraction) { - return lerp(start, end, fraction, hlsl::dot(start.data, end.data)); + this_t retval = unnormLerp(start, end, fraction); + retval.data = hlsl::normalize(retval.data); + return retval; } static scalar_type __adj_interpolant(const scalar_type angle, const scalar_type fraction, const scalar_type interpolantPrecalcTerm2, const scalar_type interpolantPrecalcTerm3) @@ -55,19 +236,43 @@ struct quaternion return fraction + interpolantPrecalcTerm3 * k; } - static this_t flerp(const this_t start, const this_t end, const scalar_type fraction) + static this_t unnormFlerp(const this_t start, const this_t end, const scalar_type fraction) { + assert(testing::relativeApproxCompare(hlsl::length(start.data), scalar_type(1.0), scalar_type(1e-4))); + assert(testing::relativeApproxCompare(hlsl::length(end.data), scalar_type(1.0), scalar_type(1e-4))); + const scalar_type pseudoAngle = hlsl::dot(start.data,end.data); const scalar_type interpolantPrecalcTerm = fraction - scalar_type(0.5); const scalar_type interpolantPrecalcTerm3 = fraction * interpolantPrecalcTerm * (fraction - scalar_type(1.0)); const scalar_type adjFrac = __adj_interpolant(hlsl::abs(pseudoAngle),fraction,interpolantPrecalcTerm*interpolantPrecalcTerm,interpolantPrecalcTerm3); - this_t retval = lerp(start,end,adjFrac,pseudoAngle); + this_t retval = unnormLerp(start,end,adjFrac,pseudoAngle); + return retval; + } + + static this_t flerp(const this_t start, const this_t end, const scalar_type fraction) + { + this_t retval = unnormFlerp(start,end,fraction); retval.data = hlsl::normalize(retval.data); return retval; } - matrix_type constructMatrix() + vector3_type transformVector(const vector3_type v, const bool assumeNoScale=false) NBL_CONST_MEMBER_FUNC + { + const scalar_type scaleRcp = hlsl::rsqrt(hlsl::dot(data, data)); + vector3_type retV = v; + scalar_type modVScale = scalar_type(2.0); + if (!assumeNoScale) + { + retV /= scaleRcp; + modVScale *= scaleRcp; + } + const vector3_type modV = v * modVScale; + const vector3_type direction = data.xyz; + return retV + hlsl::cross(direction, modV * data.w + hlsl::cross(direction, modV)); + } + + matrix_type __constructMatrix() NBL_CONST_MEMBER_FUNC { matrix_type mat; mat[0] = data.yzx * data.ywz + data.zxy * data.zyw * vector3_type( 1.0, 1.0,-1.0); @@ -76,8 +281,10 @@ struct quaternion mat[0][0] = scalar_type(0.5) - mat[0][0]; mat[1][1] = scalar_type(0.5) - mat[1][1]; mat[2][2] = scalar_type(0.5) - mat[2][2]; - mat *= scalar_type(2.0); - return hlsl::transpose(mat); // TODO: double check transpose? + mat[0] = mat[0] * scalar_type(2.0); + mat[1] = mat[1] * scalar_type(2.0); + mat[2] = mat[2] * scalar_type(2.0); + return mat; } static vector3_type slerp_delta(const vector3_type start, const vector3_type preScaledWaypoint, scalar_type cosAngleFromStart) @@ -94,10 +301,110 @@ struct quaternion return precompPart * cosAngle + hlsl::cross(planeNormal, precompPart); } + static this_t slerp(const this_t start, const this_t end, const scalar_type fraction, const scalar_type threshold = numeric_limits::epsilon) + { + const scalar_type totalPseudoAngle = hlsl::dot(start.data, end.data); + + // make sure we use the short rotation + const scalar_type cosA = ieee754::flipSignIfRHSNegative(totalPseudoAngle, totalPseudoAngle); + if (cosA <= (scalar_type(1.0) - threshold)) // spherical interpolation + { + assert(testing::relativeApproxCompare(hlsl::length(start.data), scalar_type(1.0), scalar_type(1e-4))); + assert(testing::relativeApproxCompare(hlsl::length(end.data), scalar_type(1.0), scalar_type(1e-4))); + + this_t retval; + const scalar_type sinARcp = scalar_type(1.0) / hlsl::sqrt(scalar_type(1.0) - cosA * cosA); + const scalar_type sinAt = hlsl::sin(fraction * hlsl::acos(cosA)); + const scalar_type sinAt_over_sinA = sinAt*sinARcp; + const scalar_type scale = hlsl::sqrt(scalar_type(1.0)-sinAt*sinAt) - sinAt_over_sinA*cosA; //cosAt-cos(A)sin(tA)/sin(A) = (sin(A)cos(tA)-cos(A)sin(tA))/sin(A) + const data_type adjEnd = ieee754::flipSignIfRHSNegative(end.data, totalPseudoAngle); + retval.data = scale * start.data + sinAt_over_sinA * adjEnd; + + return retval; + } + else + return unnormLerp(start, end, fraction, totalPseudoAngle); + } + data_type data; }; } + + +namespace cpp_compat_intrinsics_impl +{ +template +struct normalize_helper > +{ + static inline math::quaternion __call(const math::quaternion q) + { + math::quaternion retval; + retval.data = hlsl::normalize(q.data); + return retval; + } +}; +} + +namespace impl +{ +template +struct static_cast_helper, math::truncated_quaternion > +{ + static inline math::quaternion cast(const math::truncated_quaternion q) + { + math::quaternion retval; + retval.data.xyz = q.data; + retval.data.w = hlsl::sqrt(T(1.0) - hlsl::dot(q.data, q.data)); + return retval; + } +}; + +template +struct static_cast_helper, math::quaternion > +{ + static inline math::truncated_quaternion cast(const math::quaternion q) + { + assert(testing::relativeApproxCompare(hlsl::length(q.data), T(1.0), T(1e-4))); + math::truncated_quaternion t; + t.data.x = q.data.x; + t.data.y = q.data.y; + t.data.z = q.data.z; + return t; + } +}; + +template +struct static_cast_helper, math::quaternion > +{ + static inline matrix cast(const math::quaternion q) + { + return q.__constructMatrix(); + } +}; + +template +struct static_cast_helper, matrix > +{ + static inline math::quaternion cast(const matrix m) + { + return math::quaternion::create(m, true); + } +}; +} + +template +math::quaternion inverse(const math::quaternion q) +{ + math::quaternion retval; + retval.data.x = -q.data.x; + retval.data.y = -q.data.y; + retval.data.z = -q.data.z; + retval.data.w = q.data.w; + retval.data /= hlsl::dot(q.data,q.data); + return retval; +} + } } diff --git a/include/nbl/builtin/hlsl/testing/orientation_compare.hlsl b/include/nbl/builtin/hlsl/testing/orientation_compare.hlsl new file mode 100644 index 0000000000..3228872b4d --- /dev/null +++ b/include/nbl/builtin/hlsl/testing/orientation_compare.hlsl @@ -0,0 +1,46 @@ +#ifndef _NBL_BUILTIN_HLSL_TESTING_ORIENTATION_COMPARE_INCLUDED_ +#define _NBL_BUILTIN_HLSL_TESTING_ORIENTATION_COMPARE_INCLUDED_ + +#include + +namespace nbl +{ +namespace hlsl +{ +namespace testing +{ +namespace impl +{ + +template) +struct OrientationCompareHelper +{ + static bool __call(NBL_CONST_REF_ARG(FloatingPointVector) lhs, NBL_CONST_REF_ARG(FloatingPointVector) rhs, const float64_t maxAllowedDifference) + { + using traits = nbl::hlsl::vector_traits; + using scalar_t = typename traits::scalar_type; + + const scalar_t dotLR = hlsl::abs(hlsl::dot(lhs, rhs)); + const scalar_t dotLL = hlsl::dot(lhs,lhs); + const scalar_t dotRR = hlsl::dot(rhs,rhs); + if (dotLL < numeric_limits::min || dotRR < numeric_limits::min) + return false; + + const scalar_t scale = hlsl::sqrt(dotLL * dotRR); + return relativeApproxCompare(dotLR, scale, maxAllowedDifference); + } +}; + +} + +template +bool orientationCompare(NBL_CONST_REF_ARG(T) lhs, NBL_CONST_REF_ARG(T) rhs, const float64_t maxAllowedDifference) +{ + return impl::OrientationCompareHelper::__call(lhs, rhs, maxAllowedDifference); +} + +} +} +} + +#endif \ No newline at end of file diff --git a/include/nbl/builtin/hlsl/testing/vector_length_compare.hlsl b/include/nbl/builtin/hlsl/testing/vector_length_compare.hlsl new file mode 100644 index 0000000000..03bf72b006 --- /dev/null +++ b/include/nbl/builtin/hlsl/testing/vector_length_compare.hlsl @@ -0,0 +1,45 @@ +#ifndef _NBL_BUILTIN_HLSL_TESTING_VECTOR_LENGTH_COMPARE_INCLUDED_ +#define _NBL_BUILTIN_HLSL_TESTING_VECTOR_LENGTH_COMPARE_INCLUDED_ + +#include +#include +#include + +namespace nbl +{ +namespace hlsl +{ +namespace testing +{ +namespace impl +{ + +template) +struct LengthCompareHelper +{ + static bool __call(NBL_CONST_REF_ARG(FloatingPointVector) lhs, NBL_CONST_REF_ARG(FloatingPointVector) rhs, const float64_t maxAbsoluteDifference, const float64_t maxRelativeDifference) + { + using traits = nbl::hlsl::vector_traits; + using scalar_t = typename traits::scalar_type; + + const scalar_t dotLL = hlsl::dot(lhs,lhs); + const scalar_t dotRR = hlsl::dot(rhs,rhs); + const scalar_t diff = hlsl::abs(dotLL-dotRR); + const scalar_t sc = hlsl::max(dotLL,dotRR); + return diff <= maxAbsoluteDifference || diff <= maxRelativeDifference*sc; + } +}; + +} + +template +bool vectorLengthCompare(NBL_CONST_REF_ARG(T) lhs, NBL_CONST_REF_ARG(T) rhs, const float64_t maxAbsoluteDifference, const float64_t maxRelativeDifference) +{ + return impl::LengthCompareHelper::__call(lhs, rhs, maxAbsoluteDifference, maxRelativeDifference); +} + +} +} +} + +#endif \ No newline at end of file diff --git a/src/nbl/builtin/CMakeLists.txt b/src/nbl/builtin/CMakeLists.txt index d55362ef39..7a2a2e27c2 100644 --- a/src/nbl/builtin/CMakeLists.txt +++ b/src/nbl/builtin/CMakeLists.txt @@ -223,6 +223,7 @@ LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/format.hlsl") #linear algebra LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/linalg/fast_affine.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/linalg/transform.hlsl") +LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/linalg/matrix_runtime_traits.hlsl") # TODO: rename `equations` to `polynomials` probably LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/functions.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/geometry.hlsl") @@ -376,5 +377,7 @@ LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/rwmc/ResolveParameters.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/morton.hlsl") #testing LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/testing/relative_approx_compare.hlsl") +LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/testing/orientation_compare.hlsl") +LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/testing/vector_length_compare.hlsl") ADD_CUSTOM_BUILTIN_RESOURCES(nblBuiltinResourceData NBL_RESOURCES_TO_EMBED "${NBL_ROOT_PATH}/include" "nbl/builtin" "nbl::builtin" "${NBL_ROOT_PATH_BINARY}/include" "${NBL_ROOT_PATH_BINARY}/src" "STATIC" "INTERNAL")