From 781df861c9ccc2441c08568d79275dfed6de8c47 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 2 Dec 2025 17:13:14 +0700 Subject: [PATCH 01/37] split out new quaternion hlsl stuff over from hlsl path tracer example --- .../nbl/builtin/hlsl/math/quaternions.hlsl | 305 ++++++++++++++++++ src/nbl/builtin/CMakeLists.txt | 1 + 2 files changed, 306 insertions(+) create mode 100644 include/nbl/builtin/hlsl/math/quaternions.hlsl diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl new file mode 100644 index 0000000000..834d41cb54 --- /dev/null +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -0,0 +1,305 @@ +// 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_ +#define _NBL_BUILTIN_HLSL_MATH_QUATERNIONS_INCLUDED_ + +#include "nbl/builtin/hlsl/cpp_compat.hlsl" +#include "nbl/builtin/hlsl/tgmath.hlsl" + +namespace nbl +{ +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 +{ + using this_t = quaternion; + using scalar_type = T; + using data_type = vector; + using vector3_type = vector; + using matrix_type = matrix; + + 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; + } + + static this_t create(scalar_type x, scalar_type y, scalar_type z, scalar_type w) + { + this_t q; + q.data = data_type(x, y, z, w); + return q; + } + + static this_t create(NBL_CONST_REF_ARG(this_t) other) + { + return other; + } + + // angle: Rotation angle expressed in radians. + // axis: Rotation axis, must be normalized. + static this_t create(scalar_type angle, const vector3_type axis) + { + this_t q; + const scalar_type sinTheta = hlsl::sin(angle * 0.5); + const scalar_type cosTheta = hlsl::cos(angle * 0.5); + q.data = data_type(axis * sinTheta, cosTheta); + return q; + } + + + static this_t create(scalar_type pitch, scalar_type yaw, scalar_type roll) + { + const scalar_type rollDiv2 = roll * scalar_type(0.5); + const scalar_type sr = hlsl::sin(rollDiv2); + const scalar_type cr = hlsl::cos(rollDiv2); + + const scalar_type pitchDiv2 = pitch * scalar_type(0.5); + const scalar_type sp = hlsl::sin(pitchDiv2); + const scalar_type cp = hlsl::cos(pitchDiv2); + + const scalar_type yawDiv2 = yaw * scalar_type(0.5); + const scalar_type sy = hlsl::sin(yawDiv2); + const scalar_type cy = hlsl::cos(yawDiv2); + + this_t output; + output.data[0] = cr * sp * cy + sr * cp * sy; // x + output.data[1] = cr * cp * sy - sr * sp * cy; // y + output.data[2] = sr * cp * cy - cr * sp * sy; // z + output.data[3] = cr * cp * cy + sr * sp * sy; // w + + return output; + } + + static this_t create(NBL_CONST_REF_ARG(matrix_type) m) + { + const scalar_type m00 = m[0][0], m11 = m[1][1], m22 = m[2][2]; + const scalar_type neg_m00 = bit_cast(bit_cast(m00)^0x80000000u); + const scalar_type neg_m11 = bit_cast(bit_cast(m11)^0x80000000u); + const scalar_type neg_m22 = bit_cast(bit_cast(m22)^0x80000000u); + 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 = hlsl::promote(1.0) + Qx + Qy + Qz; + const data_type invscales = hlsl::promote(0.5) / hlsl::sqrt(tmp); + const data_type scales = tmp * invscales * hlsl::promote(0.5); + + // TODO: speed this up + this_t retval; + if (tmp.x > scalar_type(0.0)) + { + retval.data.x = (m[2][1] - m[1][2]) * invscales.x; + retval.data.y = (m[0][2] - m[2][0]) * invscales.x; + retval.data.z = (m[1][0] - m[0][1]) * invscales.x; + retval.data.w = scales.x; + } + else + { + if (tmp.y > scalar_type(0.0)) + { + retval.data.x = scales.y; + retval.data.y = (m[0][1] + m[1][0]) * invscales.y; + retval.data.z = (m[2][0] + m[0][2]) * invscales.y; + retval.data.w = (m[2][1] - m[1][2]) * invscales.y; + } + else if (tmp.z > scalar_type(0.0)) + { + retval.data.x = (m[0][1] + m[1][0]) * invscales.z; + retval.data.y = scales.z; + retval.data.z = (m[0][2] - m[2][0]) * invscales.z; + retval.data.w = (m[1][2] + m[2][1]) * invscales.z; + } + else + { + retval.data.x = (m[0][2] + m[2][0]) * invscales.w; + retval.data.y = (m[1][2] + m[2][1]) * invscales.w; + retval.data.z = scales.w; + retval.data.w = (m[1][0] - m[0][1]) * invscales.w; + } + } + + retval.data = hlsl::normalize(retval.data); + return retval; + } + + static this_t create(NBL_CONST_REF_ARG(truncated_quaternion) first3Components) + { + this_t retval; + retval.data.xyz = first3Components.data; + retval.data.w = hlsl::sqrt(scalar_type(1.0) - hlsl::dot(first3Components.data, first3Components.data)); + return retval; + } + + this_t operator*(scalar_type scalar) + { + this_t output; + output.data = data * scalar; + return output; + } + + this_t operator*(NBL_CONST_REF_ARG(this_t) other) + { + return this_t::create( + data.w * other.data.w - data.x * other.x - data.y * other.data.y - data.z * other.data.z, + data.w * other.data.x + data.x * other.w + data.y * other.data.z - data.z * other.data.y, + data.w * other.data.y - data.x * other.z + data.y * other.data.w + data.z * other.data.x, + data.w * other.data.z + data.x * other.y - data.y * other.data.x + data.z * other.data.w + ); + } + + static this_t lerp(const this_t start, const this_t end, const scalar_type fraction, const scalar_type totalPseudoAngle) + { + const AsUint negationMask = hlsl::bit_cast(totalPseudoAngle) & AsUint(0x80000000u); + const data_type adjEnd = hlsl::bit_cast(hlsl::bit_cast(end.data) ^ negationMask); + + this_t retval; + retval.data = hlsl::mix(start.data, adjEnd, fraction); + return retval; + } + + 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)); + } + + static scalar_type __adj_interpolant(const scalar_type angle, const scalar_type fraction, const scalar_type interpolantPrecalcTerm2, const scalar_type interpolantPrecalcTerm3) + { + const scalar_type A = scalar_type(1.0904) + angle * (scalar_type(-3.2452) + angle * (scalar_type(3.55645) - angle * scalar_type(1.43519))); + const scalar_type B = scalar_type(0.848013) + angle * (scalar_type(-1.06021) + angle * scalar_type(0.215638)); + const scalar_type k = A * interpolantPrecalcTerm2 + B; + return fraction + interpolantPrecalcTerm3 * k; + } + + static this_t flerp(const this_t start, const this_t end, const scalar_type fraction) + { + 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); + retval.data = hlsl::normalize(retval.data); + return retval; + } + + vector3_type transformVector(const vector3_type v) + { + scalar_type scale = hlsl::length(data); + vector3_type direction = data.xyz; + return v * scale + hlsl::cross(direction, v * data.w + hlsl::cross(direction, v)) * scalar_type(2.0); + } + + matrix_type constructMatrix() + { + matrix_type mat; + mat[0] = data.yzx * data.ywz + data.zxy * data.zyw * vector3_type( 1.0, 1.0,-1.0); + mat[1] = data.yzx * data.xzw + data.zxy * data.wxz * vector3_type(-1.0, 1.0, 1.0); + mat[2] = data.yzx * data.wyx + data.zxy * data.xwy * vector3_type( 1.0,-1.0, 1.0); + 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? + } + + static vector3_type slerp_delta(const vector3_type start, const vector3_type preScaledWaypoint, scalar_type cosAngleFromStart) + { + vector3_type planeNormal = hlsl::cross(start,preScaledWaypoint); + + cosAngleFromStart *= scalar_type(0.5); + const scalar_type sinAngle = hlsl::sqrt(scalar_type(0.5) - cosAngleFromStart); + const scalar_type cosAngle = hlsl::sqrt(scalar_type(0.5) + cosAngleFromStart); + + planeNormal *= sinAngle; + const vector3_type precompPart = hlsl::cross(planeNormal, start) * scalar_type(2.0); + + return precompPart * cosAngle + hlsl::cross(planeNormal, precompPart); + } + + this_t inverse() + { + this_t retval; + retval.data.x = bit_cast(bit_cast(data.x)^0x80000000u); + retval.data.y = bit_cast(bit_cast(data.y)^0x80000000u); + retval.data.z = bit_cast(bit_cast(data.z)^0x80000000u); + retval.data.w = data.w; + return retval; + } + + static this_t normalize(NBL_CONST_REF_ARG(this_t) q) + { + this_t retval; + retval.data = hlsl::normalize(q.data); + return retval; + } + + data_type data; +}; + +} + +namespace impl +{ + +template +struct static_cast_helper, math::truncated_quaternion > +{ + static inline math::quaternion cast(math::truncated_quaternion q) + { + return math::quaternion::create(q); + } +}; + +template +struct static_cast_helper, math::quaternion > +{ + static inline math::truncated_quaternion cast(math::quaternion q) + { + math::truncated_quaternion t; + t.data.x = t.data.x; + t.data.y = t.data.y; + t.data.z = t.data.z; + return t; + } +}; + +template +struct static_cast_helper, math::quaternion > +{ + static inline matrix cast(math::quaternion q) + { + return q.constructMatrix(); + } +}; +} + +} +} + +#endif diff --git a/src/nbl/builtin/CMakeLists.txt b/src/nbl/builtin/CMakeLists.txt index e8798499f9..37c5d2e43e 100644 --- a/src/nbl/builtin/CMakeLists.txt +++ b/src/nbl/builtin/CMakeLists.txt @@ -225,6 +225,7 @@ LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/geometry.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/intutil.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/polar.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/angle_adding.hlsl") +LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/quaternions.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/equations/quadratic.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/equations/cubic.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/equations/quartic.hlsl") From 1bf0616246f047c9be399181b319e1c5611e4617 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 11 Dec 2025 15:52:35 +0700 Subject: [PATCH 02/37] removed redundant constructors, some reorganize quaternions --- .../nbl/builtin/hlsl/math/quaternions.hlsl | 63 ++++++++++--------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 834d41cb54..6114949572 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -48,22 +48,10 @@ struct quaternion q.data = data_type(0.0, 0.0, 0.0, 1.0); return q; } - - static this_t create(scalar_type x, scalar_type y, scalar_type z, scalar_type w) - { - this_t q; - q.data = data_type(x, y, z, w); - return q; - } - - static this_t create(NBL_CONST_REF_ARG(this_t) other) - { - return other; - } // angle: Rotation angle expressed in radians. // axis: Rotation axis, must be normalized. - static this_t create(scalar_type angle, const vector3_type axis) + static this_t create(const vector3_type axis, scalar_type angle) { this_t q; const scalar_type sinTheta = hlsl::sin(angle * 0.5); @@ -72,28 +60,39 @@ struct quaternion return q; } - - static this_t create(scalar_type pitch, scalar_type yaw, scalar_type roll) + template NBL_FUNC_REQUIRES(is_same_v,U>) + static this_t create(const U halfPitchCosSin, const U halfYawCosSin, const U halfRollCosSin) { - const scalar_type rollDiv2 = roll * scalar_type(0.5); - const scalar_type sr = hlsl::sin(rollDiv2); - const scalar_type cr = hlsl::cos(rollDiv2); + const scalar_type cp = halfPitchCosSin.x; + const scalar_type sp = halfPitchCosSin.y; - const scalar_type pitchDiv2 = pitch * scalar_type(0.5); - const scalar_type sp = hlsl::sin(pitchDiv2); - const scalar_type cp = hlsl::cos(pitchDiv2); + const scalar_type cy = halfYawCosSin.x; + const scalar_type sy = halfYawCosSin.y; - const scalar_type yawDiv2 = yaw * scalar_type(0.5); - const scalar_type sy = hlsl::sin(yawDiv2); - const scalar_type cy = hlsl::cos(yawDiv2); + const scalar_type cr = halfRollCosSin.x; + const scalar_type sr = halfRollCosSin.y; - this_t output; - output.data[0] = cr * sp * cy + sr * cp * sy; // x - output.data[1] = cr * cp * sy - sr * sp * cy; // y - output.data[2] = sr * cp * cy - cr * sp * sy; // z - output.data[3] = cr * cp * cy + sr * sp * sy; // w + 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 output; + 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) @@ -165,12 +164,14 @@ struct quaternion this_t operator*(NBL_CONST_REF_ARG(this_t) other) { - return this_t::create( + this_t retval; + retval.data = data_type( data.w * other.data.w - data.x * other.x - data.y * other.data.y - data.z * other.data.z, data.w * other.data.x + data.x * other.w + data.y * other.data.z - data.z * other.data.y, data.w * other.data.y - data.x * other.z + data.y * other.data.w + data.z * other.data.x, data.w * other.data.z + data.x * other.y - data.y * other.data.x + data.z * other.data.w ); + return retval; } static this_t lerp(const this_t start, const this_t end, const scalar_type fraction, const scalar_type totalPseudoAngle) From 8745a33514602e3a3089f588d2988dcb027fe733 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 11 Dec 2025 16:46:12 +0700 Subject: [PATCH 03/37] added some checks to create from rot mat --- .../nbl/builtin/hlsl/math/quaternions.hlsl | 75 ++++++++++++++----- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 6114949572..49ad0dde96 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -95,8 +95,43 @@ struct quaternion ); } - static this_t create(NBL_CONST_REF_ARG(matrix_type) m) + static bool __isEqual(const scalar_type a, const scalar_type b) { + return hlsl::max(a/b, b/a) <= scalar_type(1e-4); + } + static bool __dotIsZero(const vector3_type a, const vector3_type b) + { + const scalar_type ab = hlsl::dot(a, b); + return hlsl::abs(ab) <= scalar_type(1e-4); + } + + static this_t create(NBL_CONST_REF_ARG(matrix_type) m, const bool dontAssertValidMatrix=false) + { + { + // only orthogonal and uniform scale mats can be converted + bool valid = __dotIsZero(m[0], m[1]); + valid = __dotIsZero(m[1], m[2]) && valid; + valid = __dotIsZero(m[0], m[2]) && valid; + + const matrix_type m_T = hlsl::transpose(m); + const scalar_type dotCol0 = hlsl::dot(m_T[0],m_T[0]); + const scalar_type dotCol1 = hlsl::dot(m_T[1],m_T[1]); + const scalar_type dotCol2 = hlsl::dot(m_T[2],m_T[2]); + valid = __isEqual(dotCol0, dotCol1) && valid; + valid = __isEqual(dotCol1, dotCol2) && valid; + valid = __isEqual(dotCol0, dotCol2) && valid; + + if (dontAssertValidMatrix) + if (!valid) + { + this_t retval; + retval.data = hlsl::promote(bit_cast(numeric_limits::quiet_NaN)); + return retval; + } + else + assert(valid); + } + const scalar_type m00 = m[0][0], m11 = m[1][1], m22 = m[2][2]; const scalar_type neg_m00 = bit_cast(bit_cast(m00)^0x80000000u); const scalar_type neg_m11 = bit_cast(bit_cast(m11)^0x80000000u); @@ -106,40 +141,42 @@ struct quaternion const data_type Qz = data_type(m22, neg_m22, neg_m22, m22); const data_type tmp = hlsl::promote(1.0) + Qx + Qy + Qz; - const data_type invscales = hlsl::promote(0.5) / hlsl::sqrt(tmp); - const data_type scales = tmp * invscales * hlsl::promote(0.5); // TODO: speed this up this_t retval; if (tmp.x > scalar_type(0.0)) { - retval.data.x = (m[2][1] - m[1][2]) * invscales.x; - retval.data.y = (m[0][2] - m[2][0]) * invscales.x; - retval.data.z = (m[1][0] - m[0][1]) * invscales.x; - retval.data.w = scales.x; + const scalar_type invscales = scalar_type(0.5) / hlsl::sqrt(tmp.x); + retval.data.x = (m[2][1] - m[1][2]) * invscales; + retval.data.y = (m[0][2] - m[2][0]) * invscales; + retval.data.z = (m[1][0] - m[0][1]) * invscales; + retval.data.w = tmp.x * invscales * scalar_type(0.5); } else { if (tmp.y > scalar_type(0.0)) { - retval.data.x = scales.y; - retval.data.y = (m[0][1] + m[1][0]) * invscales.y; - retval.data.z = (m[2][0] + m[0][2]) * invscales.y; - retval.data.w = (m[2][1] - m[1][2]) * invscales.y; + const scalar_type invscales = scalar_type(0.5) / hlsl::sqrt(tmp.y); + retval.data.x = tmp.y * invscales * scalar_type(0.5); + retval.data.y = (m[0][1] + m[1][0]) * invscales; + retval.data.z = (m[2][0] + m[0][2]) * invscales; + retval.data.w = (m[2][1] - m[1][2]) * invscales; } else if (tmp.z > scalar_type(0.0)) { - retval.data.x = (m[0][1] + m[1][0]) * invscales.z; - retval.data.y = scales.z; - retval.data.z = (m[0][2] - m[2][0]) * invscales.z; - retval.data.w = (m[1][2] + m[2][1]) * invscales.z; + const scalar_type invscales = scalar_type(0.5) / hlsl::sqrt(tmp.z); + retval.data.x = (m[0][1] + m[1][0]) * invscales; + retval.data.y = tmp.z * invscales * scalar_type(0.5); + retval.data.z = (m[0][2] - m[2][0]) * invscales; + retval.data.w = (m[1][2] + m[2][1]) * invscales; } else { - retval.data.x = (m[0][2] + m[2][0]) * invscales.w; - retval.data.y = (m[1][2] + m[2][1]) * invscales.w; - retval.data.z = scales.w; - retval.data.w = (m[1][0] - m[0][1]) * invscales.w; + const scalar_type invscales = scalar_type(0.5) / hlsl::sqrt(tmp.w); + retval.data.x = (m[0][2] + m[2][0]) * invscales; + retval.data.y = (m[1][2] + m[2][1]) * invscales; + retval.data.z = tmp.w * invscales * scalar_type(0.5); + retval.data.w = (m[1][0] - m[0][1]) * invscales; } } From 2a8451d73fab71fe283563cbcaff631c07f181e5 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 12 Dec 2025 11:15:26 +0700 Subject: [PATCH 04/37] moved normalize, static_cast to helper specializations, norm and unnorm variants for lerp/flerp --- .../nbl/builtin/hlsl/math/quaternions.hlsl | 85 ++++++++++++------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 49ad0dde96..73dc977d62 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -184,14 +184,6 @@ struct quaternion return retval; } - static this_t create(NBL_CONST_REF_ARG(truncated_quaternion) first3Components) - { - this_t retval; - retval.data.xyz = first3Components.data; - retval.data.w = hlsl::sqrt(scalar_type(1.0) - hlsl::dot(first3Components.data, first3Components.data)); - return retval; - } - this_t operator*(scalar_type scalar) { this_t output; @@ -211,19 +203,26 @@ struct quaternion 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) { - const AsUint negationMask = hlsl::bit_cast(totalPseudoAngle) & AsUint(0x80000000u); - const data_type adjEnd = hlsl::bit_cast(hlsl::bit_cast(end.data) ^ negationMask); + // TODO: benchmark uint sign flip vs just *sign(totalPseudoAngle) + const data_type adjEnd = ieee754::flipSignIfRHSNegative(end.data, totalPseudoAngle); this_t retval; retval.data = hlsl::mix(start.data, adjEnd, 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) @@ -234,26 +233,32 @@ 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) { 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,adjFrac,pseudoAngle); retval.data = hlsl::normalize(retval.data); return retval; } - vector3_type transformVector(const vector3_type v) + vector3_type transformVector(const vector3_type v, const bool assumeNoScale=false) NBL_CONST_MEMBER_FUNC { - scalar_type scale = hlsl::length(data); + scalar_type scale = hlsl::mix(hlsl::length(data), scalar_type(1.0), assumeNoScale); vector3_type direction = data.xyz; return v * scale + hlsl::cross(direction, v * data.w + hlsl::cross(direction, v)) * scalar_type(2.0); } - matrix_type constructMatrix() + 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); @@ -280,23 +285,14 @@ struct quaternion return precompPart * cosAngle + hlsl::cross(planeNormal, precompPart); } - this_t inverse() + this_t inverse() NBL_CONST_MEMBER_FUNC { this_t retval; - retval.data.x = bit_cast(bit_cast(data.x)^0x80000000u); - retval.data.y = bit_cast(bit_cast(data.y)^0x80000000u); - retval.data.z = bit_cast(bit_cast(data.z)^0x80000000u); + retval.data.xyz = -retval.data.xyz; retval.data.w = data.w; return retval; } - static this_t normalize(NBL_CONST_REF_ARG(this_t) q) - { - this_t retval; - retval.data = hlsl::normalize(q.data); - return retval; - } - data_type data; }; @@ -305,19 +301,44 @@ struct quaternion namespace impl { +template +struct normalize_helper > +{ + static inline math::truncated_quaternion __call(const math::truncated_quaternion q) + { + math::truncated_quaternion retval; + retval.data = hlsl::normalize(q.data); + return retval; + } +} + +template +struct normalize_helper > +{ + static inline math::quaternion __call(const math::quaternion q) + { + math::quaternion retval; + retval.data = hlsl::normalize(q.data); + return retval; + } +} + template struct static_cast_helper, math::truncated_quaternion > { - static inline math::quaternion cast(math::truncated_quaternion q) + static inline math::quaternion cast(const math::truncated_quaternion q) { - return math::quaternion::create(q); + math::quaternion retval; + retval.data.xyz = q.data; + retval.data.w = hlsl::sqrt(scalar_type(1.0) - hlsl::dot(q.data, q.data)); + return retval; } }; template struct static_cast_helper, math::quaternion > { - static inline math::truncated_quaternion cast(math::quaternion q) + static inline math::truncated_quaternion cast(const math::quaternion q) { math::truncated_quaternion t; t.data.x = t.data.x; @@ -330,7 +351,7 @@ struct static_cast_helper, math::quaternion > template struct static_cast_helper, math::quaternion > { - static inline matrix cast(math::quaternion q) + static inline matrix cast(const math::quaternion q) { return q.constructMatrix(); } From a93fa2608f608574e17937bf42bdcdc75e17e291 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 12 Dec 2025 15:39:32 +0700 Subject: [PATCH 05/37] fix some quaternion bugs --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 73dc977d62..91ee4975e3 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -246,7 +246,7 @@ struct quaternion static this_t flerp(const this_t start, const this_t end, const scalar_type fraction) { - this_t retval = unnormFlerp(start,end,adjFrac,pseudoAngle); + this_t retval = unnormFlerp(start,end,fraction); retval.data = hlsl::normalize(retval.data); return retval; } @@ -267,8 +267,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;// hlsl::transpose(mat); // TODO: double check transpose? } static vector3_type slerp_delta(const vector3_type start, const vector3_type preScaledWaypoint, scalar_type cosAngleFromStart) @@ -298,9 +300,9 @@ struct quaternion } -namespace impl -{ +namespace cpp_compat_intrinsics_impl +{ template struct normalize_helper > { @@ -310,7 +312,7 @@ struct normalize_helper > retval.data = hlsl::normalize(q.data); return retval; } -} +}; template struct normalize_helper > @@ -321,8 +323,11 @@ struct normalize_helper > retval.data = hlsl::normalize(q.data); return retval; } +}; } +namespace impl +{ template struct static_cast_helper, math::truncated_quaternion > { From f900b78b88768c600b586e92f72520ce0af4a475 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 17 Dec 2025 15:02:57 +0700 Subject: [PATCH 06/37] rng dim adaptor should not store its own copy of rng --- .../builtin/hlsl/random/dim_adaptor_recursive.hlsl | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/include/nbl/builtin/hlsl/random/dim_adaptor_recursive.hlsl b/include/nbl/builtin/hlsl/random/dim_adaptor_recursive.hlsl index cb0b522e68..cc933daa6c 100644 --- a/include/nbl/builtin/hlsl/random/dim_adaptor_recursive.hlsl +++ b/include/nbl/builtin/hlsl/random/dim_adaptor_recursive.hlsl @@ -18,14 +18,7 @@ struct DimAdaptorRecursive using rng_type = RNG; using return_type = vector; - static DimAdaptorRecursive construct(NBL_REF_ARG(rng_type) rng) - { - DimAdaptorRecursive retval; - retval.rng = rng; - return retval; - } - - return_type operator()() + static return_type __call(NBL_REF_ARG(rng_type) rng) { array_set setter; @@ -34,8 +27,6 @@ struct DimAdaptorRecursive setter(retval, i, rng()); return retval; } - - rng_type rng; }; } From 35993ae9071bf13a7e493c8bb307be14105512ee Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 23 Dec 2025 12:15:59 +0700 Subject: [PATCH 07/37] removed obsolete function --- include/nbl/builtin/hlsl/bxdf/fresnel.hlsl | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/nbl/builtin/hlsl/bxdf/fresnel.hlsl b/include/nbl/builtin/hlsl/bxdf/fresnel.hlsl index 33faa79efc..f4b83848dc 100644 --- a/include/nbl/builtin/hlsl/bxdf/fresnel.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/fresnel.hlsl @@ -431,14 +431,6 @@ struct Conductor return (rs2 + rp2) * hlsl::promote(0.5); } - // OrientedEtaRcps getRefractionOrientedEtaRcps() NBL_CONST_MEMBER_FUNC - // { - // OrientedEtaRcps rcpEta; - // rcpEta.value = hlsl::promote(1.0) / eta; - // rcpEta.value2 = rcpEta.value * rcpEta.value; - // return rcpEta; - // } - T eta; T etak2; T etaLen2; From 69248830bd878075b45a27c681ee86717f82472e Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 29 Dec 2025 14:37:06 +0700 Subject: [PATCH 08/37] implements incomplete gamma function (RLGamma from bxdf chi2 test) --- include/nbl/builtin/hlsl/tgmath.hlsl | 6 ++ include/nbl/builtin/hlsl/tgmath/impl.hlsl | 84 +++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/include/nbl/builtin/hlsl/tgmath.hlsl b/include/nbl/builtin/hlsl/tgmath.hlsl index 04765f3ba7..c569d34f85 100644 --- a/include/nbl/builtin/hlsl/tgmath.hlsl +++ b/include/nbl/builtin/hlsl/tgmath.hlsl @@ -249,6 +249,12 @@ inline T beta(NBL_CONST_REF_ARG(T) v1, NBL_CONST_REF_ARG(T) v2) return tgmath_impl::beta_helper::__call(v1, v2)/tgmath_impl::beta_helper::__call(T(1.0), T(1.0)); // ensure beta(1,1)==1 } +template +inline T gamma(NBL_CONST_REF_ARG(T) a, NBL_CONST_REF_ARG(T) x) +{ + return tgmath_impl::gamma_helper::__call(a, x); +} + } } diff --git a/include/nbl/builtin/hlsl/tgmath/impl.hlsl b/include/nbl/builtin/hlsl/tgmath/impl.hlsl index 93cbf0db13..4d1a30c757 100644 --- a/include/nbl/builtin/hlsl/tgmath/impl.hlsl +++ b/include/nbl/builtin/hlsl/tgmath/impl.hlsl @@ -98,6 +98,8 @@ template struct lgamma_helper; template struct beta_helper; +template +struct gamma_helper; #ifdef __HLSL_VERSION @@ -606,6 +608,88 @@ struct beta_helper) > } }; +// incomplete gamma function +template +NBL_PARTIAL_REQ_TOP(concepts::FloatingPointScalar) +struct gamma_helper) > +{ + NBL_CONSTEXPR_STATIC_INLINE T epsilon = 1e-15; + NBL_CONSTEXPR_STATIC_INLINE T big = 4503599627370496.0; + NBL_CONSTEXPR_STATIC_INLINE T bigInv = 2.22044604925031308085e-16; + + static T __call(T a, T x) + { + assert(a >= T(0.0) && x >= T(0.0)); + + if (x == T(0.0)) + return T(0.0); + + T ax = (a * log_helper::__call(x)) - x - lgamma_helper::__call(a); + if (ax < T(-709.78271289338399)) + return hlsl::mix(T(0.0), T(1.0), a < x); + + if (x <= T(1.0) || x <= a) + { + T r2 = a; + T c2 = T(1.0); + T ans2 = T(1.0); + + do { + r2 = r2 + T(1.0); + c2 = c2 * x / r2; + ans2 += c2; + } while ((c2 / ans2) > epsilon); + + return exp_helper::__call(ax) * ans2 / a; + } + + int c = 0; + T y = T(1.0) - a; + T z = x + y + T(1.0); + T p3 = T(1.0); + T q3 = x; + T p2 = x + T(1.0); + T q2 = z * x; + T ans = p2 / q2; + T error; + + do { + c++; + y += T(1.0); + z += T(2.0); + T yc = y * c; + T p = (p2 * z) - (p3 * yc); + T q = (q2 * z) - (q3 * yc); + + if (q != T(0.0)) + { + T nextans = p / q; + error = abs_helper::__call((ans - nextans) / nextans); + ans = nextans; + } + else + { + error = 1; + } + + p3 = p2; + p2 = p; + q3 = q2; + q2 = q; + + if (abs_helper::__call(p) > big) + { + p3 *= bigInv; + p2 *= bigInv; + q3 *= bigInv; + q2 *= bigInv; + } + } while (error > epsilon); + + return T(1.0) - (exp_helper::__call(ax) * ans); + } +}; + #ifdef __HLSL_VERSION // SPIR-V already defines specializations for builtin vector types #define VECTOR_SPECIALIZATION_CONCEPT concepts::Vectorial && !is_vector_v From 688391d3421a6a97534070871c95d6bcf59f37ec Mon Sep 17 00:00:00 2001 From: keptsecret Date: Mon, 29 Dec 2025 16:41:02 +0700 Subject: [PATCH 09/37] added draft version of adaptive simpson, only tested on cpp and should change to compile time depth --- .../math/quadrature/adaptive_simpson.hlsl | 67 +++++++++++++++++++ src/nbl/builtin/CMakeLists.txt | 1 + 2 files changed, 68 insertions(+) create mode 100644 include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl diff --git a/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl new file mode 100644 index 0000000000..db596f9c6b --- /dev/null +++ b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl @@ -0,0 +1,67 @@ +// 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_QUADRATURE_ADAPTIVE_SIMPSON_INCLUDED_ +#define _NBL_BUILTIN_HLSL_MATH_QUADRATURE_ADAPTIVE_SIMPSON_INCLUDED_ + +#include + +namespace nbl +{ +namespace hlsl +{ +namespace math +{ +namespace quadrature +{ + +namespace impl +{ +template +struct integrate_helper +{ + static float_t __call(float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, int depth, NBL_REF_ARG(int) count) + { + float_t d = float_t(0.5) * (a + b); + float_t e = float_t(0.5) * (b + c); + float_t fd = F::__call(d); + float_t fe = F::__call(e); + + float_t h = c - a; + float_t I0 = (float_t(1.0) / float_t(12.0)) * h * (fa + float_t(4.0) * fd + fb); + float_t I1 = (float_t(1.0) / float_t(12.0)) * h * (fb + float_t(4.0) * fe + fc); + float_t Ip = I0 + I1; + count++; + + if (Depth <= 0 || hlsl::abs(Ip - I) < float_t(15.0) * eps) + return Ip + (float_t(1.0) / float_t(15.0)) * (Ip - I); + + return integrate_helper::__call(a, d, b, fa, fd, fb, I0, float_t(0.5) * eps, depth-1, count) + + integrate_helper::__call(b, e, c, fb, fe, fc, I1, float_t(0.5) * eps, depth-1, count); + } +}; +} + +template // F has function __call(x) +struct AdaptiveSimpson +{ + static float_t __call(float_t x0, float_t x1, float_t eps = 1e-6) + { + int count = 0; + float_t a = x0; + float_t b = float_t(0.5) * (x0 + x1); + float_t c = x1; + float_t fa = F::__call(a); + float_t fb = F::__call(b); + float_t fc = F::__call(c); + float_t I = (c - a) * (float_t(1.0) / float_t(6.0)) * (fa + float_t(4.0) * fb + fc); + return impl::integrate_helper::__call(a, b, c, fa, fb, fc, I, eps, Depth, count); + } +}; + +} +} +} +} + +#endif diff --git a/src/nbl/builtin/CMakeLists.txt b/src/nbl/builtin/CMakeLists.txt index 085ed3c923..73e3068af2 100644 --- a/src/nbl/builtin/CMakeLists.txt +++ b/src/nbl/builtin/CMakeLists.txt @@ -236,6 +236,7 @@ LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/equations/quartic.hlsl") #extra math LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/quadrature/gauss_legendre/gauss_legendre.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/quadrature/gauss_legendre/impl.hlsl") +LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/math/quadrature/adaptive_simpson.hlsl") #acceleration structures LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/acceleration_structures.hlsl") #colorspace From 5964da0668a2992f4c7073b2110dea8774cb05d8 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 30 Dec 2025 11:28:29 +0700 Subject: [PATCH 10/37] adds turbo colormap --- .../nbl/builtin/hlsl/visualization/turbo.hlsl | 294 ++++++++++++++++++ src/nbl/builtin/CMakeLists.txt | 2 + 2 files changed, 296 insertions(+) create mode 100644 include/nbl/builtin/hlsl/visualization/turbo.hlsl diff --git a/include/nbl/builtin/hlsl/visualization/turbo.hlsl b/include/nbl/builtin/hlsl/visualization/turbo.hlsl new file mode 100644 index 0000000000..c12323ff4f --- /dev/null +++ b/include/nbl/builtin/hlsl/visualization/turbo.hlsl @@ -0,0 +1,294 @@ +// 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_VISUALIZATION_TURBO_INCLUDED_ +#define _NBL_BUILTIN_HLSL_VISUALIZATION_TURBO_INCLUDED_ + +#include + +namespace nbl +{ +namespace hlsl +{ +namespace visualization +{ + +// from Google's Turbo colormap: https://gist.github.com/mikhailov-work/6a308c20e494d9e0ccc29036b28faa7a +struct Turbo +{ + static const float32_t3 RGB_LUT[256]; + + static float32_t3 map(float x) + { + x = hlsl::clamp(x, 0.f, 1.f); + int i = int(x * 255.f); + int j = hlsl::min(255, i+1); + float s = x * 255.f - float(i); + return RGB_LUT[i] + (RGB_LUT[j] - RGB_LUT[i]) * s; + } +}; + +inline const float32_t3 Turbo::RGB_LUT[256] = { + float32_t3(0.18995,0.07176,0.23217), + float32_t3(0.19483,0.08339,0.26149), + float32_t3(0.19956,0.09498,0.29024), + float32_t3(0.20415,0.10652,0.31844), + float32_t3(0.20860,0.11802,0.34607), + float32_t3(0.21291,0.12947,0.37314), + float32_t3(0.21708,0.14087,0.39964), + float32_t3(0.22111,0.15223,0.42558), + float32_t3(0.22500,0.16354,0.45096), + float32_t3(0.22875,0.17481,0.47578), + float32_t3(0.23236,0.18603,0.50004), + float32_t3(0.23582,0.19720,0.52373), + float32_t3(0.23915,0.20833,0.54686), + float32_t3(0.24234,0.21941,0.56942), + float32_t3(0.24539,0.23044,0.59142), + float32_t3(0.24830,0.24143,0.61286), + float32_t3(0.25107,0.25237,0.63374), + float32_t3(0.25369,0.26327,0.65406), + float32_t3(0.25618,0.27412,0.67381), + float32_t3(0.25853,0.28492,0.69300), + float32_t3(0.26074,0.29568,0.71162), + float32_t3(0.26280,0.30639,0.72968), + float32_t3(0.26473,0.31706,0.74718), + float32_t3(0.26652,0.32768,0.76412), + float32_t3(0.26816,0.33825,0.78050), + float32_t3(0.26967,0.34878,0.79631), + float32_t3(0.27103,0.35926,0.81156), + float32_t3(0.27226,0.36970,0.82624), + float32_t3(0.27334,0.38008,0.84037), + float32_t3(0.27429,0.39043,0.85393), + float32_t3(0.27509,0.40072,0.86692), + float32_t3(0.27576,0.41097,0.87936), + float32_t3(0.27628,0.42118,0.89123), + float32_t3(0.27667,0.43134,0.90254), + float32_t3(0.27691,0.44145,0.91328), + float32_t3(0.27701,0.45152,0.92347), + float32_t3(0.27698,0.46153,0.93309), + float32_t3(0.27680,0.47151,0.94214), + float32_t3(0.27648,0.48144,0.95064), + float32_t3(0.27603,0.49132,0.95857), + float32_t3(0.27543,0.50115,0.96594), + float32_t3(0.27469,0.51094,0.97275), + float32_t3(0.27381,0.52069,0.97899), + float32_t3(0.27273,0.53040,0.98461), + float32_t3(0.27106,0.54015,0.98930), + float32_t3(0.26878,0.54995,0.99303), + float32_t3(0.26592,0.55979,0.99583), + float32_t3(0.26252,0.56967,0.99773), + float32_t3(0.25862,0.57958,0.99876), + float32_t3(0.25425,0.58950,0.99896), + float32_t3(0.24946,0.59943,0.99835), + float32_t3(0.24427,0.60937,0.99697), + float32_t3(0.23874,0.61931,0.99485), + float32_t3(0.23288,0.62923,0.99202), + float32_t3(0.22676,0.63913,0.98851), + float32_t3(0.22039,0.64901,0.98436), + float32_t3(0.21382,0.65886,0.97959), + float32_t3(0.20708,0.66866,0.97423), + float32_t3(0.20021,0.67842,0.96833), + float32_t3(0.19326,0.68812,0.96190), + float32_t3(0.18625,0.69775,0.95498), + float32_t3(0.17923,0.70732,0.94761), + float32_t3(0.17223,0.71680,0.93981), + float32_t3(0.16529,0.72620,0.93161), + float32_t3(0.15844,0.73551,0.92305), + float32_t3(0.15173,0.74472,0.91416), + float32_t3(0.14519,0.75381,0.90496), + float32_t3(0.13886,0.76279,0.89550), + float32_t3(0.13278,0.77165,0.88580), + float32_t3(0.12698,0.78037,0.87590), + float32_t3(0.12151,0.78896,0.86581), + float32_t3(0.11639,0.79740,0.85559), + float32_t3(0.11167,0.80569,0.84525), + float32_t3(0.10738,0.81381,0.83484), + float32_t3(0.10357,0.82177,0.82437), + float32_t3(0.10026,0.82955,0.81389), + float32_t3(0.09750,0.83714,0.80342), + float32_t3(0.09532,0.84455,0.79299), + float32_t3(0.09377,0.85175,0.78264), + float32_t3(0.09287,0.85875,0.77240), + float32_t3(0.09267,0.86554,0.76230), + float32_t3(0.09320,0.87211,0.75237), + float32_t3(0.09451,0.87844,0.74265), + float32_t3(0.09662,0.88454,0.73316), + float32_t3(0.09958,0.89040,0.72393), + float32_t3(0.10342,0.89600,0.71500), + float32_t3(0.10815,0.90142,0.70599), + float32_t3(0.11374,0.90673,0.69651), + float32_t3(0.12014,0.91193,0.68660), + float32_t3(0.12733,0.91701,0.67627), + float32_t3(0.13526,0.92197,0.66556), + float32_t3(0.14391,0.92680,0.65448), + float32_t3(0.15323,0.93151,0.64308), + float32_t3(0.16319,0.93609,0.63137), + float32_t3(0.17377,0.94053,0.61938), + float32_t3(0.18491,0.94484,0.60713), + float32_t3(0.19659,0.94901,0.59466), + float32_t3(0.20877,0.95304,0.58199), + float32_t3(0.22142,0.95692,0.56914), + float32_t3(0.23449,0.96065,0.55614), + float32_t3(0.24797,0.96423,0.54303), + float32_t3(0.26180,0.96765,0.52981), + float32_t3(0.27597,0.97092,0.51653), + float32_t3(0.29042,0.97403,0.50321), + float32_t3(0.30513,0.97697,0.48987), + float32_t3(0.32006,0.97974,0.47654), + float32_t3(0.33517,0.98234,0.46325), + float32_t3(0.35043,0.98477,0.45002), + float32_t3(0.36581,0.98702,0.43688), + float32_t3(0.38127,0.98909,0.42386), + float32_t3(0.39678,0.99098,0.41098), + float32_t3(0.41229,0.99268,0.39826), + float32_t3(0.42778,0.99419,0.38575), + float32_t3(0.44321,0.99551,0.37345), + float32_t3(0.45854,0.99663,0.36140), + float32_t3(0.47375,0.99755,0.34963), + float32_t3(0.48879,0.99828,0.33816), + float32_t3(0.50362,0.99879,0.32701), + float32_t3(0.51822,0.99910,0.31622), + float32_t3(0.53255,0.99919,0.30581), + float32_t3(0.54658,0.99907,0.29581), + float32_t3(0.56026,0.99873,0.28623), + float32_t3(0.57357,0.99817,0.27712), + float32_t3(0.58646,0.99739,0.26849), + float32_t3(0.59891,0.99638,0.26038), + float32_t3(0.61088,0.99514,0.25280), + float32_t3(0.62233,0.99366,0.24579), + float32_t3(0.63323,0.99195,0.23937), + float32_t3(0.64362,0.98999,0.23356), + float32_t3(0.65394,0.98775,0.22835), + float32_t3(0.66428,0.98524,0.22370), + float32_t3(0.67462,0.98246,0.21960), + float32_t3(0.68494,0.97941,0.21602), + float32_t3(0.69525,0.97610,0.21294), + float32_t3(0.70553,0.97255,0.21032), + float32_t3(0.71577,0.96875,0.20815), + float32_t3(0.72596,0.96470,0.20640), + float32_t3(0.73610,0.96043,0.20504), + float32_t3(0.74617,0.95593,0.20406), + float32_t3(0.75617,0.95121,0.20343), + float32_t3(0.76608,0.94627,0.20311), + float32_t3(0.77591,0.94113,0.20310), + float32_t3(0.78563,0.93579,0.20336), + float32_t3(0.79524,0.93025,0.20386), + float32_t3(0.80473,0.92452,0.20459), + float32_t3(0.81410,0.91861,0.20552), + float32_t3(0.82333,0.91253,0.20663), + float32_t3(0.83241,0.90627,0.20788), + float32_t3(0.84133,0.89986,0.20926), + float32_t3(0.85010,0.89328,0.21074), + float32_t3(0.85868,0.88655,0.21230), + float32_t3(0.86709,0.87968,0.21391), + float32_t3(0.87530,0.87267,0.21555), + float32_t3(0.88331,0.86553,0.21719), + float32_t3(0.89112,0.85826,0.21880), + float32_t3(0.89870,0.85087,0.22038), + float32_t3(0.90605,0.84337,0.22188), + float32_t3(0.91317,0.83576,0.22328), + float32_t3(0.92004,0.82806,0.22456), + float32_t3(0.92666,0.82025,0.22570), + float32_t3(0.93301,0.81236,0.22667), + float32_t3(0.93909,0.80439,0.22744), + float32_t3(0.94489,0.79634,0.22800), + float32_t3(0.95039,0.78823,0.22831), + float32_t3(0.95560,0.78005,0.22836), + float32_t3(0.96049,0.77181,0.22811), + float32_t3(0.96507,0.76352,0.22754), + float32_t3(0.96931,0.75519,0.22663), + float32_t3(0.97323,0.74682,0.22536), + float32_t3(0.97679,0.73842,0.22369), + float32_t3(0.98000,0.73000,0.22161), + float32_t3(0.98289,0.72140,0.21918), + float32_t3(0.98549,0.71250,0.21650), + float32_t3(0.98781,0.70330,0.21358), + float32_t3(0.98986,0.69382,0.21043), + float32_t3(0.99163,0.68408,0.20706), + float32_t3(0.99314,0.67408,0.20348), + float32_t3(0.99438,0.66386,0.19971), + float32_t3(0.99535,0.65341,0.19577), + float32_t3(0.99607,0.64277,0.19165), + float32_t3(0.99654,0.63193,0.18738), + float32_t3(0.99675,0.62093,0.18297), + float32_t3(0.99672,0.60977,0.17842), + float32_t3(0.99644,0.59846,0.17376), + float32_t3(0.99593,0.58703,0.16899), + float32_t3(0.99517,0.57549,0.16412), + float32_t3(0.99419,0.56386,0.15918), + float32_t3(0.99297,0.55214,0.15417), + float32_t3(0.99153,0.54036,0.14910), + float32_t3(0.98987,0.52854,0.14398), + float32_t3(0.98799,0.51667,0.13883), + float32_t3(0.98590,0.50479,0.13367), + float32_t3(0.98360,0.49291,0.12849), + float32_t3(0.98108,0.48104,0.12332), + float32_t3(0.97837,0.46920,0.11817), + float32_t3(0.97545,0.45740,0.11305), + float32_t3(0.97234,0.44565,0.10797), + float32_t3(0.96904,0.43399,0.10294), + float32_t3(0.96555,0.42241,0.09798), + float32_t3(0.96187,0.41093,0.09310), + float32_t3(0.95801,0.39958,0.08831), + float32_t3(0.95398,0.38836,0.08362), + float32_t3(0.94977,0.37729,0.07905), + float32_t3(0.94538,0.36638,0.07461), + float32_t3(0.94084,0.35566,0.07031), + float32_t3(0.93612,0.34513,0.06616), + float32_t3(0.93125,0.33482,0.06218), + float32_t3(0.92623,0.32473,0.05837), + float32_t3(0.92105,0.31489,0.05475), + float32_t3(0.91572,0.30530,0.05134), + float32_t3(0.91024,0.29599,0.04814), + float32_t3(0.90463,0.28696,0.04516), + float32_t3(0.89888,0.27824,0.04243), + float32_t3(0.89298,0.26981,0.03993), + float32_t3(0.88691,0.26152,0.03753), + float32_t3(0.88066,0.25334,0.03521), + float32_t3(0.87422,0.24526,0.03297), + float32_t3(0.86760,0.23730,0.03082), + float32_t3(0.86079,0.22945,0.02875), + float32_t3(0.85380,0.22170,0.02677), + float32_t3(0.84662,0.21407,0.02487), + float32_t3(0.83926,0.20654,0.02305), + float32_t3(0.83172,0.19912,0.02131), + float32_t3(0.82399,0.19182,0.01966), + float32_t3(0.81608,0.18462,0.01809), + float32_t3(0.80799,0.17753,0.01660), + float32_t3(0.79971,0.17055,0.01520), + float32_t3(0.79125,0.16368,0.01387), + float32_t3(0.78260,0.15693,0.01264), + float32_t3(0.77377,0.15028,0.01148), + float32_t3(0.76476,0.14374,0.01041), + float32_t3(0.75556,0.13731,0.00942), + float32_t3(0.74617,0.13098,0.00851), + float32_t3(0.73661,0.12477,0.00769), + float32_t3(0.72686,0.11867,0.00695), + float32_t3(0.71692,0.11268,0.00629), + float32_t3(0.70680,0.10680,0.00571), + float32_t3(0.69650,0.10102,0.00522), + float32_t3(0.68602,0.09536,0.00481), + float32_t3(0.67535,0.08980,0.00449), + float32_t3(0.66449,0.08436,0.00424), + float32_t3(0.65345,0.07902,0.00408), + float32_t3(0.64223,0.07380,0.00401), + float32_t3(0.63082,0.06868,0.00401), + float32_t3(0.61923,0.06367,0.00410), + float32_t3(0.60746,0.05878,0.00427), + float32_t3(0.59550,0.05399,0.00453), + float32_t3(0.58336,0.04931,0.00486), + float32_t3(0.57103,0.04474,0.00529), + float32_t3(0.55852,0.04028,0.00579), + float32_t3(0.54583,0.03593,0.00638), + float32_t3(0.53295,0.03169,0.00705), + float32_t3(0.51989,0.02756,0.00780), + float32_t3(0.50664,0.02354,0.00863), + float32_t3(0.49321,0.01963,0.00955), + float32_t3(0.47960,0.01583,0.01055) +}; + +} +} +} + +#endif diff --git a/src/nbl/builtin/CMakeLists.txt b/src/nbl/builtin/CMakeLists.txt index 73e3068af2..9f904fdf6a 100644 --- a/src/nbl/builtin/CMakeLists.txt +++ b/src/nbl/builtin/CMakeLists.txt @@ -245,6 +245,8 @@ LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/colorspace/OETF.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/colorspace/decodeCIEXYZ.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/colorspace/encodeCIEXYZ.hlsl") LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/colorspace.hlsl") +#visualization +LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/visualization/turbo.hlsl") #barycentrics LIST_BUILTIN_RESOURCE(NBL_RESOURCES_TO_EMBED "hlsl/barycentric/utils.hlsl") #scanning append From e9a325a687fb95bbf89f17fea74522a6e44eb4f7 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 30 Dec 2025 15:31:55 +0700 Subject: [PATCH 11/37] fixes 1d adaptive simpson to use compile-time depth --- .../math/quadrature/adaptive_simpson.hlsl | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl index db596f9c6b..91d577e220 100644 --- a/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl +++ b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl @@ -17,10 +17,10 @@ namespace quadrature namespace impl { -template +template // F has function __call(x) struct integrate_helper { - static float_t __call(float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, int depth, NBL_REF_ARG(int) count) + static float_t __call(float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) { float_t d = float_t(0.5) * (a + b); float_t e = float_t(0.5) * (b + c); @@ -33,11 +33,31 @@ struct integrate_helper float_t Ip = I0 + I1; count++; - if (Depth <= 0 || hlsl::abs(Ip - I) < float_t(15.0) * eps) + if (hlsl::abs(Ip - I) < float_t(15.0) * eps) return Ip + (float_t(1.0) / float_t(15.0)) * (Ip - I); - return integrate_helper::__call(a, d, b, fa, fd, fb, I0, float_t(0.5) * eps, depth-1, count) + - integrate_helper::__call(b, e, c, fb, fe, fc, I1, float_t(0.5) * eps, depth-1, count); + return integrate_helper::__call(a, d, b, fa, fd, fb, I0, float_t(0.5) * eps, count) + + integrate_helper::__call(b, e, c, fb, fe, fc, I1, float_t(0.5) * eps, count); + } +}; + +template +struct integrate_helper +{ + static float_t __call(float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) + { + float_t d = float_t(0.5) * (a + b); + float_t e = float_t(0.5) * (b + c); + float_t fd = F::__call(d); + float_t fe = F::__call(e); + + float_t h = c - a; + float_t I0 = (float_t(1.0) / float_t(12.0)) * h * (fa + float_t(4.0) * fd + fb); + float_t I1 = (float_t(1.0) / float_t(12.0)) * h * (fb + float_t(4.0) * fe + fc); + float_t Ip = I0 + I1; + count++; + + return Ip + (float_t(1.0) / float_t(15.0)) * (Ip - I); } }; } @@ -55,7 +75,7 @@ struct AdaptiveSimpson float_t fb = F::__call(b); float_t fc = F::__call(c); float_t I = (c - a) * (float_t(1.0) / float_t(6.0)) * (fa + float_t(4.0) * fb + fc); - return impl::integrate_helper::__call(a, b, c, fa, fb, fc, I, eps, Depth, count); + return impl::integrate_helper::__call(a, b, c, fa, fb, fc, I, eps, count); } }; From 3354e6a1962a5645c3e37b6cd4754b3293c6988d Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 30 Dec 2025 17:05:47 +0700 Subject: [PATCH 12/37] converted adaptive simpson 2d into templated structs --- .../math/quadrature/adaptive_simpson.hlsl | 75 +++++++++++++++---- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl index 91d577e220..61cad6ae7f 100644 --- a/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl +++ b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl @@ -20,12 +20,12 @@ namespace impl template // F has function __call(x) struct integrate_helper { - static float_t __call(float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) + static float_t __call(NBL_REF_ARG(F) f, float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) { float_t d = float_t(0.5) * (a + b); float_t e = float_t(0.5) * (b + c); - float_t fd = F::__call(d); - float_t fe = F::__call(e); + float_t fd = f.__call(d); + float_t fe = f.__call(e); float_t h = c - a; float_t I0 = (float_t(1.0) / float_t(12.0)) * h * (fa + float_t(4.0) * fd + fb); @@ -36,20 +36,20 @@ struct integrate_helper if (hlsl::abs(Ip - I) < float_t(15.0) * eps) return Ip + (float_t(1.0) / float_t(15.0)) * (Ip - I); - return integrate_helper::__call(a, d, b, fa, fd, fb, I0, float_t(0.5) * eps, count) + - integrate_helper::__call(b, e, c, fb, fe, fc, I1, float_t(0.5) * eps, count); + return integrate_helper::__call(f, a, d, b, fa, fd, fb, I0, float_t(0.5) * eps, count) + + integrate_helper::__call(f, b, e, c, fb, fe, fc, I1, float_t(0.5) * eps, count); } }; template struct integrate_helper { - static float_t __call(float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) + static float_t __call(NBL_REF_ARG(F) f, float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) { float_t d = float_t(0.5) * (a + b); float_t e = float_t(0.5) * (b + c); - float_t fd = F::__call(d); - float_t fe = F::__call(e); + float_t fd = f.__call(d); + float_t fe = f.__call(e); float_t h = c - a; float_t I0 = (float_t(1.0) / float_t(12.0)) * h * (fa + float_t(4.0) * fd + fb); @@ -65,17 +65,66 @@ struct integrate_helper template // F has function __call(x) struct AdaptiveSimpson { - static float_t __call(float_t x0, float_t x1, float_t eps = 1e-6) + static float_t __call(NBL_REF_ARG(F) f, float_t x0, float_t x1, float_t eps = 1e-6) { int count = 0; float_t a = x0; float_t b = float_t(0.5) * (x0 + x1); float_t c = x1; - float_t fa = F::__call(a); - float_t fb = F::__call(b); - float_t fc = F::__call(c); + float_t fa = f.__call(a); + float_t fb = f.__call(b); + float_t fc = f.__call(c); float_t I = (c - a) * (float_t(1.0) / float_t(6.0)) * (fa + float_t(4.0) * fb + fc); - return impl::integrate_helper::__call(a, b, c, fa, fb, fc, I, eps, count); + return impl::integrate_helper::__call(f, a, b, c, fa, fb, fc, I, eps, count); + } +}; + + +namespace impl +{ +template +struct InnerIntegrand +{ + float __call(float_t x) + { + return f.__call(x, y); + } + + F f; + float_t y; +}; + +template +struct OuterIntegrand +{ + float __call(float_t y) + { + using func_t = InnerIntegrand; + func_t innerFunc; + innerFunc.f = f; + innerFunc.y = y; + return AdaptiveSimpson::__call(innerFunc, x0, x1, eps); + } + + F f; + float_t x0; + float_t x1; + float_t eps; +}; +} + +template // F has function __call(x) +struct AdaptiveSimpson2D +{ + static float_t __call(NBL_REF_ARG(F) f, float32_t2 x0, float32_t2 x1, float_t eps = 1e-6) + { + using func_t = impl::OuterIntegrand; + func_t outerFunc; + outerFunc.f = f; + outerFunc.x0 = x0.x; + outerFunc.x1 = x1.x; + outerFunc.eps = eps; + return AdaptiveSimpson::__call(outerFunc, x0.y, x1.y, eps); } }; From 2f33aa03cbcdfaf20df6f26c6b6ffac39fb20dfd Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 6 Jan 2026 16:26:43 +0700 Subject: [PATCH 13/37] some fixes to quaternions --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 91ee4975e3..be3b7b8ede 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -184,21 +184,21 @@ struct quaternion return retval; } - this_t operator*(scalar_type scalar) + 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) + this_t operator*(NBL_CONST_REF_ARG(this_t) other) NBL_CONST_MEMBER_FUNC { this_t retval; retval.data = data_type( - data.w * other.data.w - data.x * other.x - data.y * other.data.y - data.z * other.data.z, - data.w * other.data.x + data.x * other.w + data.y * other.data.z - data.z * other.data.y, - data.w * other.data.y - data.x * other.z + data.y * other.data.w + data.z * other.data.x, - data.w * other.data.z + data.x * other.y - data.y * other.data.x + data.z * other.data.w + 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; } @@ -270,7 +270,7 @@ struct quaternion 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;// hlsl::transpose(mat); // TODO: double check transpose? + return mat; } static vector3_type slerp_delta(const vector3_type start, const vector3_type preScaledWaypoint, scalar_type cosAngleFromStart) @@ -335,7 +335,7 @@ struct static_cast_helper, math::truncated_quaternion > { math::quaternion retval; retval.data.xyz = q.data; - retval.data.w = hlsl::sqrt(scalar_type(1.0) - hlsl::dot(q.data, q.data)); + retval.data.w = hlsl::sqrt(T(1.0) - hlsl::dot(q.data, q.data)); return retval; } }; From a22d46ae9506112f5ba5830cb81a9b7dbe9b3f81 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 7 Jan 2026 12:08:16 +0700 Subject: [PATCH 14/37] implement quaternion slerp (might need optimizing?) --- .../nbl/builtin/hlsl/math/quaternions.hlsl | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index be3b7b8ede..b54e1ad619 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -206,10 +206,10 @@ struct quaternion static this_t unnormLerp(const this_t start, const this_t end, const scalar_type fraction, const scalar_type totalPseudoAngle) { // TODO: benchmark uint sign flip vs just *sign(totalPseudoAngle) - const data_type adjEnd = ieee754::flipSignIfRHSNegative(end.data, totalPseudoAngle); + const data_type adjEnd = ieee754::flipSignIfRHSNegative(end.data, hlsl::promote(totalPseudoAngle)); this_t retval; - retval.data = hlsl::mix(start.data, adjEnd, fraction); + retval.data = hlsl::mix(start.data, adjEnd, hlsl::promote(fraction)); return retval; } @@ -287,10 +287,33 @@ 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 + { + this_t retval; + + const scalar_type A = hlsl::acos(cosA); + const scalar_type sinARcp = scalar_type(1.0) / hlsl::sqrt(scalar_type(1.0) - cosA * cosA); + const scalar_type sinAt = hlsl::sin(fraction * A); + const data_type adjEnd = ieee754::flipSignIfRHSNegative(end.data, hlsl::promote(totalPseudoAngle)); + retval.data = (hlsl::sin((scalar_type(1.0) - fraction) * A) * start.data + sinAt * adjEnd) * sinARcp; + + return retval; + } + else + return unnormLerp(start, end, fraction, totalPseudoAngle); + // return hlsl::normalize(unnormLerp(start, end, fraction, totalPseudoAngle)); + } + this_t inverse() NBL_CONST_MEMBER_FUNC { this_t retval; - retval.data.xyz = -retval.data.xyz; + retval.data.xyz = -data.xyz; retval.data.w = data.w; return retval; } From f71cca19d9d18f99cb4265c6d183999cd618c568 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 7 Jan 2026 13:56:40 +0700 Subject: [PATCH 15/37] minor optimization to slerp --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index b54e1ad619..b7f39f19fe 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -296,18 +296,17 @@ struct quaternion if (cosA <= (scalar_type(1.0) - threshold)) // spherical interpolation { this_t retval; - - const scalar_type A = hlsl::acos(cosA); const scalar_type sinARcp = scalar_type(1.0) / hlsl::sqrt(scalar_type(1.0) - cosA * cosA); - const scalar_type sinAt = hlsl::sin(fraction * A); + 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, hlsl::promote(totalPseudoAngle)); - retval.data = (hlsl::sin((scalar_type(1.0) - fraction) * A) * start.data + sinAt * adjEnd) * sinARcp; + retval.data = scale * start.data + sinAt_over_sinA * adjEnd; return retval; } else return unnormLerp(start, end, fraction, totalPseudoAngle); - // return hlsl::normalize(unnormLerp(start, end, fraction, totalPseudoAngle)); } this_t inverse() NBL_CONST_MEMBER_FUNC From c39c78a8e7b8d9709ddbc9de602d6dff5573d0da Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 7 Jan 2026 15:26:01 +0700 Subject: [PATCH 16/37] fix create from rotation matrix --- .../nbl/builtin/hlsl/math/quaternions.hlsl | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index b7f39f19fe..1f720b0247 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -140,42 +140,47 @@ struct quaternion 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 = hlsl::promote(1.0) + Qx + Qy + Qz; + // const data_type tmp = hlsl::promote(1.0) + Qx + Qy + Qz; + const data_type tmp = Qx + Qy + Qz; // TODO: speed this up this_t retval; if (tmp.x > scalar_type(0.0)) { - const scalar_type invscales = scalar_type(0.5) / hlsl::sqrt(tmp.x); + 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[2][1] - m[1][2]) * invscales; retval.data.y = (m[0][2] - m[2][0]) * invscales; retval.data.z = (m[1][0] - m[0][1]) * invscales; - retval.data.w = tmp.x * invscales * scalar_type(0.5); + retval.data.w = scales * scalar_type(0.5); } else { if (tmp.y > scalar_type(0.0)) { - const scalar_type invscales = scalar_type(0.5) / hlsl::sqrt(tmp.y); - retval.data.x = tmp.y * invscales * scalar_type(0.5); + 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[0][1] + m[1][0]) * invscales; retval.data.z = (m[2][0] + m[0][2]) * invscales; retval.data.w = (m[2][1] - m[1][2]) * invscales; } else if (tmp.z > scalar_type(0.0)) { - const scalar_type invscales = scalar_type(0.5) / hlsl::sqrt(tmp.z); + 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[0][1] + m[1][0]) * invscales; - retval.data.y = tmp.z * invscales * scalar_type(0.5); - retval.data.z = (m[0][2] - m[2][0]) * invscales; - retval.data.w = (m[1][2] + m[2][1]) * invscales; + retval.data.y = scales * scalar_type(0.5); + retval.data.z = (m[1][2] + m[2][1]) * invscales; + retval.data.w = (m[0][2] - m[2][0]) * invscales; } else { - const scalar_type invscales = scalar_type(0.5) / hlsl::sqrt(tmp.w); + 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[0][2] + m[2][0]) * invscales; retval.data.y = (m[1][2] + m[2][1]) * invscales; - retval.data.z = tmp.w * invscales * scalar_type(0.5); + retval.data.z = scales * scalar_type(0.5); retval.data.w = (m[1][0] - m[0][1]) * invscales; } } From 0b180c88b65d37acf0ccc0817d5d5d97cd6fdf74 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 7 Jan 2026 16:20:40 +0700 Subject: [PATCH 17/37] force constructor type with requires to avoid dxc implicit conversions --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 1f720b0247..4be73482bb 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -51,12 +51,13 @@ struct quaternion // angle: Rotation angle expressed in radians. // axis: Rotation axis, must be normalized. - static this_t create(const vector3_type axis, scalar_type angle) + template && is_same_v) + static this_t create(const U axis, const F angle, const F uniformScale = scalar_type(1.0)) { this_t q; const scalar_type sinTheta = hlsl::sin(angle * 0.5); const scalar_type cosTheta = hlsl::cos(angle * 0.5); - q.data = data_type(axis * sinTheta, cosTheta); + q.data = data_type(axis * sinTheta, cosTheta) * uniformScale; return q; } @@ -301,7 +302,7 @@ struct quaternion if (cosA <= (scalar_type(1.0) - threshold)) // spherical interpolation { this_t retval; - const scalar_type sinARcp = scalar_type(1.0) / hlsl::sqrt(scalar_type(1.0) - cosA * cosA); + 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) From de1b0d1f5aa4cb4e1b3bd73330315f776de1c108 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 7 Jan 2026 17:13:56 +0700 Subject: [PATCH 18/37] fixes to transformVector and other minor fixes --- .../nbl/builtin/hlsl/math/quaternions.hlsl | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 4be73482bb..34abb042fb 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -134,9 +134,9 @@ struct quaternion } const scalar_type m00 = m[0][0], m11 = m[1][1], m22 = m[2][2]; - const scalar_type neg_m00 = bit_cast(bit_cast(m00)^0x80000000u); - const scalar_type neg_m11 = bit_cast(bit_cast(m11)^0x80000000u); - const scalar_type neg_m22 = bit_cast(bit_cast(m22)^0x80000000u); + 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); @@ -186,7 +186,7 @@ struct quaternion } } - retval.data = hlsl::normalize(retval.data); + retval.data = hlsl::normalize(retval.data) / hlsl::sqrt(hlsl::dot(m[0], m[0])); // restore uniform scale return retval; } @@ -211,6 +211,8 @@ struct quaternion static this_t unnormLerp(const this_t start, const this_t end, const scalar_type fraction, const scalar_type totalPseudoAngle) { + assert(hlsl::length(start.data) == scalar_type(1.0)); + assert(hlsl::length(end.data) == scalar_type(1.0)); // TODO: benchmark uint sign flip vs just *sign(totalPseudoAngle) const data_type adjEnd = ieee754::flipSignIfRHSNegative(end.data, hlsl::promote(totalPseudoAngle)); @@ -241,6 +243,9 @@ struct quaternion static this_t unnormFlerp(const this_t start, const this_t end, const scalar_type fraction) { + assert(hlsl::length(start.data) == scalar_type(1.0)); + assert(hlsl::length(end.data) == scalar_type(1.0)); + 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)); @@ -259,9 +264,10 @@ struct quaternion vector3_type transformVector(const vector3_type v, const bool assumeNoScale=false) NBL_CONST_MEMBER_FUNC { - scalar_type scale = hlsl::mix(hlsl::length(data), scalar_type(1.0), assumeNoScale); - vector3_type direction = data.xyz; - return v * scale + hlsl::cross(direction, v * data.w + hlsl::cross(direction, v)) * scalar_type(2.0); + const scalar_type scaleRcp = scalar_type(1.0) / hlsl::sqrt(hlsl::dot(data, data)); + const vector3_type modV = v * scalar_type(2.0) * scaleRcp; + const vector3_type direction = data.xyz; + return v / scaleRcp + hlsl::cross(direction, modV * data.w + hlsl::cross(direction, modV)); } matrix_type constructMatrix() NBL_CONST_MEMBER_FUNC @@ -336,8 +342,10 @@ struct normalize_helper > { static inline math::truncated_quaternion __call(const math::truncated_quaternion q) { + assert(hlsl::length(q.data) == scalar_type(1.0)); + math::truncated_quaternion retval; - retval.data = hlsl::normalize(q.data); + retval.data = q.data; // should be normalized by definition (dropped component should be 1.0) return retval; } }; From 96ef95d82251abfcf85f194afa43b2e46982b87a Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 8 Jan 2026 14:09:22 +0700 Subject: [PATCH 19/37] added matrix runtime traits for checking orthogonality, uniform scale --- .../math/linalg/matrix_runtime_traits.hlsl | 66 +++++++++++++++++++ .../nbl/builtin/hlsl/math/quaternions.hlsl | 24 +------ src/nbl/builtin/CMakeLists.txt | 1 + 3 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl 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..fc19b2cb3e --- /dev/null +++ b/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl @@ -0,0 +1,66 @@ +// 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 = testing::relativeApproxCompare(hlsl::dot(m[i], m[(i+1)%N]), scalar_t(0.0), 1e-4) && orthogonal; + retval.orthogonal = orthogonal; + } + { + const matrix_t m_T = hlsl::transpose(m); + scalar_t dots[N]; + NBL_UNROLL for (uint16_t i = 0; i < N; i++) + dots[i] = hlsl::dot(m[i], m[i]); + + bool uniformScale = true; + NBL_UNROLL for (uint16_t i = 0; i < N-1; i++) + uniformScale = testing::relativeApproxCompare(dots[i], dots[i+1], 1e-4) && uniformScale; + + retval.uniformScale = uniformScale; + retval.orthonormal = uniformScale && retval.orthogonal && testing::relativeApproxCompare(dots[0], scalar_t(1.0), 1e-5); + } + return retval; + } + + bool invertible; + bool orthogonal; + bool uniformScale; + bool orthonormal; +}; + +} +} +} +} + +#endif diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 34abb042fb..59f2eea243 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -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 { @@ -96,31 +97,12 @@ struct quaternion ); } - static bool __isEqual(const scalar_type a, const scalar_type b) - { - return hlsl::max(a/b, b/a) <= scalar_type(1e-4); - } - static bool __dotIsZero(const vector3_type a, const vector3_type b) - { - const scalar_type ab = hlsl::dot(a, b); - return hlsl::abs(ab) <= scalar_type(1e-4); - } - static this_t create(NBL_CONST_REF_ARG(matrix_type) m, const bool dontAssertValidMatrix=false) { { // only orthogonal and uniform scale mats can be converted - bool valid = __dotIsZero(m[0], m[1]); - valid = __dotIsZero(m[1], m[2]) && valid; - valid = __dotIsZero(m[0], m[2]) && valid; - - const matrix_type m_T = hlsl::transpose(m); - const scalar_type dotCol0 = hlsl::dot(m_T[0],m_T[0]); - const scalar_type dotCol1 = hlsl::dot(m_T[1],m_T[1]); - const scalar_type dotCol2 = hlsl::dot(m_T[2],m_T[2]); - valid = __isEqual(dotCol0, dotCol1) && valid; - valid = __isEqual(dotCol1, dotCol2) && valid; - valid = __isEqual(dotCol0, dotCol2) && valid; + linalg::RuntimeTraits traits = linalg::RuntimeTraits::create(m); + bool valid = traits.orthogonal && traits.uniformScale; if (dontAssertValidMatrix) if (!valid) diff --git a/src/nbl/builtin/CMakeLists.txt b/src/nbl/builtin/CMakeLists.txt index 085ed3c923..038ac2573d 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") From a0acd3512dbf594ea31077d1f9a4b5786b89e08f Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 13 Jan 2026 14:00:40 +0700 Subject: [PATCH 20/37] matrix runtime traits stores uniform scale squared, changed calculations slightly --- .../math/linalg/matrix_runtime_traits.hlsl | 22 ++++++++++++------- .../nbl/builtin/hlsl/math/quaternions.hlsl | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl b/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl index fc19b2cb3e..43b05d56ba 100644 --- a/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl +++ b/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl @@ -33,28 +33,34 @@ struct RuntimeTraits { bool orthogonal = true; NBL_UNROLL for (uint16_t i = 0; i < N; i++) - orthogonal = testing::relativeApproxCompare(hlsl::dot(m[i], m[(i+1)%N]), scalar_t(0.0), 1e-4) && orthogonal; + 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 dots[N]; NBL_UNROLL for (uint16_t i = 0; i < N; i++) - dots[i] = hlsl::dot(m[i], m[i]); + dots[i] = hlsl::dot(m[i], m_T[i]); - bool uniformScale = true; - NBL_UNROLL for (uint16_t i = 0; i < N-1; i++) - uniformScale = testing::relativeApproxCompare(dots[i], dots[i+1], 1e-4) && uniformScale; + scalar_t uniformScaleSq = hlsl::dot(m[0], m_T[0]); + NBL_UNROLL for (uint16_t i = 1; i < N; i++) + { + if (!testing::relativeApproxCompare(hlsl::dot(m[i], m_T[i]), uniformScaleSq, 1e-4)) + { + uniformScaleSq = bit_cast(numeric_limits::quiet_NaN); + break; + } + } - retval.uniformScale = uniformScale; - retval.orthonormal = uniformScale && retval.orthogonal && testing::relativeApproxCompare(dots[0], scalar_t(1.0), 1e-5); + retval.uniformScaleSq = uniformScaleSq; + retval.orthonormal = retval.orthogonal && testing::relativeApproxCompare(uniformScaleSq, scalar_t(1.0), 1e-5); } return retval; } bool invertible; bool orthogonal; - bool uniformScale; + scalar_t uniformScaleSq; bool orthonormal; }; diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 59f2eea243..966463b5e4 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -102,7 +102,7 @@ struct quaternion { // only orthogonal and uniform scale mats can be converted linalg::RuntimeTraits traits = linalg::RuntimeTraits::create(m); - bool valid = traits.orthogonal && traits.uniformScale; + bool valid = traits.orthogonal && !hlsl::isnan(traits.uniformScaleSq); if (dontAssertValidMatrix) if (!valid) From d1c4a89881934f6123ddfff225e452acc8c312dc Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 13 Jan 2026 14:51:54 +0700 Subject: [PATCH 21/37] added more static_casts and new partial spec for flipIfRHSNegative --- include/nbl/builtin/hlsl/ieee754.hlsl | 36 ++++++++++++--- .../nbl/builtin/hlsl/math/quaternions.hlsl | 45 ++++++++++++------- 2 files changed, 58 insertions(+), 23 deletions(-) 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/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 966463b5e4..2133490f2d 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -52,16 +52,19 @@ struct quaternion // angle: Rotation angle expressed in radians. // axis: Rotation axis, must be normalized. - template && is_same_v) - static this_t create(const U axis, const F angle, const F uniformScale = scalar_type(1.0)) + template && is_same_v::scalar_type,F>) + static this_t create(const U axis, const F angle, const F uniformScale = F(1.0)) { + using scalar_t = typename vector_traits::scalar_type; this_t q; - const scalar_type sinTheta = hlsl::sin(angle * 0.5); - const scalar_type cosTheta = hlsl::cos(angle * 0.5); + 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 template NBL_FUNC_REQUIRES(is_same_v,U>) static this_t create(const U halfPitchCosSin, const U halfYawCosSin, const U halfRollCosSin) { @@ -99,10 +102,12 @@ struct quaternion 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) @@ -168,7 +173,7 @@ struct quaternion } } - retval.data = hlsl::normalize(retval.data) / hlsl::sqrt(hlsl::dot(m[0], m[0])); // restore uniform scale + retval.data = hlsl::normalize(retval.data) * hlsl::rsqrt(uniformScaleSq); // restore uniform scale return retval; } @@ -193,10 +198,9 @@ struct quaternion static this_t unnormLerp(const this_t start, const this_t end, const scalar_type fraction, const scalar_type totalPseudoAngle) { - assert(hlsl::length(start.data) == scalar_type(1.0)); - assert(hlsl::length(end.data) == scalar_type(1.0)); - // TODO: benchmark uint sign flip vs just *sign(totalPseudoAngle) - const data_type adjEnd = ieee754::flipSignIfRHSNegative(end.data, hlsl::promote(totalPseudoAngle)); + 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, hlsl::promote(fraction)); @@ -225,8 +229,8 @@ struct quaternion static this_t unnormFlerp(const this_t start, const this_t end, const scalar_type fraction) { - assert(hlsl::length(start.data) == scalar_type(1.0)); - assert(hlsl::length(end.data) == scalar_type(1.0)); + 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); @@ -252,7 +256,7 @@ struct quaternion return v / scaleRcp + hlsl::cross(direction, modV * data.w + hlsl::cross(direction, modV)); } - matrix_type constructMatrix() NBL_CONST_MEMBER_FUNC + 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); @@ -294,7 +298,7 @@ struct quaternion 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, hlsl::promote(totalPseudoAngle)); + const data_type adjEnd = ieee754::flipSignIfRHSNegative(end.data, totalPseudoAngle); retval.data = scale * start.data + sinAt_over_sinA * adjEnd; return retval; @@ -324,8 +328,7 @@ struct normalize_helper > { static inline math::truncated_quaternion __call(const math::truncated_quaternion q) { - assert(hlsl::length(q.data) == scalar_type(1.0)); - + assert(testing::relativeApproxCompare(hlsl::length(q.data), scalar_type(1.0), scalar_type(1e-4))); math::truncated_quaternion retval; retval.data = q.data; // should be normalized by definition (dropped component should be 1.0) return retval; @@ -363,6 +366,7 @@ struct static_cast_helper, math::quaternion > { static inline math::truncated_quaternion cast(const math::quaternion q) { + assert(testing::relativeApproxCompare(hlsl::length(q.data), scalar_type(1.0), scalar_type(1e-4))); math::truncated_quaternion t; t.data.x = t.data.x; t.data.y = t.data.y; @@ -376,7 +380,16 @@ struct static_cast_helper, math::quaternion > { static inline matrix cast(const math::quaternion q) { - return q.constructMatrix(); + return q.__constructMatrix(); + } +}; + +template +struct static_cast_helper, matrix > +{ + static inline math::quaternion cast(const matrix m) + { + return math::quaternion::create(m, true); } }; } From e8a6488d5dc36e6cd578416669e1c7c37fd08393 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Tue, 13 Jan 2026 15:08:17 +0700 Subject: [PATCH 22/37] account for no scale in transform vector --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 2133490f2d..7e10a5c710 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -250,10 +250,17 @@ struct quaternion vector3_type transformVector(const vector3_type v, const bool assumeNoScale=false) NBL_CONST_MEMBER_FUNC { - const scalar_type scaleRcp = scalar_type(1.0) / hlsl::sqrt(hlsl::dot(data, data)); - const vector3_type modV = v * scalar_type(2.0) * scaleRcp; + 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 v / scaleRcp + hlsl::cross(direction, modV * data.w + hlsl::cross(direction, modV)); + return retV + hlsl::cross(direction, modV * data.w + hlsl::cross(direction, modV)); } matrix_type __constructMatrix() NBL_CONST_MEMBER_FUNC @@ -293,6 +300,9 @@ struct quaternion 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)); From c07365fbe5097dfe40cb5480fdf7209c7aa045bf Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 14 Jan 2026 10:54:19 +0700 Subject: [PATCH 23/37] more comment info for pitch yaw roll, removed normalize truncated quat --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 7e10a5c710..9efe359298 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -52,8 +52,8 @@ struct quaternion // angle: Rotation angle expressed in radians. // axis: Rotation axis, must be normalized. - template && is_same_v::scalar_type,F>) - static this_t create(const U axis, const F angle, const F uniformScale = F(1.0)) + 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; @@ -64,7 +64,7 @@ struct quaternion return q; } - // applies rotation equivalent to 3x3 matrix in order of pitch * yaw * roll + // 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) { @@ -333,18 +333,6 @@ struct quaternion namespace cpp_compat_intrinsics_impl { -template -struct normalize_helper > -{ - static inline math::truncated_quaternion __call(const math::truncated_quaternion q) - { - assert(testing::relativeApproxCompare(hlsl::length(q.data), scalar_type(1.0), scalar_type(1e-4))); - math::truncated_quaternion retval; - retval.data = q.data; // should be normalized by definition (dropped component should be 1.0) - return retval; - } -}; - template struct normalize_helper > { From 2aa275e6a811aa01961bac2eb5c72374ed652d7c Mon Sep 17 00:00:00 2001 From: keptsecret Date: Wed, 14 Jan 2026 12:35:55 +0700 Subject: [PATCH 24/37] create from matrix restore scale correctly --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 9efe359298..b001052810 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -173,7 +173,7 @@ struct quaternion } } - retval.data = hlsl::normalize(retval.data) * hlsl::rsqrt(uniformScaleSq); // restore uniform scale + retval.data = hlsl::normalize(retval.data) * hlsl::sqrt(uniformScaleSq); // restore uniform scale return retval; } From 3869cb105e554dfb7b036094941f96d3f583879d Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 15 Jan 2026 11:31:51 +0700 Subject: [PATCH 25/37] minor bug fixes to quaternions --- .../builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl | 8 ++------ include/nbl/builtin/hlsl/math/quaternions.hlsl | 9 ++++----- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl b/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl index 43b05d56ba..dc74c45ddd 100644 --- a/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl +++ b/include/nbl/builtin/hlsl/math/linalg/matrix_runtime_traits.hlsl @@ -38,14 +38,10 @@ struct RuntimeTraits } { const matrix_t m_T = hlsl::transpose(m); - scalar_t dots[N]; - NBL_UNROLL for (uint16_t i = 0; i < N; i++) - dots[i] = hlsl::dot(m[i], m_T[i]); - - scalar_t uniformScaleSq = hlsl::dot(m[0], m_T[0]); + 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[i], m_T[i]), uniformScaleSq, 1e-4)) + if (!testing::relativeApproxCompare(hlsl::dot(m_T[i], m_T[i]), uniformScaleSq, 1e-4)) { uniformScaleSq = bit_cast(numeric_limits::quiet_NaN); break; diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index b001052810..31fb97a51a 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -128,7 +128,6 @@ struct quaternion 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 = hlsl::promote(1.0) + Qx + Qy + Qz; const data_type tmp = Qx + Qy + Qz; // TODO: speed this up @@ -364,11 +363,11 @@ struct static_cast_helper, math::quaternion > { static inline math::truncated_quaternion cast(const math::quaternion q) { - assert(testing::relativeApproxCompare(hlsl::length(q.data), scalar_type(1.0), scalar_type(1e-4))); + assert(testing::relativeApproxCompare(hlsl::length(q.data), T(1.0), T(1e-4))); math::truncated_quaternion t; - t.data.x = t.data.x; - t.data.y = t.data.y; - t.data.z = t.data.z; + t.data.x = q.data.x; + t.data.y = q.data.y; + t.data.z = q.data.z; return t; } }; From a602fba54c90d1473c5d2267a54e1a25d03e5ae6 Mon Sep 17 00:00:00 2001 From: devsh Date: Thu, 15 Jan 2026 08:06:02 +0100 Subject: [PATCH 26/37] add some operators to hlsl::matrix in C++ --- include/nbl/builtin/hlsl/cpp_compat/matrix.hlsl | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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) From 4aa236838791995f0dc309ca3b1f27e3c44cf968 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 15 Jan 2026 14:35:09 +0700 Subject: [PATCH 27/37] factor out uniform scale from mat before convert --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 31fb97a51a..00200d903a 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -100,12 +100,12 @@ struct quaternion ); } - static this_t create(NBL_CONST_REF_ARG(matrix_type) m, const bool dontAssertValidMatrix=false) + 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); + linalg::RuntimeTraits traits = linalg::RuntimeTraits::create(_m); bool valid = traits.orthogonal && !hlsl::isnan(traits.uniformScaleSq); uniformScaleSq = traits.uniformScaleSq; @@ -120,6 +120,10 @@ struct quaternion assert(valid); } + 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; @@ -172,7 +176,7 @@ struct quaternion } } - retval.data = hlsl::normalize(retval.data) * hlsl::sqrt(uniformScaleSq); // restore uniform scale + retval.data = hlsl::normalize(retval.data) * uniformScale; // restore uniform scale return retval; } From 5f02325d67e768e7f724b19fe9e0ec0a2ceaf312 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 15 Jan 2026 17:25:56 +0700 Subject: [PATCH 28/37] new vector comparison by orientation --- .../hlsl/testing/orientation_compare.hlsl | 44 +++++++++++++++++++ src/nbl/builtin/CMakeLists.txt | 1 + 2 files changed, 45 insertions(+) create mode 100644 include/nbl/builtin/hlsl/testing/orientation_compare.hlsl 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..7884cf1b21 --- /dev/null +++ b/include/nbl/builtin/hlsl/testing/orientation_compare.hlsl @@ -0,0 +1,44 @@ +#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::dot(lhs, rhs); + if (dotLR < scalar_t(0.0)) + return false; + + const scalar_t scale = hlsl::sqrt(hlsl::dot(lhs,lhs) * hlsl::dot(rhs,rhs)); + 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/src/nbl/builtin/CMakeLists.txt b/src/nbl/builtin/CMakeLists.txt index e44f41b29e..86a0ddf9b9 100644 --- a/src/nbl/builtin/CMakeLists.txt +++ b/src/nbl/builtin/CMakeLists.txt @@ -377,5 +377,6 @@ 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") 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") From 11f7f2eb72fa4286b9a6cab5fa696b83429720a1 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Thu, 15 Jan 2026 18:14:44 +0700 Subject: [PATCH 29/37] return nan quaternion if uniform scale is 0 --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 00200d903a..ed0f796fe8 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -119,6 +119,12 @@ struct quaternion 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; From 266cd710e7fae965def0f6c79a3488a28db8ba53 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 16 Jan 2026 10:25:08 +0700 Subject: [PATCH 30/37] account for negative orientation, added check for 0 length vectors --- include/nbl/builtin/hlsl/testing/orientation_compare.hlsl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/nbl/builtin/hlsl/testing/orientation_compare.hlsl b/include/nbl/builtin/hlsl/testing/orientation_compare.hlsl index 7884cf1b21..3228872b4d 100644 --- a/include/nbl/builtin/hlsl/testing/orientation_compare.hlsl +++ b/include/nbl/builtin/hlsl/testing/orientation_compare.hlsl @@ -20,11 +20,13 @@ struct OrientationCompareHelper using traits = nbl::hlsl::vector_traits; using scalar_t = typename traits::scalar_type; - const scalar_t dotLR = hlsl::dot(lhs, rhs); - if (dotLR < scalar_t(0.0)) + 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(hlsl::dot(lhs,lhs) * hlsl::dot(rhs,rhs)); + const scalar_t scale = hlsl::sqrt(dotLL * dotRR); return relativeApproxCompare(dotLR, scale, maxAllowedDifference); } }; From 61f9ca3471aa2b6acfd0747a669d1cfa5274cef6 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 16 Jan 2026 11:40:03 +0700 Subject: [PATCH 31/37] added concept requires to adaptive simpson function, changed func sig --- .../math/quadrature/adaptive_simpson.hlsl | 59 +++++++++++++++---- 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl index 61cad6ae7f..6952775f82 100644 --- a/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl +++ b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl @@ -5,6 +5,7 @@ #define _NBL_BUILTIN_HLSL_MATH_QUADRATURE_ADAPTIVE_SIMPSON_INCLUDED_ #include +#include namespace nbl { @@ -24,8 +25,8 @@ struct integrate_helper { float_t d = float_t(0.5) * (a + b); float_t e = float_t(0.5) * (b + c); - float_t fd = f.__call(d); - float_t fe = f.__call(e); + float_t fd = f(d); + float_t fe = f(e); float_t h = c - a; float_t I0 = (float_t(1.0) / float_t(12.0)) * h * (fa + float_t(4.0) * fd + fb); @@ -48,8 +49,8 @@ struct integrate_helper { float_t d = float_t(0.5) * (a + b); float_t e = float_t(0.5) * (b + c); - float_t fd = f.__call(d); - float_t fe = f.__call(e); + float_t fd = f(d); + float_t fe = f(e); float_t h = c - a; float_t I0 = (float_t(1.0) / float_t(12.0)) * h * (fa + float_t(4.0) * fd + fb); @@ -60,20 +61,37 @@ struct integrate_helper return Ip + (float_t(1.0) / float_t(15.0)) * (Ip - I); } }; + +#define NBL_CONCEPT_NAME FuncOneArg +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename) +#define NBL_CONCEPT_TPLT_PRM_NAMES (F)(T) +#define NBL_CONCEPT_PARAM_0 (func, F) +#define NBL_CONCEPT_PARAM_1 (x, T) +NBL_CONCEPT_BEGIN(2) +#define func NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 +#define x NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 +NBL_CONCEPT_END( + ((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(concepts::FloatingPointScalar, T)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((func(x)), ::nbl::hlsl::is_same_v, T)) +); +#undef x +#undef func +#include } -template // F has function __call(x) +template()(0)), uint32_t Depth=6 NBL_PRIMARY_REQUIRES(impl::FuncOneArg) struct AdaptiveSimpson { + // eps: absolute tolerance on the integral estimate static float_t __call(NBL_REF_ARG(F) f, float_t x0, float_t x1, float_t eps = 1e-6) { int count = 0; float_t a = x0; float_t b = float_t(0.5) * (x0 + x1); float_t c = x1; - float_t fa = f.__call(a); - float_t fb = f.__call(b); - float_t fc = f.__call(c); + float_t fa = f(a); + float_t fb = f(b); + float_t fc = f(c); float_t I = (c - a) * (float_t(1.0) / float_t(6.0)) * (fa + float_t(4.0) * fb + fc); return impl::integrate_helper::__call(f, a, b, c, fa, fb, fc, I, eps, count); } @@ -85,9 +103,9 @@ namespace impl template struct InnerIntegrand { - float __call(float_t x) + float_t operator()(float_t x) { - return f.__call(x, y); + return f(x, y); } F f; @@ -97,7 +115,7 @@ struct InnerIntegrand template struct OuterIntegrand { - float __call(float_t y) + float_t operator()(float_t y) { using func_t = InnerIntegrand; func_t innerFunc; @@ -111,11 +129,28 @@ struct OuterIntegrand float_t x1; float_t eps; }; + +#define NBL_CONCEPT_NAME FuncTwoArgs +#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename) +#define NBL_CONCEPT_TPLT_PRM_NAMES (F)(T) +#define NBL_CONCEPT_PARAM_0 (func, F) +#define NBL_CONCEPT_PARAM_1 (x, T) +NBL_CONCEPT_BEGIN(2) +#define func NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 +#define x NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 +NBL_CONCEPT_END( + ((NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT)(concepts::FloatingPointScalar, T)) + ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((func(x,x)), ::nbl::hlsl::is_same_v, T)) +); +#undef x +#undef func +#include } -template // F has function __call(x) +template()(0)), uint32_t Depth=6 NBL_PRIMARY_REQUIRES(impl::FuncTwoArgs) struct AdaptiveSimpson2D { + // eps: absolute tolerance on the integral estimate static float_t __call(NBL_REF_ARG(F) f, float32_t2 x0, float32_t2 x1, float_t eps = 1e-6) { using func_t = impl::OuterIntegrand; From 762b826e21cd9261e280ffe8a3957c8a7dbb8be9 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 16 Jan 2026 13:33:51 +0700 Subject: [PATCH 32/37] minor fixes to turbo vis struct --- include/nbl/builtin/hlsl/visualization/turbo.hlsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nbl/builtin/hlsl/visualization/turbo.hlsl b/include/nbl/builtin/hlsl/visualization/turbo.hlsl index c12323ff4f..d8ab2a8df6 100644 --- a/include/nbl/builtin/hlsl/visualization/turbo.hlsl +++ b/include/nbl/builtin/hlsl/visualization/turbo.hlsl @@ -18,7 +18,7 @@ struct Turbo { static const float32_t3 RGB_LUT[256]; - static float32_t3 map(float x) + static float32_t3 __call(float x) { x = hlsl::clamp(x, 0.f, 1.f); int i = int(x * 255.f); @@ -28,7 +28,7 @@ struct Turbo } }; -inline const float32_t3 Turbo::RGB_LUT[256] = { +NBL_CONSTEXPR_INLINE_OOL_MEMBER float32_t3 Turbo::RGB_LUT[256] = { float32_t3(0.18995,0.07176,0.23217), float32_t3(0.19483,0.08339,0.26149), float32_t3(0.19956,0.09498,0.29024), From 25998568abc0cf4c2e9894661842b3b646d14dda Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 16 Jan 2026 13:50:07 +0700 Subject: [PATCH 33/37] made ndf and bxdf methods const --- .../hlsl/bxdf/base/cook_torrance_base.hlsl | 22 ++++++------ .../builtin/hlsl/bxdf/base/lambertian.hlsl | 20 +++++------ .../builtin/hlsl/bxdf/base/oren_nayar.hlsl | 26 +++++++------- include/nbl/builtin/hlsl/bxdf/fresnel.hlsl | 8 ----- .../nbl/builtin/hlsl/bxdf/ndf/beckmann.hlsl | 30 ++++++++-------- include/nbl/builtin/hlsl/bxdf/ndf/ggx.hlsl | 34 +++++++++---------- .../bxdf/reflection/delta_distribution.hlsl | 16 ++++----- .../bxdf/transmission/delta_distribution.hlsl | 16 ++++----- .../bxdf/transmission/smooth_dielectric.hlsl | 34 +++++++++---------- 9 files changed, 99 insertions(+), 107 deletions(-) diff --git a/include/nbl/builtin/hlsl/bxdf/base/cook_torrance_base.hlsl b/include/nbl/builtin/hlsl/bxdf/base/cook_torrance_base.hlsl index d70e8823da..924c36c7e9 100644 --- a/include/nbl/builtin/hlsl/bxdf/base/cook_torrance_base.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/base/cook_torrance_base.hlsl @@ -50,7 +50,7 @@ struct quant_query_helper using quant_query_type = typename N::quant_query_type; template - static quant_query_type __call(NBL_REF_ARG(N) ndf, NBL_CONST_REF_ARG(F) fresnel, NBL_CONST_REF_ARG(I) interaction, NBL_CONST_REF_ARG(C) cache) + static quant_query_type __call(NBL_CONST_REF_ARG(N) ndf, NBL_CONST_REF_ARG(F) fresnel, NBL_CONST_REF_ARG(I) interaction, NBL_CONST_REF_ARG(C) cache) { return ndf.template createQuantQuery(interaction, cache, fresnel.getRefractionOrientedEta()); } @@ -62,7 +62,7 @@ struct quant_query_helper using quant_query_type = typename N::quant_query_type; template - static quant_query_type __call(NBL_REF_ARG(N) ndf, NBL_CONST_REF_ARG(F) fresnel, NBL_CONST_REF_ARG(I) interaction, NBL_CONST_REF_ARG(C) cache) + static quant_query_type __call(NBL_CONST_REF_ARG(N) ndf, NBL_CONST_REF_ARG(F) fresnel, NBL_CONST_REF_ARG(I) interaction, NBL_CONST_REF_ARG(C) cache) { typename N::scalar_type dummy; return ndf.template createQuantQuery(interaction, cache, dummy); @@ -146,7 +146,7 @@ struct SCookTorrance return hlsl::mix(reflectance, scalar_type(1.0)-reflectance, transmitted); } - bool __dotIsValue(const vector3_type a, const vector3_type b, const scalar_type value) + bool __dotIsValue(const vector3_type a, const vector3_type b, const scalar_type value) NBL_CONST_MEMBER_FUNC { const scalar_type ab = hlsl::dot(a, b); return hlsl::max(ab, value / ab) <= scalar_type(value + 1e-3); @@ -156,7 +156,7 @@ struct SCookTorrance template, class MicrofacetCache=conditional_t NBL_FUNC_REQUIRES(RequiredInteraction && RequiredMicrofacetCache) - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { fresnel_type _f = __getOrientedFresnel(fresnel, interaction.getNdotV()); if (!__checkValid(_f, _sample, interaction, cache)) @@ -197,7 +197,7 @@ struct SCookTorrance sample_type __generate_common(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type localH, const scalar_type NdotV, const scalar_type VdotH, const scalar_type LdotH, bool transmitted, NBL_CONST_REF_ARG(fresnel::OrientedEtaRcps) rcpEta, - NBL_REF_ARG(bool) valid) + NBL_REF_ARG(bool) valid) NBL_CONST_MEMBER_FUNC { // fail if samples have invalid paths const scalar_type NdotL = hlsl::mix(scalar_type(2.0) * VdotH * localH.z - NdotV, @@ -244,7 +244,7 @@ struct SCookTorrance return sample_type::create(L, T, B, NdotL); } template NBL_FUNC_REQUIRES(C::value && !IsBSDF) - sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u, NBL_REF_ARG(anisocache_type) cache) + sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u, NBL_REF_ARG(anisocache_type) cache) NBL_CONST_MEMBER_FUNC { const scalar_type NdotV = interaction.getNdotV(); if (NdotV < numeric_limits::min) @@ -274,7 +274,7 @@ struct SCookTorrance return s; } template NBL_FUNC_REQUIRES(C::value && IsBSDF) - sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u, NBL_REF_ARG(anisocache_type) cache) + sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u, NBL_REF_ARG(anisocache_type) cache) NBL_CONST_MEMBER_FUNC { const vector3_type localV = interaction.getTangentSpaceV(); const scalar_type NdotV = localV.z; @@ -322,7 +322,7 @@ struct SCookTorrance return s; } template NBL_FUNC_REQUIRES(C::value && !IsAnisotropic) - sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const conditional_t u, NBL_REF_ARG(isocache_type) cache) + sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const conditional_t u, NBL_REF_ARG(isocache_type) cache) NBL_CONST_MEMBER_FUNC { anisocache_type aniso_cache; sample_type s = generate(anisotropic_interaction_type::create(interaction), u, aniso_cache); @@ -331,7 +331,7 @@ struct SCookTorrance } template - scalar_type __pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) + scalar_type __pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { using quant_query_type = typename ndf_type::quant_query_type; using dg1_query_type = typename ndf_type::dg1_query_type; @@ -356,7 +356,7 @@ struct SCookTorrance template, class MicrofacetCache=conditional_t NBL_FUNC_REQUIRES(RequiredInteraction && RequiredMicrofacetCache) - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { fresnel_type _f = __getOrientedFresnel(fresnel, interaction.getNdotV()); if (!__checkValid(_f, _sample, interaction, cache)) @@ -370,7 +370,7 @@ struct SCookTorrance template, class MicrofacetCache=conditional_t NBL_FUNC_REQUIRES(RequiredInteraction && RequiredMicrofacetCache) - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { if (!_sample.isValid()) return quotient_pdf_type::create(scalar_type(0.0), scalar_type(0.0)); // set pdf=0 when quo=0 because we don't want to give high weight to sampling strategy that yields 0 contribution diff --git a/include/nbl/builtin/hlsl/bxdf/base/lambertian.hlsl b/include/nbl/builtin/hlsl/bxdf/base/lambertian.hlsl index 8500f5c6c5..a107921026 100644 --- a/include/nbl/builtin/hlsl/bxdf/base/lambertian.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/base/lambertian.hlsl @@ -25,24 +25,24 @@ struct SLambertianBase NBL_CONSTEXPR_STATIC_INLINE BxDFClampMode _clamp = conditional_value::value; - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return hlsl::promote(_sample.getNdotL(_clamp) * numbers::inv_pi * hlsl::mix(1.0, 0.5, IsBSDF)); } - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return eval(_sample, interaction.isotropic); } template > - enable_if_t generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u) + enable_if_t generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u) NBL_CONST_MEMBER_FUNC { ray_dir_info_type L; L.setDirection(sampling::ProjectedHemisphere::generate(u)); return sample_type::createFromTangentSpace(L, interaction.getFromTangentSpace()); } template > - enable_if_t generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u) + enable_if_t generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u) NBL_CONST_MEMBER_FUNC { vector3_type _u = u; ray_dir_info_type L; @@ -50,29 +50,29 @@ struct SLambertianBase return sample_type::createFromTangentSpace(L, interaction.getFromTangentSpace()); } template > - enable_if_t generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u) + enable_if_t generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u) NBL_CONST_MEMBER_FUNC { return generate(anisotropic_interaction_type::create(interaction), u); } template > - enable_if_t generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector3_type u) + enable_if_t generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector3_type u) NBL_CONST_MEMBER_FUNC { return generate(anisotropic_interaction_type::create(interaction), u); } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { NBL_IF_CONSTEXPR (IsBSDF) return sampling::ProjectedSphere::pdf(_sample.getNdotL(_clamp)); else return sampling::ProjectedHemisphere::pdf(_sample.getNdotL(_clamp)); } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return pdf(_sample, interaction.isotropic); } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { sampling::quotient_and_pdf qp; NBL_IF_CONSTEXPR (IsBSDF) @@ -81,7 +81,7 @@ struct SLambertianBase qp = sampling::ProjectedHemisphere::template quotient_and_pdf(_sample.getNdotL(_clamp)); return quotient_pdf_type::create(qp.quotient[0], qp.pdf); } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return quotient_and_pdf(_sample, interaction.isotropic); } diff --git a/include/nbl/builtin/hlsl/bxdf/base/oren_nayar.hlsl b/include/nbl/builtin/hlsl/bxdf/base/oren_nayar.hlsl index cdec22e892..d104842608 100644 --- a/include/nbl/builtin/hlsl/bxdf/base/oren_nayar.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/base/oren_nayar.hlsl @@ -45,39 +45,39 @@ struct SOrenNayarBase return retval; } - scalar_type __rec_pi_factored_out_wo_clamps(scalar_type VdotL, scalar_type clampedNdotL, scalar_type clampedNdotV) + scalar_type __rec_pi_factored_out_wo_clamps(scalar_type VdotL, scalar_type clampedNdotL, scalar_type clampedNdotV) NBL_CONST_MEMBER_FUNC { scalar_type C = 1.0 / max(clampedNdotL, clampedNdotV); scalar_type cos_phi_sin_theta = max(VdotL - clampedNdotL * clampedNdotV, 0.0); return (AB.x + AB.y * cos_phi_sin_theta * C); } template - spectral_type __eval(NBL_CONST_REF_ARG(Query) query, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + spectral_type __eval(NBL_CONST_REF_ARG(Query) query, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { scalar_type NdotL = _sample.getNdotL(_clamp); return hlsl::promote(NdotL * numbers::inv_pi * hlsl::mix(1.0, 0.5, IsBSDF) * __rec_pi_factored_out_wo_clamps(query.getVdotL(), NdotL, interaction.getNdotV(_clamp))); } - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { SQuery query; query.VdotL = hlsl::dot(interaction.getV().getDirection(), _sample.getL().getDirection()); return __eval(query, _sample, interaction); } - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return eval(_sample, interaction.isotropic); } template > - enable_if_t generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u) + enable_if_t generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u) NBL_CONST_MEMBER_FUNC { ray_dir_info_type L; L.setDirection(sampling::ProjectedHemisphere::generate(u)); return sample_type::createFromTangentSpace(L, interaction.getFromTangentSpace()); } template > - enable_if_t generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u) + enable_if_t generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u) NBL_CONST_MEMBER_FUNC { vector3_type _u = u; ray_dir_info_type L; @@ -85,42 +85,42 @@ struct SOrenNayarBase return sample_type::createFromTangentSpace(L, interaction.getFromTangentSpace()); } template > - enable_if_t generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u) + enable_if_t generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u) NBL_CONST_MEMBER_FUNC { return generate(anisotropic_interaction_type::create(interaction), u); } template > - enable_if_t generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector3_type u) + enable_if_t generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector3_type u) NBL_CONST_MEMBER_FUNC { return generate(anisotropic_interaction_type::create(interaction), u); } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { if (IsBSDF) return sampling::ProjectedSphere::pdf(_sample.getNdotL(_clamp)); else return sampling::ProjectedHemisphere::pdf(_sample.getNdotL(_clamp)); } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return pdf(_sample, interaction.isotropic); } template - quotient_pdf_type __quotient_and_pdf(NBL_CONST_REF_ARG(Query) query, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + quotient_pdf_type __quotient_and_pdf(NBL_CONST_REF_ARG(Query) query, NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { scalar_type _pdf = pdf(_sample, interaction); scalar_type q = __rec_pi_factored_out_wo_clamps(query.getVdotL(), _sample.getNdotL(_clamp), interaction.getNdotV(_clamp)); return quotient_pdf_type::create(q, _pdf); } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { SQuery query; query.VdotL = hlsl::dot(interaction.getV().getDirection(), _sample.getL().getDirection()); return __quotient_and_pdf(query, _sample, interaction); } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return quotient_and_pdf(_sample, interaction.isotropic); } diff --git a/include/nbl/builtin/hlsl/bxdf/fresnel.hlsl b/include/nbl/builtin/hlsl/bxdf/fresnel.hlsl index f4b83848dc..76ea58de6a 100644 --- a/include/nbl/builtin/hlsl/bxdf/fresnel.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/fresnel.hlsl @@ -695,14 +695,6 @@ struct Iridescent getRefractionOrientedEtaRcps() NBL_CONST_MEMBER_FUNC - // { - // OrientedEtaRcps rcpEta; - // rcpEta.value = hlsl::promote(1.0) / base_type::eta13; - // rcpEta.value2 = rcpEta.value * rcpEta.value; - // return rcpEta; - // } - vector_type getEtak23() NBL_CONST_MEMBER_FUNC { return etak23; diff --git a/include/nbl/builtin/hlsl/bxdf/ndf/beckmann.hlsl b/include/nbl/builtin/hlsl/bxdf/ndf/beckmann.hlsl index c719bbfd4e..556292d0e8 100644 --- a/include/nbl/builtin/hlsl/bxdf/ndf/beckmann.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/ndf/beckmann.hlsl @@ -100,7 +100,7 @@ struct BeckmannCommon) - scalar_type D(NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) + scalar_type D(NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { if (a2 < numeric_limits::min) { @@ -115,7 +115,7 @@ struct BeckmannCommon= scalar_type(0.0)); return NdotX2 / (a2 * (scalar_type(1.0) - NdotX2)); @@ -131,7 +131,7 @@ struct BeckmannCommon) - scalar_type D(NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) + scalar_type D(NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { if (a2 < numeric_limits::min) { @@ -147,7 +147,7 @@ struct BeckmannCommon; using vector3_type = vector; - vector3_type __call(const vector3_type localV, const vector2_type u) + vector3_type __call(const vector3_type localV, const vector2_type u) NBL_CONST_MEMBER_FUNC { //stretch vector3_type V = nbl::hlsl::normalize(vector3_type(ax * localV.x, ay * localV.y, localV.z)); @@ -275,7 +275,7 @@ struct Beckmann } template && RequiredMicrofacetCache) - quant_query_type createQuantQuery(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, scalar_type orientedEta) + quant_query_type createQuantQuery(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, scalar_type orientedEta) NBL_CONST_MEMBER_FUNC { quant_query_type quant_query; // only has members for refraction NBL_IF_CONSTEXPR(SupportsTransmission) @@ -285,7 +285,7 @@ struct Beckmann return quant_query; } template NBL_FUNC_REQUIRES(RequiredInteraction && RequiredMicrofacetCache) - enable_if_t createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + enable_if_t createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { dg1_query_type dg1_query; bool dummy; @@ -294,7 +294,7 @@ struct Beckmann return dg1_query; } template NBL_FUNC_REQUIRES(LightSample && RequiredInteraction) - enable_if_t createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) + enable_if_t createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) NBL_CONST_MEMBER_FUNC { g2g1_query_type g2_query; g2_query.lambda_L = Lambda(__ndf_base.C2(_sample.getNdotL2())); @@ -302,7 +302,7 @@ struct Beckmann return g2_query; } template NBL_FUNC_REQUIRES(RequiredInteraction && RequiredMicrofacetCache) - enable_if_t createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + enable_if_t createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { dg1_query_type dg1_query; bool dummy; @@ -311,7 +311,7 @@ struct Beckmann return dg1_query; } template NBL_FUNC_REQUIRES(LightSample && RequiredInteraction) - enable_if_t createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) + enable_if_t createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) NBL_CONST_MEMBER_FUNC { g2g1_query_type g2_query; g2_query.lambda_L = Lambda(__ndf_base.C2(_sample.getTdotL2(), _sample.getBdotL2(), _sample.getNdotL2())); @@ -319,20 +319,20 @@ struct Beckmann return g2_query; } - vector3_type generateH(const vector3_type localV, const vector2_type u) + vector3_type generateH(const vector3_type localV, const vector2_type u) NBL_CONST_MEMBER_FUNC { return __generate_base.__call(localV, u); } template && RequiredInteraction && RequiredMicrofacetCache) - quant_type D(NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) + quant_type D(NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { scalar_type d = __ndf_base.template D(cache, isInfinity); return createDualMeasureQuantity(d, interaction.getNdotV(BxDFClampMode::BCM_ABS), _sample.getNdotL(BxDFClampMode::BCM_ABS), quant_query); } template && RequiredInteraction) - quant_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_REF_ARG(bool) isInfinity) + quant_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { scalar_type D = query.getNdf(); isInfinity = hlsl::isinf(D); @@ -348,7 +348,7 @@ struct Beckmann } template && RequiredInteraction && RequiredMicrofacetCache) - scalar_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + scalar_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { scalar_type onePlusLambda_V = scalar_type(1.0) + query.getLambdaV(); scalar_type lambda_L = query.getLambdaL(); @@ -356,7 +356,7 @@ struct Beckmann } template && RequiredInteraction && RequiredMicrofacetCache) - scalar_type G2_over_G1(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + scalar_type G2_over_G1(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { scalar_type onePlusLambda_V = scalar_type(1.0) + query.getLambdaV(); scalar_type lambda_L = query.getLambdaL(); diff --git a/include/nbl/builtin/hlsl/bxdf/ndf/ggx.hlsl b/include/nbl/builtin/hlsl/bxdf/ndf/ggx.hlsl index c64f6e3b84..2c5f0c819c 100644 --- a/include/nbl/builtin/hlsl/bxdf/ndf/ggx.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/ndf/ggx.hlsl @@ -86,7 +86,7 @@ struct GGXCommon) - scalar_type D(NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) + scalar_type D(NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { if (a2 < numeric_limits::min) { @@ -99,7 +99,7 @@ struct GGXCommon= numeric_limits::min); return sqrt(a2 + one_minus_a2 * NdotX2); @@ -116,7 +116,7 @@ struct GGXCommon) - scalar_type D(NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) + scalar_type D(NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { if (a2 < numeric_limits::min) { @@ -131,7 +131,7 @@ struct GGXCommon= numeric_limits::min && ay2 >= numeric_limits::min); return sqrt(TdotX2 * ax2 + BdotX2 * ay2 + NdotX2); @@ -149,7 +149,7 @@ struct GGXGenerateH using vector2_type = vector; using vector3_type = vector; - vector3_type __call(const vector3_type localV, const vector2_type u) + vector3_type __call(const vector3_type localV, const vector2_type u) NBL_CONST_MEMBER_FUNC { vector3_type V = hlsl::normalize(vector3_type(ax * localV.x, ay * localV.y, localV.z));//stretch view vector so that we're sampling as if roughness=1.0 @@ -213,7 +213,7 @@ struct GGX } template && RequiredMicrofacetCache) - quant_query_type createQuantQuery(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, scalar_type orientedEta) + quant_query_type createQuantQuery(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, scalar_type orientedEta) NBL_CONST_MEMBER_FUNC { quant_query_type quant_query; // only has members for refraction NBL_IF_CONSTEXPR(SupportsTransmission) @@ -223,7 +223,7 @@ struct GGX return quant_query; } template NBL_FUNC_REQUIRES(RequiredInteraction && RequiredMicrofacetCache) - enable_if_t createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + enable_if_t createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { dg1_query_type dg1_query; bool dummy; @@ -233,7 +233,7 @@ struct GGX return dg1_query; } template NBL_FUNC_REQUIRES(LightSample && RequiredInteraction) - enable_if_t createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) + enable_if_t createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) NBL_CONST_MEMBER_FUNC { g2g1_query_type g2_query; g2_query.devsh_l = __ndf_base.devsh_part(_sample.getNdotL2()); @@ -241,7 +241,7 @@ struct GGX return g2_query; } template NBL_FUNC_REQUIRES(RequiredInteraction && RequiredMicrofacetCache) - enable_if_t createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + enable_if_t createDG1Query(NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { dg1_query_type dg1_query; bool dummy; @@ -251,7 +251,7 @@ struct GGX return dg1_query; } template NBL_FUNC_REQUIRES(LightSample && RequiredInteraction) - enable_if_t createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) + enable_if_t createG2G1Query(NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction) NBL_CONST_MEMBER_FUNC { g2g1_query_type g2_query; g2_query.devsh_l = __ndf_base.devsh_part(_sample.getTdotL2(), _sample.getBdotL2(), _sample.getNdotL2()); @@ -259,20 +259,20 @@ struct GGX return g2_query; } - vector3_type generateH(const vector3_type localV, const vector2_type u) + vector3_type generateH(const vector3_type localV, const vector2_type u) NBL_CONST_MEMBER_FUNC { return __generate_base.__call(localV, u); } template && RequiredInteraction && RequiredMicrofacetCache) - quant_type D(NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) + quant_type D(NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { scalar_type d = __ndf_base.template D(cache, isInfinity); return createDualMeasureQuantity(d, interaction.getNdotV(BxDFClampMode::BCM_ABS), _sample.getNdotL(BxDFClampMode::BCM_ABS), quant_query); } template && RequiredInteraction) - quant_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_REF_ARG(bool) isInfinity) + quant_type DG1(NBL_CONST_REF_ARG(dg1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { scalar_type D = query.getNdfwoNumerator(); isInfinity = hlsl::isinf(D); @@ -301,7 +301,7 @@ struct GGX } template && RequiredInteraction && RequiredMicrofacetCache) - scalar_type correlated_wo_numerator(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + scalar_type correlated_wo_numerator(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { scalar_type NdotV = interaction.getNdotV(BxDFClampMode::BCM_ABS); scalar_type NdotL = _sample.getNdotL(BxDFClampMode::BCM_ABS); @@ -325,13 +325,13 @@ struct GGX } template && RequiredInteraction && RequiredMicrofacetCache) - scalar_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + scalar_type correlated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { return scalar_type(4.0) * interaction.getNdotV(BxDFClampMode::BCM_ABS) * _sample.getNdotL(BxDFClampMode::BCM_ABS) * correlated_wo_numerator(query, _sample, interaction, cache); } template && RequiredInteraction && RequiredMicrofacetCache) - quant_type Dcorrelated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) + quant_type Dcorrelated(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(quant_query_type) quant_query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache, NBL_REF_ARG(bool) isInfinity) NBL_CONST_MEMBER_FUNC { scalar_type dg = __ndf_base.template D(cache, isInfinity); if (isInfinity) @@ -361,7 +361,7 @@ struct GGX } template && RequiredInteraction && RequiredMicrofacetCache) - scalar_type G2_over_G1(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) + scalar_type G2_over_G1(NBL_CONST_REF_ARG(g2g1_query_type) query, NBL_CONST_REF_ARG(LS) _sample, NBL_CONST_REF_ARG(Interaction) interaction, NBL_CONST_REF_ARG(MicrofacetCache) cache) NBL_CONST_MEMBER_FUNC { scalar_type G2_over_G1; scalar_type NdotV = interaction.getNdotV(BxDFClampMode::BCM_ABS); diff --git a/include/nbl/builtin/hlsl/bxdf/reflection/delta_distribution.hlsl b/include/nbl/builtin/hlsl/bxdf/reflection/delta_distribution.hlsl index 7a37cc3b72..9bf9e16aa9 100644 --- a/include/nbl/builtin/hlsl/bxdf/reflection/delta_distribution.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/reflection/delta_distribution.hlsl @@ -25,16 +25,16 @@ struct SDeltaDistribution NBL_CONSTEXPR_STATIC_INLINE BxDFClampMode _clamp = BxDFClampMode::BCM_MAX; - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return hlsl::promote(0); } - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return hlsl::promote(0); } - sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u) + sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u) NBL_CONST_MEMBER_FUNC { vector3_type V = interaction.getV().getDirection(); bxdf::Reflect r = bxdf::Reflect::create(V, interaction.getN()); @@ -47,26 +47,26 @@ struct SDeltaDistribution return s; } - sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u) + sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u) NBL_CONST_MEMBER_FUNC { return generate(anisotropic_interaction_type::create(interaction), u); } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return 0; } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return 0; } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { const scalar_type _pdf = bit_cast(numeric_limits::infinity); return quotient_pdf_type::create(1.0, _pdf); } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return quotient_and_pdf(_sample, interaction.isotropic); } diff --git a/include/nbl/builtin/hlsl/bxdf/transmission/delta_distribution.hlsl b/include/nbl/builtin/hlsl/bxdf/transmission/delta_distribution.hlsl index 4e247c05d8..7ec41aeed5 100644 --- a/include/nbl/builtin/hlsl/bxdf/transmission/delta_distribution.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/transmission/delta_distribution.hlsl @@ -25,16 +25,16 @@ struct SDeltaDistribution NBL_CONSTEXPR_STATIC_INLINE BxDFClampMode _clamp = BxDFClampMode::BCM_ABS; - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return hlsl::promote(0); } - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return hlsl::promote(0); } - sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u) + sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector2_type u) NBL_CONST_MEMBER_FUNC { ray_dir_info_type L = interaction.getV().transmit(); sample_type s = sample_type::create(L, interaction.getN()); @@ -44,26 +44,26 @@ struct SDeltaDistribution s.NdotL2 = interaction.getNdotV2(); return s; } - sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u) + sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector2_type u) NBL_CONST_MEMBER_FUNC { return generate(anisotropic_interaction_type::create(interaction), u); } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return 0; } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return 0; } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { const scalar_type _pdf = bit_cast(numeric_limits::infinity); return quotient_pdf_type::create(1.0, _pdf); } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return quotient_and_pdf(_sample, interaction.isotropic); } diff --git a/include/nbl/builtin/hlsl/bxdf/transmission/smooth_dielectric.hlsl b/include/nbl/builtin/hlsl/bxdf/transmission/smooth_dielectric.hlsl index 6d5744fb49..bee202dc8d 100644 --- a/include/nbl/builtin/hlsl/bxdf/transmission/smooth_dielectric.hlsl +++ b/include/nbl/builtin/hlsl/bxdf/transmission/smooth_dielectric.hlsl @@ -26,16 +26,16 @@ struct SSmoothDielectric NBL_CONSTEXPR_STATIC_INLINE BxDFClampMode _clamp = BxDFClampMode::BCM_ABS; - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return hlsl::promote(0); } - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return hlsl::promote(0); } - sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, NBL_REF_ARG(vector3_type) u) + sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, NBL_REF_ARG(vector3_type) u) NBL_CONST_MEMBER_FUNC { const scalar_type reflectance = fresnel::Dielectric::__call(orientedEta.value*orientedEta.value, interaction.getNdotV(_clamp))[0]; @@ -51,27 +51,27 @@ struct SSmoothDielectric ray_dir_info_type L = V.reflectRefract(rr, transmitted, orientedEta.rcp[0]); return sample_type::create(L, interaction.getT(), interaction.getB(), interaction.getN()); } - sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, NBL_REF_ARG(vector3_type) u) + sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, NBL_REF_ARG(vector3_type) u) NBL_CONST_MEMBER_FUNC { return generate(anisotropic_interaction_type::create(interaction), u); } // eval and pdf return 0 because smooth dielectric/conductor BxDFs are dirac delta distributions, model perfectly specular objects that scatter light to only one outgoing direction - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return 0; } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return 0; } // smooth BxDFs are isotropic by definition - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return quotient_pdf_type::create(1.0, bit_cast(numeric_limits::infinity)); } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return quotient_and_pdf(_sample, interaction.isotropic); } @@ -105,11 +105,11 @@ struct SThinSmoothDielectric return retval; } - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return hlsl::promote(0); } - spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + spectral_type eval(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return hlsl::promote(0); } @@ -118,7 +118,7 @@ struct SThinSmoothDielectric // its basically a set of weights that determine // assert(1.0==luminosityContributionHint.r+luminosityContributionHint.g+luminosityContributionHint.b); // `remainderMetadata` is a variable which the generator function returns byproducts of sample generation that would otherwise have to be redundantly calculated `quotient_and_pdf` - sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u, NBL_REF_ARG(spectral_type) remainderMetadata) + sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u, NBL_REF_ARG(spectral_type) remainderMetadata) NBL_CONST_MEMBER_FUNC { // we will only ever intersect from the outside const spectral_type reflectance = fresnel::thinDielectricInfiniteScatter(fresnel(interaction.getNdotV(_clamp))); @@ -140,27 +140,27 @@ struct SThinSmoothDielectric return sample_type::create(L, interaction.getT(), interaction.getB(), N); } - sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u) + sample_type generate(NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction, const vector3_type u) NBL_CONST_MEMBER_FUNC { vector3_type dummy; return generate(interaction, u, dummy); } - sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector3_type u) + sample_type generate(NBL_CONST_REF_ARG(isotropic_interaction_type) interaction, const vector3_type u) NBL_CONST_MEMBER_FUNC { return generate(anisotropic_interaction_type::create(interaction), u); } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return 0; } - scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + scalar_type pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return 0; } // smooth BxDFs are isotropic by definition - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(isotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { const bool transmitted = ComputeMicrofacetNormal::isTransmissionPath(interaction.getNdotV(), _sample.getNdotL()); const spectral_type reflectance = fresnel::thinDielectricInfiniteScatter(fresnel(interaction.getNdotV(_clamp))); @@ -171,7 +171,7 @@ struct SThinSmoothDielectric const scalar_type _pdf = bit_cast(numeric_limits::infinity); return quotient_pdf_type::create(sampleValue / sampleProb, _pdf); } - quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) + quotient_pdf_type quotient_and_pdf(NBL_CONST_REF_ARG(sample_type) _sample, NBL_CONST_REF_ARG(anisotropic_interaction_type) interaction) NBL_CONST_MEMBER_FUNC { return quotient_and_pdf(_sample, interaction.isotropic); } From 9a3918a2e330762af674eb0a6f0f0914855b124a Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 16 Jan 2026 13:50:48 +0700 Subject: [PATCH 34/37] adaptive simpson should take const function --- .../hlsl/math/quadrature/adaptive_simpson.hlsl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl index 6952775f82..b480397057 100644 --- a/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl +++ b/include/nbl/builtin/hlsl/math/quadrature/adaptive_simpson.hlsl @@ -21,7 +21,7 @@ namespace impl template // F has function __call(x) struct integrate_helper { - static float_t __call(NBL_REF_ARG(F) f, float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) + static float_t __call(NBL_CONST_REF_ARG(F) f, float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) { float_t d = float_t(0.5) * (a + b); float_t e = float_t(0.5) * (b + c); @@ -45,7 +45,7 @@ struct integrate_helper template struct integrate_helper { - static float_t __call(NBL_REF_ARG(F) f, float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) + static float_t __call(NBL_CONST_REF_ARG(F) f, float_t a, float_t b, float_t c, float_t fa, float_t fb, float_t fc, float_t I, float_t eps, NBL_REF_ARG(int) count) { float_t d = float_t(0.5) * (a + b); float_t e = float_t(0.5) * (b + c); @@ -83,7 +83,7 @@ template()(0)), uint32_t Depth=6 N struct AdaptiveSimpson { // eps: absolute tolerance on the integral estimate - static float_t __call(NBL_REF_ARG(F) f, float_t x0, float_t x1, float_t eps = 1e-6) + static float_t __call(NBL_CONST_REF_ARG(F) f, float_t x0, float_t x1, float_t eps = 1e-6) { int count = 0; float_t a = x0; @@ -103,7 +103,7 @@ namespace impl template struct InnerIntegrand { - float_t operator()(float_t x) + float_t operator()(float_t x) NBL_CONST_MEMBER_FUNC { return f(x, y); } @@ -115,7 +115,7 @@ struct InnerIntegrand template struct OuterIntegrand { - float_t operator()(float_t y) + float_t operator()(float_t y) NBL_CONST_MEMBER_FUNC { using func_t = InnerIntegrand; func_t innerFunc; @@ -151,7 +151,7 @@ template()(0)), uint32_t Depth=6 N struct AdaptiveSimpson2D { // eps: absolute tolerance on the integral estimate - static float_t __call(NBL_REF_ARG(F) f, float32_t2 x0, float32_t2 x1, float_t eps = 1e-6) + static float_t __call(NBL_CONST_REF_ARG(F) f, float32_t2 x0, float32_t2 x1, float_t eps = 1e-6) { using func_t = impl::OuterIntegrand; func_t outerFunc; From ce371c732aba74e6038075b3ba5f96dc12303daf Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 16 Jan 2026 15:03:17 +0700 Subject: [PATCH 35/37] fixes create from matrix by using correct row-column indexing --- .../nbl/builtin/hlsl/math/quaternions.hlsl | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index ed0f796fe8..b56c6024cd 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -146,9 +146,9 @@ struct quaternion { 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[2][1] - m[1][2]) * invscales; - retval.data.y = (m[0][2] - m[2][0]) * invscales; - retval.data.z = (m[1][0] - m[0][1]) * invscales; + 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 @@ -158,31 +158,31 @@ struct quaternion 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[0][1] + m[1][0]) * invscales; - retval.data.z = (m[2][0] + m[0][2]) * invscales; - retval.data.w = (m[2][1] - m[1][2]) * invscales; + 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[0][1] + m[1][0]) * invscales; + retval.data.x = (m[1][0] + m[0][1]) * invscales; retval.data.y = scales * scalar_type(0.5); - retval.data.z = (m[1][2] + m[2][1]) * invscales; - retval.data.w = (m[0][2] - m[2][0]) * invscales; + 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[0][2] + m[2][0]) * invscales; - retval.data.y = (m[1][2] + m[2][1]) * invscales; + 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[1][0] - m[0][1]) * invscales; + retval.data.w = (m[0][1] - m[1][0]) * invscales; } } - retval.data = hlsl::normalize(retval.data) * uniformScale; // restore uniform scale + retval.data = retval.data * uniformScale; // restore uniform scale return retval; } @@ -326,7 +326,7 @@ struct quaternion return unnormLerp(start, end, fraction, totalPseudoAngle); } - this_t inverse() NBL_CONST_MEMBER_FUNC + this_t operator-() NBL_CONST_MEMBER_FUNC { this_t retval; retval.data.xyz = -data.xyz; From c8df31adf40358139f49e6d9caa52234993a8727 Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 16 Jan 2026 15:09:33 +0700 Subject: [PATCH 36/37] fix glm not liking unary - on swizzle --- include/nbl/builtin/hlsl/math/quaternions.hlsl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index b56c6024cd..9208bc2256 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -329,7 +329,9 @@ struct quaternion this_t operator-() NBL_CONST_MEMBER_FUNC { this_t retval; - retval.data.xyz = -data.xyz; + retval.data.x = -data.x; + retval.data.y = -data.y; + retval.data.z = -data.z; retval.data.w = data.w; return retval; } From f4b0b43d8aa65d83bc2559da24c694920cfa141a Mon Sep 17 00:00:00 2001 From: keptsecret Date: Fri, 16 Jan 2026 15:29:13 +0700 Subject: [PATCH 37/37] do quaternion inverse not as member function --- .../nbl/builtin/hlsl/math/quaternions.hlsl | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/include/nbl/builtin/hlsl/math/quaternions.hlsl b/include/nbl/builtin/hlsl/math/quaternions.hlsl index 9208bc2256..2d294cd4be 100644 --- a/include/nbl/builtin/hlsl/math/quaternions.hlsl +++ b/include/nbl/builtin/hlsl/math/quaternions.hlsl @@ -326,16 +326,6 @@ struct quaternion return unnormLerp(start, end, fraction, totalPseudoAngle); } - this_t operator-() NBL_CONST_MEMBER_FUNC - { - this_t retval; - retval.data.x = -data.x; - retval.data.y = -data.y; - retval.data.z = -data.z; - retval.data.w = data.w; - return retval; - } - data_type data; }; @@ -403,6 +393,18 @@ struct static_cast_helper, matrix > }; } +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; +} + } }