|
| 1 | +// Copyright (C) 2018-2023 - DevSH Graphics Programming Sp. z O.O. |
| 2 | +// This file is part of the "Nabla Engine". |
| 3 | +// For conditions of distribution and use, see copyright notice in nabla.h |
| 4 | +#ifndef _NBL_BUILTIN_HLSL_MATH_QUATERNIONS_INCLUDED_ |
| 5 | +#define _NBL_BUILTIN_HLSL_MATH_QUATERNIONS_INCLUDED_ |
| 6 | + |
| 7 | +#include "nbl/builtin/hlsl/cpp_compat.hlsl" |
| 8 | +#include "nbl/builtin/hlsl/tgmath.hlsl" |
| 9 | + |
| 10 | +namespace nbl |
| 11 | +{ |
| 12 | +namespace hlsl |
| 13 | +{ |
| 14 | +namespace math |
| 15 | +{ |
| 16 | + |
| 17 | +template <typename T> |
| 18 | +struct quaternion_t |
| 19 | +{ |
| 20 | + using this_t = quaternion_t<T>; |
| 21 | + using scalar_type = T; |
| 22 | + using data_type = vector<T, 4>; |
| 23 | + using vector3_type = vector<T, 3>; |
| 24 | + using matrix_type = matrix<T, 3, 3>; |
| 25 | + |
| 26 | + static this_t createFromTruncated(const vector3_type first3Components) |
| 27 | + { |
| 28 | + this_t retval; |
| 29 | + retval.data.xyz = first3Components; |
| 30 | + retval.data.w = hlsl::sqrt(scalar_type(1.0) - hlsl::dot(first3Components, first3Components)); |
| 31 | + return retval; |
| 32 | + } |
| 33 | + |
| 34 | + static this_t lerp(const this_t start, const this_t end, const scalar_type fraction, const scalar_type totalPseudoAngle) |
| 35 | + { |
| 36 | + using AsUint = typename unsigned_integer_of_size<sizeof(scalar_type)>::type; |
| 37 | + const AsUint negationMask = hlsl::bit_cast<AsUint>(totalPseudoAngle) & AsUint(0x80000000u); |
| 38 | + const data_type adjEnd = hlsl::bit_cast<scalar_type>(hlsl::bit_cast<AsUint>(end.data) ^ negationMask); |
| 39 | + |
| 40 | + this_t retval; |
| 41 | + retval.data = hlsl::mix(start.data, adjEnd, fraction); |
| 42 | + return retval; |
| 43 | + } |
| 44 | + |
| 45 | + static this_t lerp(const this_t start, const this_t end, const scalar_type fraction) |
| 46 | + { |
| 47 | + return lerp(start, end, fraction, hlsl::dot(start.data, end.data)); |
| 48 | + } |
| 49 | + |
| 50 | + static scalar_type __adj_interpolant(const scalar_type angle, const scalar_type fraction, const scalar_type interpolantPrecalcTerm2, const scalar_type interpolantPrecalcTerm3) |
| 51 | + { |
| 52 | + const scalar_type A = scalar_type(1.0904) + angle * (scalar_type(-3.2452) + angle * (scalar_type(3.55645) - angle * scalar_type(1.43519))); |
| 53 | + const scalar_type B = scalar_type(0.848013) + angle * (scalar_type(-1.06021) + angle * scalar_type(0.215638)); |
| 54 | + const scalar_type k = A * interpolantPrecalcTerm2 + B; |
| 55 | + return fraction + interpolantPrecalcTerm3 * k; |
| 56 | + } |
| 57 | + |
| 58 | + static this_t flerp(const this_t start, const this_t end, const scalar_type fraction) |
| 59 | + { |
| 60 | + const scalar_type pseudoAngle = hlsl::dot(start.data,end.data); |
| 61 | + const scalar_type interpolantPrecalcTerm = fraction - scalar_type(0.5); |
| 62 | + const scalar_type interpolantPrecalcTerm3 = fraction * interpolantPrecalcTerm * (fraction - scalar_type(1.0)); |
| 63 | + const scalar_type adjFrac = __adj_interpolant(hlsl::abs(pseudoAngle),fraction,interpolantPrecalcTerm*interpolantPrecalcTerm,interpolantPrecalcTerm3); |
| 64 | + |
| 65 | + this_t retval = lerp(start,end,adjFrac,pseudoAngle); |
| 66 | + retval.data = hlsl::normalize(retval.data); |
| 67 | + return retval; |
| 68 | + } |
| 69 | + |
| 70 | + matrix_type constructMatrix() |
| 71 | + { |
| 72 | + matrix_type mat; |
| 73 | + mat[0] = data.yzx * data.ywz + data.zxy * data.zyw * vector3_type( 1.0, 1.0,-1.0); |
| 74 | + mat[1] = data.yzx * data.xzw + data.zxy * data.wxz * vector3_type(-1.0, 1.0, 1.0); |
| 75 | + mat[2] = data.yzx * data.wyx + data.zxy * data.xwy * vector3_type( 1.0,-1.0, 1.0); |
| 76 | + mat[0][0] = scalar_type(0.5) - mat[0][0]; |
| 77 | + mat[1][1] = scalar_type(0.5) - mat[1][1]; |
| 78 | + mat[2][2] = scalar_type(0.5) - mat[2][2]; |
| 79 | + mat *= scalar_type(2.0); |
| 80 | + return hlsl::transpose(mat); // TODO: double check transpose? |
| 81 | + } |
| 82 | + |
| 83 | + static vector3_type slerp_delta(const vector3_type start, const vector3_type preScaledWaypoint, scalar_type cosAngleFromStart) |
| 84 | + { |
| 85 | + vector3_type planeNormal = hlsl::cross(start,preScaledWaypoint); |
| 86 | + |
| 87 | + cosAngleFromStart *= scalar_type(0.5); |
| 88 | + const scalar_type sinAngle = hlsl::sqrt(scalar_type(0.5) - cosAngleFromStart); |
| 89 | + const scalar_type cosAngle = hlsl::sqrt(scalar_type(0.5) + cosAngleFromStart); |
| 90 | + |
| 91 | + planeNormal *= sinAngle; |
| 92 | + const vector3_type precompPart = hlsl::cross(planeNormal, start) * scalar_type(2.0); |
| 93 | + |
| 94 | + return precompPart * cosAngle + hlsl::cross(planeNormal, precompPart); |
| 95 | + } |
| 96 | + |
| 97 | + data_type data; |
| 98 | +}; |
| 99 | + |
| 100 | +} |
| 101 | +} |
| 102 | +} |
| 103 | + |
| 104 | +#endif |
0 commit comments