Spaces:
Sleeping
Sleeping
| /** Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved. | |
| * NVIDIA CORPORATION and its licensors retain all intellectual property | |
| * and proprietary rights in and to this software, related documentation | |
| * and any modifications thereto. Any use, reproduction, disclosure or | |
| * distribution of this software and related documentation without an express | |
| * license agreement from NVIDIA CORPORATION is strictly prohibited. | |
| */ | |
| namespace wp | |
| { | |
| template<typename Type> | |
| struct quat_t | |
| { | |
| // zero constructor for adjoint variable initialization | |
| inline CUDA_CALLABLE quat_t(Type x=Type(0), Type y=Type(0), Type z=Type(0), Type w=Type(0)) : x(x), y(y), z(z), w(w) {} | |
| explicit inline CUDA_CALLABLE quat_t(const vec_t<3,Type>& v, Type w=Type(0)) : x(v[0]), y(v[1]), z(v[2]), w(w) {} | |
| template<typename OtherType> | |
| explicit inline CUDA_CALLABLE quat_t(const quat_t<OtherType>& other) | |
| { | |
| x = static_cast<Type>(other.x); | |
| y = static_cast<Type>(other.y); | |
| z = static_cast<Type>(other.z); | |
| w = static_cast<Type>(other.w); | |
| } | |
| // imaginary part | |
| Type x; | |
| Type y; | |
| Type z; | |
| // real part | |
| Type w; | |
| }; | |
| using quat = quat_t<float>; | |
| using quath = quat_t<half>; | |
| using quatf = quat_t<float>; | |
| using quatd = quat_t<double>; | |
| template<typename Type> | |
| inline CUDA_CALLABLE bool operator==(const quat_t<Type>& a, const quat_t<Type>& b) | |
| { | |
| return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; | |
| } | |
| template<typename Type> | |
| inline bool CUDA_CALLABLE isfinite(const quat_t<Type>& q) | |
| { | |
| return isfinite(q.x) && isfinite(q.y) && isfinite(q.z) && isfinite(q.w); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> atomic_add(quat_t<Type> * addr, quat_t<Type> value) | |
| { | |
| Type x = atomic_add(&(addr -> x), value.x); | |
| Type y = atomic_add(&(addr -> y), value.y); | |
| Type z = atomic_add(&(addr -> z), value.z); | |
| Type w = atomic_add(&(addr -> w), value.w); | |
| return quat_t<Type>(x, y, z, w); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_t(Type x, Type y, Type z, Type w, Type& adj_x, Type& adj_y, Type& adj_z, Type& adj_w, quat_t<Type> adj_ret) | |
| { | |
| adj_x += adj_ret.x; | |
| adj_y += adj_ret.y; | |
| adj_z += adj_ret.z; | |
| adj_w += adj_ret.w; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_t(const vec_t<3,Type>& v, Type w, vec_t<3,Type>& adj_v, Type& adj_w, quat_t<Type> adj_ret) | |
| { | |
| adj_v[0] += adj_ret.x; | |
| adj_v[1] += adj_ret.y; | |
| adj_v[2] += adj_ret.z; | |
| adj_w += adj_ret.w; | |
| } | |
| // casting constructor adjoint | |
| template<typename Type, typename OtherType> | |
| inline CUDA_CALLABLE void adj_quat_t(const quat_t<OtherType>& other, quat_t<OtherType>& adj_other, const quat_t<Type>& adj_ret) | |
| { | |
| adj_other.x += static_cast<OtherType>(adj_ret.x); | |
| adj_other.y += static_cast<OtherType>(adj_ret.y); | |
| adj_other.z += static_cast<OtherType>(adj_ret.z); | |
| adj_other.w += static_cast<OtherType>(adj_ret.w); | |
| } | |
| // forward methods | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> quat_from_axis_angle(const vec_t<3,Type>& axis, Type angle) | |
| { | |
| Type half = angle*Type(Type(0.5)); | |
| Type w = cos(half); | |
| Type sin_theta_over_two = sin(half); | |
| vec_t<3,Type> v = axis*sin_theta_over_two; | |
| return quat_t<Type>(v[0], v[1], v[2], w); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void quat_to_axis_angle(const quat_t<Type>& q, vec_t<3,Type>& axis, Type& angle) | |
| { | |
| vec_t<3,Type> v = vec_t<3,Type>(q.x, q.y, q.z); | |
| axis = q.w < Type(0) ? -normalize(v) : normalize(v); | |
| angle = Type(2) * atan2(length(v), abs(q.w)); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> quat_rpy(Type roll, Type pitch, Type yaw) | |
| { | |
| Type cy = cos(yaw * Type(0.5)); | |
| Type sy = sin(yaw * Type(0.5)); | |
| Type cr = cos(roll * Type(0.5)); | |
| Type sr = sin(roll * Type(0.5)); | |
| Type cp = cos(pitch * Type(0.5)); | |
| Type sp = sin(pitch * Type(0.5)); | |
| Type w = (cy * cr * cp + sy * sr * sp); | |
| Type x = (cy * sr * cp - sy * cr * sp); | |
| Type y = (cy * cr * sp + sy * sr * cp); | |
| Type z = (sy * cr * cp - cy * sr * sp); | |
| return quat_t<Type>(x, y, z, w); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> quat_inverse(const quat_t<Type>& q) | |
| { | |
| return quat_t<Type>(-q.x, -q.y, -q.z, q.w); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE Type dot(const quat_t<Type>& a, const quat_t<Type>& b) | |
| { | |
| return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE Type tensordot(const quat_t<Type>& a, const quat_t<Type>& b) | |
| { | |
| // corresponds to `np.tensordot()` with all axes being contracted | |
| return dot(a, b); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE Type length(const quat_t<Type>& q) | |
| { | |
| return sqrt(dot(q, q)); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE Type length_sq(const quat_t<Type>& q) | |
| { | |
| return dot(q, q); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> normalize(const quat_t<Type>& q) | |
| { | |
| Type l = length(q); | |
| if (l > Type(kEps)) | |
| { | |
| Type inv_l = Type(1)/l; | |
| return quat_t<Type>(q.x*inv_l, q.y*inv_l, q.z*inv_l, q.w*inv_l); | |
| } | |
| else | |
| { | |
| return quat_t<Type>(Type(0), Type(0), Type(0), Type(1)); | |
| } | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> add(const quat_t<Type>& a, const quat_t<Type>& b) | |
| { | |
| return quat_t<Type>(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> sub(const quat_t<Type>& a, const quat_t<Type>& b) | |
| { | |
| return quat_t<Type>(a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w);} | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> mul(const quat_t<Type>& a, const quat_t<Type>& b) | |
| { | |
| return quat_t<Type>(a.w*b.x + b.w*a.x + a.y*b.z - b.y*a.z, | |
| a.w*b.y + b.w*a.y + a.z*b.x - b.z*a.x, | |
| a.w*b.z + b.w*a.z + a.x*b.y - b.x*a.y, | |
| a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> mul(const quat_t<Type>& a, Type s) | |
| { | |
| return quat_t<Type>(a.x*s, a.y*s, a.z*s, a.w*s); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> mul(Type s, const quat_t<Type>& a) | |
| { | |
| return mul(a, s); | |
| } | |
| // division | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> div(quat_t<Type> q, Type s) | |
| { | |
| return quat_t<Type>(q.x/s, q.y/s, q.z/s, q.w/s); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> div(Type s, quat_t<Type> q) | |
| { | |
| return quat_t<Type>(s/q.x, s/q.y, s/q.z, s/q.w); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> operator / (quat_t<Type> a, Type s) | |
| { | |
| return div(a,s); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> operator / (Type s, quat_t<Type> a) | |
| { | |
| return div(s,a); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> operator*(Type s, const quat_t<Type>& a) | |
| { | |
| return mul(a, s); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> operator*(const quat_t<Type>& a, Type s) | |
| { | |
| return mul(a, s); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE vec_t<3,Type> quat_rotate(const quat_t<Type>& q, const vec_t<3,Type>& x) | |
| { | |
| Type c = (Type(2)*q.w*q.w-Type(1)); | |
| Type d = Type(2)*(q.x*x.c[0] + q.y*x.c[1] + q.z*x.c[2]); | |
| return vec_t<3,Type>( | |
| x.c[0]*c + q.x*d + (q.y * x[2] - q.z * x[1])*q.w*Type(2), | |
| x.c[1]*c + q.y*d + (q.z * x[0] - q.x * x[2])*q.w*Type(2), | |
| x.c[2]*c + q.z*d + (q.x * x[1] - q.y * x[0])*q.w*Type(2) | |
| ); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE vec_t<3,Type> quat_rotate_inv(const quat_t<Type>& q, const vec_t<3,Type>& x) | |
| { | |
| Type c = (Type(2)*q.w*q.w-Type(1)); | |
| Type d = Type(2)*(q.x*x.c[0] + q.y*x.c[1] + q.z*x.c[2]); | |
| return vec_t<3,Type>( | |
| x.c[0]*c + q.x*d - (q.y * x[2] - q.z * x[1])*q.w*Type(2), | |
| x.c[1]*c + q.y*d - (q.z * x[0] - q.x * x[2])*q.w*Type(2), | |
| x.c[2]*c + q.z*d - (q.x * x[1] - q.y * x[0])*q.w*Type(2) | |
| ); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> quat_slerp(const quat_t<Type>& q0, const quat_t<Type>& q1, Type t) | |
| { | |
| vec_t<3,Type> axis; | |
| Type angle; | |
| quat_to_axis_angle(mul(quat_inverse(q0), q1), axis, angle); | |
| return mul(q0, quat_from_axis_angle(axis, t * angle)); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE mat_t<3,3,Type> quat_to_matrix(const quat_t<Type>& q) | |
| { | |
| vec_t<3,Type> c1 = quat_rotate(q, vec_t<3,Type>(1.0, 0.0, 0.0)); | |
| vec_t<3,Type> c2 = quat_rotate(q, vec_t<3,Type>(0.0, 1.0, 0.0)); | |
| vec_t<3,Type> c3 = quat_rotate(q, vec_t<3,Type>(0.0, 0.0, 1.0)); | |
| return mat_t<3,3,Type>(c1, c2, c3); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE quat_t<Type> quat_from_matrix(const mat_t<3,3,Type>& m) | |
| { | |
| const Type tr = m.data[0][0] + m.data[1][1] + m.data[2][2]; | |
| Type x, y, z, w, h = Type(0); | |
| if (tr >= Type(0)) { | |
| h = sqrt(tr + Type(1)); | |
| w = Type(0.5) * h; | |
| h = Type(0.5) / h; | |
| x = (m.data[2][1] - m.data[1][2]) * h; | |
| y = (m.data[0][2] - m.data[2][0]) * h; | |
| z = (m.data[1][0] - m.data[0][1]) * h; | |
| } else { | |
| size_t max_diag = 0; | |
| if (m.data[1][1] > m.data[0][0]) { | |
| max_diag = 1; | |
| } | |
| if (m.data[2][2] > m.data[max_diag][max_diag]) { | |
| max_diag = 2; | |
| } | |
| if (max_diag == 0) { | |
| h = sqrt((m.data[0][0] - (m.data[1][1] + m.data[2][2])) + Type(1)); | |
| x = Type(0.5) * h; | |
| h = Type(0.5) / h; | |
| y = (m.data[0][1] + m.data[1][0]) * h; | |
| z = (m.data[2][0] + m.data[0][2]) * h; | |
| w = (m.data[2][1] - m.data[1][2]) * h; | |
| } else if (max_diag == 1) { | |
| h = sqrt((m.data[1][1] - (m.data[2][2] + m.data[0][0])) + Type(1)); | |
| y = Type(0.5) * h; | |
| h = Type(0.5) / h; | |
| z = (m.data[1][2] + m.data[2][1]) * h; | |
| x = (m.data[0][1] + m.data[1][0]) * h; | |
| w = (m.data[0][2] - m.data[2][0]) * h; | |
| } if (max_diag == 2) { | |
| h = sqrt((m.data[2][2] - (m.data[0][0] + m.data[1][1])) + Type(1)); | |
| z = Type(0.5) * h; | |
| h = Type(0.5) / h; | |
| x = (m.data[2][0] + m.data[0][2]) * h; | |
| y = (m.data[1][2] + m.data[2][1]) * h; | |
| w = (m.data[1][0] - m.data[0][1]) * h; | |
| } | |
| } | |
| return normalize(quat_t<Type>(x, y, z, w)); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE Type extract(const quat_t<Type>& a, int idx) | |
| { | |
| if (idx < 0 || idx > 3) | |
| { | |
| printf("quat_t index %d out of bounds at %s %d", idx, __FILE__, __LINE__); | |
| assert(0); | |
| } | |
| /* | |
| * Because quat data is not stored in an array, we index the quaternion by checking all possible idx values. | |
| * (&a.x)[idx] would be the preferred access strategy, but this results in undefined behavior in the clang compiler | |
| * at optimization level 3. | |
| */ | |
| if (idx == 0) {return a.x;} | |
| else if (idx == 1) {return a.y;} | |
| else if (idx == 2) {return a.z;} | |
| else {return a.w;} | |
| } | |
| template<typename Type> | |
| CUDA_CALLABLE inline quat_t<Type> lerp(const quat_t<Type>& a, const quat_t<Type>& b, Type t) | |
| { | |
| return a*(Type(1)-t) + b*t; | |
| } | |
| template<typename Type> | |
| CUDA_CALLABLE inline void adj_lerp(const quat_t<Type>& a, const quat_t<Type>& b, Type t, quat_t<Type>& adj_a, quat_t<Type>& adj_b, Type& adj_t, const quat_t<Type>& adj_ret) | |
| { | |
| adj_a += adj_ret*(Type(1)-t); | |
| adj_b += adj_ret*t; | |
| adj_t += tensordot(b, adj_ret) - tensordot(a, adj_ret); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_extract(const quat_t<Type>& a, int idx, quat_t<Type>& adj_a, int & adj_idx, Type & adj_ret) | |
| { | |
| if (idx < 0 || idx > 3) | |
| { | |
| printf("quat_t index %d out of bounds at %s %d", idx, __FILE__, __LINE__); | |
| assert(0); | |
| } | |
| // See wp::extract(const quat_t<Type>& a, int idx) note | |
| if (idx == 0) {adj_a.x += adj_ret;} | |
| else if (idx == 1) {adj_a.y += adj_ret;} | |
| else if (idx == 2) {adj_a.z += adj_ret;} | |
| else {adj_a.w += adj_ret;} | |
| } | |
| // backward methods | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_from_axis_angle(const vec_t<3,Type>& axis, Type angle, vec_t<3,Type>& adj_axis, Type& adj_angle, const quat_t<Type>& adj_ret) | |
| { | |
| vec_t<3,Type> v = vec_t<3,Type>(adj_ret.x, adj_ret.y, adj_ret.z); | |
| Type s = sin(angle*Type(0.5)); | |
| Type c = cos(angle*Type(0.5)); | |
| quat_t<Type> dqda = quat_t<Type>(axis[0]*c, axis[1]*c, axis[2]*c, -s)*Type(0.5); | |
| adj_axis += v*s; | |
| adj_angle += dot(dqda, adj_ret); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_to_axis_angle(const quat_t<Type>& q, vec_t<3,Type>& axis, Type& angle, quat_t<Type>& adj_q, const vec_t<3,Type>& adj_axis, const Type& adj_angle) | |
| { | |
| Type l = length(vec_t<3,Type>(q.x, q.y, q.z)); | |
| Type ax_qx = Type(0); | |
| Type ax_qy = Type(0); | |
| Type ax_qz = Type(0); | |
| Type ay_qx = Type(0); | |
| Type ay_qy = Type(0); | |
| Type ay_qz = Type(0); | |
| Type az_qx = Type(0); | |
| Type az_qy = Type(0); | |
| Type az_qz = Type(0); | |
| Type t_qx = Type(0); | |
| Type t_qy = Type(0); | |
| Type t_qz = Type(0); | |
| Type t_qw = Type(0); | |
| Type flip = q.w < Type(0) ? -1.0 : 1.0; | |
| if (l > Type(0)) | |
| { | |
| Type l_sq = l*l; | |
| Type l_inv = Type(1) / l; | |
| Type l_inv_sq = l_inv * l_inv; | |
| Type l_inv_cu = l_inv_sq * l_inv; | |
| Type C = flip * l_inv_cu; | |
| ax_qx = C * (q.y*q.y + q.z*q.z); | |
| ax_qy = -C * q.x*q.y; | |
| ax_qz = -C * q.x*q.z; | |
| ay_qx = -C * q.y*q.x; | |
| ay_qy = C * (q.x*q.x + q.z*q.z); | |
| ay_qz = -C * q.y*q.z; | |
| az_qx = -C * q.z*q.x; | |
| az_qy = -C * q.z*q.y; | |
| az_qz = C * (q.x*q.x + q.y*q.y); | |
| Type D = Type(2) * flip / (l_sq + q.w*q.w); | |
| t_qx = D * l_inv * q.x * q.w; | |
| t_qy = D * l_inv * q.y * q.w; | |
| t_qz = D * l_inv * q.z * q.w; | |
| t_qw = -D * l; | |
| } | |
| else | |
| { | |
| if (abs(q.w) > Type(kEps)) | |
| { | |
| Type t_qx = Type(2) / (sqrt(Type(3)) * abs(q.w)); | |
| Type t_qy = Type(2) / (sqrt(Type(3)) * abs(q.w)); | |
| Type t_qz = Type(2) / (sqrt(Type(3)) * abs(q.w)); | |
| } | |
| // o/w we have a null quat_t which cannot backpropagate | |
| } | |
| adj_q.x += ax_qx * adj_axis[0] + ay_qx * adj_axis[1] + az_qx * adj_axis[2] + t_qx * adj_angle; | |
| adj_q.y += ax_qy * adj_axis[0] + ay_qy * adj_axis[1] + az_qy * adj_axis[2] + t_qy * adj_angle; | |
| adj_q.z += ax_qz * adj_axis[0] + ay_qz * adj_axis[1] + az_qz * adj_axis[2] + t_qz * adj_angle; | |
| adj_q.w += t_qw * adj_angle; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_rpy(Type roll, Type pitch, Type yaw, Type& adj_roll, Type& adj_pitch, Type& adj_yaw, const quat_t<Type>& adj_ret) | |
| { | |
| Type cy = cos(yaw * Type(0.5)); | |
| Type sy = sin(yaw * Type(0.5)); | |
| Type cr = cos(roll * Type(0.5)); | |
| Type sr = sin(roll * Type(0.5)); | |
| Type cp = cos(pitch * Type(0.5)); | |
| Type sp = sin(pitch * Type(0.5)); | |
| Type w = (cy * cr * cp + sy * sr * sp); | |
| Type x = (cy * sr * cp - sy * cr * sp); | |
| Type y = (cy * cr * sp + sy * sr * cp); | |
| Type z = (sy * cr * cp - cy * sr * sp); | |
| Type dx_dr = Type(0.5) * w; | |
| Type dx_dp = -Type(0.5) * cy * sr * sp - Type(0.5) * sy * cr * cp; | |
| Type dx_dy = -Type(0.5) * y; | |
| Type dy_dr = Type(0.5) * z; | |
| Type dy_dp = Type(0.5) * cy * cr * cp - Type(0.5) * sy * sr * sp; | |
| Type dy_dy = Type(0.5) * x; | |
| Type dz_dr = -Type(0.5) * y; | |
| Type dz_dp = -Type(0.5) * sy * cr * sp - Type(0.5) * cy * sr * cp; | |
| Type dz_dy = Type(0.5) * w; | |
| Type dw_dr = -Type(0.5) * x; | |
| Type dw_dp = -Type(0.5) * cy * cr * sp + Type(0.5) * sy * sr * cp; | |
| Type dw_dy = -Type(0.5) * z; | |
| adj_roll += dot(quat_t<Type>(dx_dr, dy_dr, dz_dr, dw_dr), adj_ret); | |
| adj_pitch += dot(quat_t<Type>(dx_dp, dy_dp, dz_dp, dw_dp), adj_ret); | |
| adj_yaw += dot(quat_t<Type>(dx_dy, dy_dy, dz_dy, dw_dy), adj_ret); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_dot(const quat_t<Type>& a, const quat_t<Type>& b, quat_t<Type>& adj_a, quat_t<Type>& adj_b, const Type adj_ret) | |
| { | |
| adj_a += b*adj_ret; | |
| adj_b += a*adj_ret; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void tensordot(const quat_t<Type>& a, const quat_t<Type>& b, quat_t<Type>& adj_a, quat_t<Type>& adj_b, const Type adj_ret) | |
| { | |
| adj_dot(a, b, adj_a, adj_b, adj_ret); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_length(const quat_t<Type>& a, Type ret, quat_t<Type>& adj_a, const Type adj_ret) | |
| { | |
| if (ret > Type(kEps)) | |
| { | |
| Type inv_l = Type(1)/ret; | |
| adj_a += quat_t<Type>(a.x*inv_l, a.y*inv_l, a.z*inv_l, a.w*inv_l) * adj_ret; | |
| } | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_length_sq(const quat_t<Type>& a, quat_t<Type>& adj_a, const Type adj_ret) | |
| { | |
| adj_a += Type(2)*a*adj_ret; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_normalize(const quat_t<Type>& q, quat_t<Type>& adj_q, const quat_t<Type>& adj_ret) | |
| { | |
| Type l = length(q); | |
| if (l > Type(kEps)) | |
| { | |
| Type l_inv = Type(1)/l; | |
| adj_q += adj_ret*l_inv - q*(l_inv*l_inv*l_inv*dot(q, adj_ret)); | |
| } | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_inverse(const quat_t<Type>& q, quat_t<Type>& adj_q, const quat_t<Type>& adj_ret) | |
| { | |
| adj_q.x -= adj_ret.x; | |
| adj_q.y -= adj_ret.y; | |
| adj_q.z -= adj_ret.z; | |
| adj_q.w += adj_ret.w; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_add(const quat_t<Type>& a, const quat_t<Type>& b, quat_t<Type>& adj_a, quat_t<Type>& adj_b, const quat_t<Type>& adj_ret) | |
| { | |
| adj_a += adj_ret; | |
| adj_b += adj_ret; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_sub(const quat_t<Type>& a, const quat_t<Type>& b, quat_t<Type>& adj_a, quat_t<Type>& adj_b, const quat_t<Type>& adj_ret) | |
| { | |
| adj_a += adj_ret; | |
| adj_b -= adj_ret; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_mul(const quat_t<Type>& a, const quat_t<Type>& b, quat_t<Type>& adj_a, quat_t<Type>& adj_b, const quat_t<Type>& adj_ret) | |
| { | |
| // shorthand | |
| const quat_t<Type>& r = adj_ret; | |
| adj_a += quat_t<Type>(b.w*r.x - b.x*r.w + b.y*r.z - b.z*r.y, | |
| b.w*r.y - b.y*r.w - b.x*r.z + b.z*r.x, | |
| b.w*r.z + b.x*r.y - b.y*r.x - b.z*r.w, | |
| b.w*r.w + b.x*r.x + b.y*r.y + b.z*r.z); | |
| adj_b += quat_t<Type>(a.w*r.x - a.x*r.w - a.y*r.z + a.z*r.y, | |
| a.w*r.y - a.y*r.w + a.x*r.z - a.z*r.x, | |
| a.w*r.z - a.x*r.y + a.y*r.x - a.z*r.w, | |
| a.w*r.w + a.x*r.x + a.y*r.y + a.z*r.z); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_mul(const quat_t<Type>& a, Type s, quat_t<Type>& adj_a, Type& adj_s, const quat_t<Type>& adj_ret) | |
| { | |
| adj_a += adj_ret*s; | |
| adj_s += dot(a, adj_ret); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_mul(Type s, const quat_t<Type>& a, Type& adj_s, quat_t<Type>& adj_a, const quat_t<Type>& adj_ret) | |
| { | |
| adj_mul(a, s, adj_a, adj_s, adj_ret); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_div(quat_t<Type> a, Type s, quat_t<Type>& adj_a, Type& adj_s, const quat_t<Type>& adj_ret) | |
| { | |
| adj_s -= dot(a, adj_ret)/ (s * s); // - a / s^2 | |
| adj_a += adj_ret / s; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_div(Type s, quat_t<Type> a, Type& adj_s, quat_t<Type>& adj_a, const quat_t<Type>& adj_ret) | |
| { | |
| adj_s -= dot(a, adj_ret)/ (s * s); // - a / s^2 | |
| adj_a += s / adj_ret; | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_rotate(const quat_t<Type>& q, const vec_t<3,Type>& p, quat_t<Type>& adj_q, vec_t<3,Type>& adj_p, const vec_t<3,Type>& adj_ret) | |
| { | |
| { | |
| Type t2 = p[2]*q.z*Type(2); | |
| Type t3 = p[1]*q.w*Type(2); | |
| Type t4 = p[0]*q.w*Type(2); | |
| Type t5 = p[0]*q.x*Type(2); | |
| Type t6 = p[1]*q.y*Type(2); | |
| Type t7 = p[2]*q.y*Type(2); | |
| Type t8 = p[0]*q.z*Type(2); | |
| Type t9 = p[0]*q.y*Type(2); | |
| Type t10 = p[1]*q.x*Type(2); | |
| adj_q.x += adj_ret[2]*(t3+t8)+adj_ret[0]*(t2+t6+p[0]*q.x*Type(4))+adj_ret[1]*(t9-p[2]*q.w*Type(2)); | |
| adj_q.y += adj_ret[1]*(t2+t5+p[1]*q.y*Type(4))+adj_ret[0]*(t10+p[2]*q.w*Type(2))-adj_ret[2]*(t4-p[1]*q.z*Type(2)); | |
| adj_q.z += adj_ret[1]*(t4+t7)+adj_ret[2]*(t5+t6+p[2]*q.z*Type(4))-adj_ret[0]*(t3-p[2]*q.x*Type(2)); | |
| adj_q.w += adj_ret[0]*(t7+p[0]*q.w*Type(4)-p[1]*q.z*Type(2))+adj_ret[1]*(t8+p[1]*q.w*Type(4)-p[2]*q.x*Type(2))+adj_ret[2]*(-t9+t10+p[2]*q.w*Type(4)); | |
| } | |
| { | |
| Type t2 = q.w*q.w; | |
| Type t3 = t2*Type(2); | |
| Type t4 = q.w*q.z*Type(2); | |
| Type t5 = q.x*q.y*Type(2); | |
| Type t6 = q.w*q.y*Type(2); | |
| Type t7 = q.w*q.x*Type(2); | |
| Type t8 = q.y*q.z*Type(2); | |
| adj_p[0] += adj_ret[1]*(t4+t5)+adj_ret[0]*(t3+(q.x*q.x)*Type(2)-Type(1))-adj_ret[2]*(t6-q.x*q.z*Type(2)); | |
| adj_p[1] += adj_ret[2]*(t7+t8)-adj_ret[0]*(t4-t5)+adj_ret[1]*(t3+(q.y*q.y)*Type(2)-Type(1)); | |
| adj_p[2] += -adj_ret[1]*(t7-t8)+adj_ret[2]*(t3+(q.z*q.z)*Type(2)-Type(1))+adj_ret[0]*(t6+q.x*q.z*Type(2)); | |
| } | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_rotate_inv(const quat_t<Type>& q, const vec_t<3,Type>& p, quat_t<Type>& adj_q, vec_t<3,Type>& adj_p, const vec_t<3,Type>& adj_ret) | |
| { | |
| const vec_t<3,Type>& r = adj_ret; | |
| { | |
| Type t2 = p[2]*q.w*Type(2); | |
| Type t3 = p[2]*q.z*Type(2); | |
| Type t4 = p[1]*q.w*Type(2); | |
| Type t5 = p[0]*q.w*Type(2); | |
| Type t6 = p[0]*q.x*Type(2); | |
| Type t7 = p[1]*q.y*Type(2); | |
| Type t8 = p[1]*q.z*Type(2); | |
| Type t9 = p[2]*q.x*Type(2); | |
| Type t10 = p[0]*q.y*Type(2); | |
| adj_q.x += r[1]*(t2+t10)+r[0]*(t3+t7+p[0]*q.x*Type(4))-r[2]*(t4-p[0]*q.z*Type(2)); | |
| adj_q.y += r[2]*(t5+t8)+r[1]*(t3+t6+p[1]*q.y*Type(4))-r[0]*(t2-p[1]*q.x*Type(2)); | |
| adj_q.z += r[0]*(t4+t9)+r[2]*(t6+t7+p[2]*q.z*Type(4))-r[1]*(t5-p[2]*q.y*Type(2)); | |
| adj_q.w += r[0]*(t8+p[0]*q.w*Type(4)-p[2]*q.y*Type(2))+r[1]*(t9+p[1]*q.w*Type(4)-p[0]*q.z*Type(2))+r[2]*(t10-p[1]*q.x*Type(2)+p[2]*q.w*Type(4)); | |
| } | |
| { | |
| Type t2 = q.w*q.w; | |
| Type t3 = t2*Type(2); | |
| Type t4 = q.w*q.z*Type(2); | |
| Type t5 = q.w*q.y*Type(2); | |
| Type t6 = q.x*q.z*Type(2); | |
| Type t7 = q.w*q.x*Type(2); | |
| adj_p[0] += r[2]*(t5+t6)+r[0]*(t3+(q.x*q.x)*Type(2)-Type(1))-r[1]*(t4-q.x*q.y*Type(2)); | |
| adj_p[1] += r[1]*(t3+(q.y*q.y)*Type(2)-Type(1))+r[0]*(t4+q.x*q.y*Type(2))-r[2]*(t7-q.y*q.z*Type(2)); | |
| adj_p[2] += -r[0]*(t5-t6)+r[2]*(t3+(q.z*q.z)*Type(2)-Type(1))+r[1]*(t7+q.y*q.z*Type(2)); | |
| } | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_slerp(const quat_t<Type>& q0, const quat_t<Type>& q1, Type t, quat_t<Type>& ret, quat_t<Type>& adj_q0, quat_t<Type>& adj_q1, Type& adj_t, const quat_t<Type>& adj_ret) | |
| { | |
| vec_t<3,Type> axis; | |
| Type angle; | |
| quat_t<Type> q0_inv = quat_inverse(q0); | |
| quat_t<Type> q_inc = mul(q0_inv, q1); | |
| quat_to_axis_angle(q_inc, axis, angle); | |
| quat_t<Type> qt = quat_from_axis_angle(axis, angle * t); | |
| angle = angle * 0.5; | |
| // adj_t | |
| adj_t += dot(mul(ret, quat_t<Type>(angle*axis[0], angle*axis[1], angle*axis[2], Type(0))), adj_ret); | |
| // adj_q0 | |
| quat_t<Type> q_inc_x_q0; | |
| quat_t<Type> q_inc_y_q0; | |
| quat_t<Type> q_inc_z_q0; | |
| quat_t<Type> q_inc_w_q0; | |
| quat_t<Type> q_inc_x_q1; | |
| quat_t<Type> q_inc_y_q1; | |
| quat_t<Type> q_inc_z_q1; | |
| quat_t<Type> q_inc_w_q1; | |
| adj_mul(q0_inv, q1, q_inc_x_q0, q_inc_x_q1, quat_t<Type>(1.f, Type(0), Type(0), Type(0))); | |
| adj_mul(q0_inv, q1, q_inc_y_q0, q_inc_y_q1, quat_t<Type>(Type(0), 1.f, Type(0), Type(0))); | |
| adj_mul(q0_inv, q1, q_inc_z_q0, q_inc_z_q1, quat_t<Type>(Type(0), Type(0), 1.f, Type(0))); | |
| adj_mul(q0_inv, q1, q_inc_w_q0, q_inc_w_q1, quat_t<Type>(Type(0), Type(0), Type(0), 1.f)); | |
| quat_t<Type> a_x_q_inc; | |
| quat_t<Type> a_y_q_inc; | |
| quat_t<Type> a_z_q_inc; | |
| quat_t<Type> t_q_inc; | |
| adj_quat_to_axis_angle(q_inc, axis, angle, a_x_q_inc, vec_t<3,Type>(1.f, Type(0), Type(0)), Type(0)); | |
| adj_quat_to_axis_angle(q_inc, axis, angle, a_y_q_inc, vec_t<3,Type>(Type(0), 1.f, Type(0)), Type(0)); | |
| adj_quat_to_axis_angle(q_inc, axis, angle, a_z_q_inc, vec_t<3,Type>(Type(0), Type(0), 1.f), Type(0)); | |
| adj_quat_to_axis_angle(q_inc, axis, angle, t_q_inc, vec_t<3,Type>(Type(0), Type(0), Type(0)), Type(1)); | |
| Type cs = cos(angle*t); | |
| Type sn = sin(angle*t); | |
| quat_t<Type> q_inc_q0_x = quat_t<Type>(-q_inc_x_q0.x, -q_inc_y_q0.x, -q_inc_z_q0.x, -q_inc_w_q0.x); | |
| quat_t<Type> q_inc_q0_y = quat_t<Type>(-q_inc_x_q0.y, -q_inc_y_q0.y, -q_inc_z_q0.y, -q_inc_w_q0.y); | |
| quat_t<Type> q_inc_q0_z = quat_t<Type>(-q_inc_x_q0.z, -q_inc_y_q0.z, -q_inc_z_q0.z, -q_inc_w_q0.z); | |
| quat_t<Type> q_inc_q0_w = quat_t<Type>(q_inc_x_q0.w, q_inc_y_q0.w, q_inc_z_q0.w, q_inc_w_q0.w); | |
| Type a_x_q0_x = dot(a_x_q_inc, q_inc_q0_x); | |
| Type a_x_q0_y = dot(a_x_q_inc, q_inc_q0_y); | |
| Type a_x_q0_z = dot(a_x_q_inc, q_inc_q0_z); | |
| Type a_x_q0_w = dot(a_x_q_inc, q_inc_q0_w); | |
| Type a_y_q0_x = dot(a_y_q_inc, q_inc_q0_x); | |
| Type a_y_q0_y = dot(a_y_q_inc, q_inc_q0_y); | |
| Type a_y_q0_z = dot(a_y_q_inc, q_inc_q0_z); | |
| Type a_y_q0_w = dot(a_y_q_inc, q_inc_q0_w); | |
| Type a_z_q0_x = dot(a_z_q_inc, q_inc_q0_x); | |
| Type a_z_q0_y = dot(a_z_q_inc, q_inc_q0_y); | |
| Type a_z_q0_z = dot(a_z_q_inc, q_inc_q0_z); | |
| Type a_z_q0_w = dot(a_z_q_inc, q_inc_q0_w); | |
| Type t_q0_x = dot(t_q_inc, q_inc_q0_x); | |
| Type t_q0_y = dot(t_q_inc, q_inc_q0_y); | |
| Type t_q0_z = dot(t_q_inc, q_inc_q0_z); | |
| Type t_q0_w = dot(t_q_inc, q_inc_q0_w); | |
| quat_t<Type> q_s_q0_x = mul(quat_t<Type>(1.f, Type(0), Type(0), Type(0)), qt) + mul(q0, quat_t<Type>( | |
| 0.5 * t * axis[0] * t_q0_x * cs + a_x_q0_x * sn, | |
| 0.5 * t * axis[1] * t_q0_x * cs + a_y_q0_x * sn, | |
| 0.5 * t * axis[2] * t_q0_x * cs + a_z_q0_x * sn, | |
| -0.5 * t * t_q0_x * sn)); | |
| quat_t<Type> q_s_q0_y = mul(quat_t<Type>(Type(0), 1.f, Type(0), Type(0)), qt) + mul(q0, quat_t<Type>( | |
| 0.5 * t * axis[0] * t_q0_y * cs + a_x_q0_y * sn, | |
| 0.5 * t * axis[1] * t_q0_y * cs + a_y_q0_y * sn, | |
| 0.5 * t * axis[2] * t_q0_y * cs + a_z_q0_y * sn, | |
| -0.5 * t * t_q0_y * sn)); | |
| quat_t<Type> q_s_q0_z = mul(quat_t<Type>(Type(0), Type(0), 1.f, Type(0)), qt) + mul(q0, quat_t<Type>( | |
| 0.5 * t * axis[0] * t_q0_z * cs + a_x_q0_z * sn, | |
| 0.5 * t * axis[1] * t_q0_z * cs + a_y_q0_z * sn, | |
| 0.5 * t * axis[2] * t_q0_z * cs + a_z_q0_z * sn, | |
| -0.5 * t * t_q0_z * sn)); | |
| quat_t<Type> q_s_q0_w = mul(quat_t<Type>(Type(0), Type(0), Type(0), 1.f), qt) + mul(q0, quat_t<Type>( | |
| 0.5 * t * axis[0] * t_q0_w * cs + a_x_q0_w * sn, | |
| 0.5 * t * axis[1] * t_q0_w * cs + a_y_q0_w * sn, | |
| 0.5 * t * axis[2] * t_q0_w * cs + a_z_q0_w * sn, | |
| -0.5 * t * t_q0_w * sn)); | |
| adj_q0.x += dot(q_s_q0_x, adj_ret); | |
| adj_q0.y += dot(q_s_q0_y, adj_ret); | |
| adj_q0.z += dot(q_s_q0_z, adj_ret); | |
| adj_q0.w += dot(q_s_q0_w, adj_ret); | |
| // adj_q1 | |
| quat_t<Type> q_inc_q1_x = quat_t<Type>(q_inc_x_q1.x, q_inc_y_q1.x, q_inc_z_q1.x, q_inc_w_q1.x); | |
| quat_t<Type> q_inc_q1_y = quat_t<Type>(q_inc_x_q1.y, q_inc_y_q1.y, q_inc_z_q1.y, q_inc_w_q1.y); | |
| quat_t<Type> q_inc_q1_z = quat_t<Type>(q_inc_x_q1.z, q_inc_y_q1.z, q_inc_z_q1.z, q_inc_w_q1.z); | |
| quat_t<Type> q_inc_q1_w = quat_t<Type>(q_inc_x_q1.w, q_inc_y_q1.w, q_inc_z_q1.w, q_inc_w_q1.w); | |
| Type a_x_q1_x = dot(a_x_q_inc, q_inc_q1_x); | |
| Type a_x_q1_y = dot(a_x_q_inc, q_inc_q1_y); | |
| Type a_x_q1_z = dot(a_x_q_inc, q_inc_q1_z); | |
| Type a_x_q1_w = dot(a_x_q_inc, q_inc_q1_w); | |
| Type a_y_q1_x = dot(a_y_q_inc, q_inc_q1_x); | |
| Type a_y_q1_y = dot(a_y_q_inc, q_inc_q1_y); | |
| Type a_y_q1_z = dot(a_y_q_inc, q_inc_q1_z); | |
| Type a_y_q1_w = dot(a_y_q_inc, q_inc_q1_w); | |
| Type a_z_q1_x = dot(a_z_q_inc, q_inc_q1_x); | |
| Type a_z_q1_y = dot(a_z_q_inc, q_inc_q1_y); | |
| Type a_z_q1_z = dot(a_z_q_inc, q_inc_q1_z); | |
| Type a_z_q1_w = dot(a_z_q_inc, q_inc_q1_w); | |
| Type t_q1_x = dot(t_q_inc, q_inc_q1_x); | |
| Type t_q1_y = dot(t_q_inc, q_inc_q1_y); | |
| Type t_q1_z = dot(t_q_inc, q_inc_q1_z); | |
| Type t_q1_w = dot(t_q_inc, q_inc_q1_w); | |
| quat_t<Type> q_s_q1_x = mul(q0, quat_t<Type>( | |
| 0.5 * t * axis[0] * t_q1_x * cs + a_x_q1_x * sn, | |
| 0.5 * t * axis[1] * t_q1_x * cs + a_y_q1_x * sn, | |
| 0.5 * t * axis[2] * t_q1_x * cs + a_z_q1_x * sn, | |
| -0.5 * t * t_q1_x * sn)); | |
| quat_t<Type> q_s_q1_y = mul(q0, quat_t<Type>( | |
| 0.5 * t * axis[0] * t_q1_y * cs + a_x_q1_y * sn, | |
| 0.5 * t * axis[1] * t_q1_y * cs + a_y_q1_y * sn, | |
| 0.5 * t * axis[2] * t_q1_y * cs + a_z_q1_y * sn, | |
| -0.5 * t * t_q1_y * sn)); | |
| quat_t<Type> q_s_q1_z = mul(q0, quat_t<Type>( | |
| 0.5 * t * axis[0] * t_q1_z * cs + a_x_q1_z * sn, | |
| 0.5 * t * axis[1] * t_q1_z * cs + a_y_q1_z * sn, | |
| 0.5 * t * axis[2] * t_q1_z * cs + a_z_q1_z * sn, | |
| -0.5 * t * t_q1_z * sn)); | |
| quat_t<Type> q_s_q1_w = mul(q0, quat_t<Type>( | |
| 0.5 * t * axis[0] * t_q1_w * cs + a_x_q1_w * sn, | |
| 0.5 * t * axis[1] * t_q1_w * cs + a_y_q1_w * sn, | |
| 0.5 * t * axis[2] * t_q1_w * cs + a_z_q1_w * sn, | |
| -0.5 * t * t_q1_w * sn)); | |
| adj_q1.x += dot(q_s_q1_x, adj_ret); | |
| adj_q1.y += dot(q_s_q1_y, adj_ret); | |
| adj_q1.z += dot(q_s_q1_z, adj_ret); | |
| adj_q1.w += dot(q_s_q1_w, adj_ret); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_to_matrix(const quat_t<Type>& q, quat_t<Type>& adj_q, mat_t<3,3,Type>& adj_ret) | |
| { | |
| // we don't care about adjoint w.r.t. constant identity matrix | |
| vec_t<3,Type> t; | |
| adj_quat_rotate(q, vec_t<3,Type>(1.0, 0.0, 0.0), adj_q, t, adj_ret.get_col(0)); | |
| adj_quat_rotate(q, vec_t<3,Type>(0.0, 1.0, 0.0), adj_q, t, adj_ret.get_col(1)); | |
| adj_quat_rotate(q, vec_t<3,Type>(0.0, 0.0, 1.0), adj_q, t, adj_ret.get_col(2)); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_quat_from_matrix(const mat_t<3,3,Type>& m, mat_t<3,3,Type>& adj_m, const quat_t<Type>& adj_ret) | |
| { | |
| const Type tr = m.data[0][0] + m.data[1][1] + m.data[2][2]; | |
| Type x, y, z, w, h = Type(0); | |
| Type dx_dm00 = Type(0), dx_dm01 = Type(0), dx_dm02 = Type(0); | |
| Type dx_dm10 = Type(0), dx_dm11 = Type(0), dx_dm12 = Type(0); | |
| Type dx_dm20 = Type(0), dx_dm21 = Type(0), dx_dm22 = Type(0); | |
| Type dy_dm00 = Type(0), dy_dm01 = Type(0), dy_dm02 = Type(0); | |
| Type dy_dm10 = Type(0), dy_dm11 = Type(0), dy_dm12 = Type(0); | |
| Type dy_dm20 = Type(0), dy_dm21 = Type(0), dy_dm22 = Type(0); | |
| Type dz_dm00 = Type(0), dz_dm01 = Type(0), dz_dm02 = Type(0); | |
| Type dz_dm10 = Type(0), dz_dm11 = Type(0), dz_dm12 = Type(0); | |
| Type dz_dm20 = Type(0), dz_dm21 = Type(0), dz_dm22 = Type(0); | |
| Type dw_dm00 = Type(0), dw_dm01 = Type(0), dw_dm02 = Type(0); | |
| Type dw_dm10 = Type(0), dw_dm11 = Type(0), dw_dm12 = Type(0); | |
| Type dw_dm20 = Type(0), dw_dm21 = Type(0), dw_dm22 = Type(0); | |
| if (tr >= Type(0)) { | |
| h = sqrt(tr + Type(1)); | |
| w = Type(0.5) * h; | |
| h = Type(0.5) / h; | |
| x = (m.data[2][1] - m.data[1][2]) * h; | |
| y = (m.data[0][2] - m.data[2][0]) * h; | |
| z = (m.data[1][0] - m.data[0][1]) * h; | |
| dw_dm00 = Type(0.5) * h; | |
| dw_dm11 = Type(0.5) * h; | |
| dw_dm22 = Type(0.5) * h; | |
| dx_dm21 = h; | |
| dx_dm12 = -h; | |
| dx_dm00 = Type(2) * h*h*h * (m.data[1][2] - m.data[2][1]); | |
| dx_dm11 = Type(2) * h*h*h * (m.data[1][2] - m.data[2][1]); | |
| dx_dm22 = Type(2) * h*h*h * (m.data[1][2] - m.data[2][1]); | |
| dy_dm02 = h; | |
| dy_dm20 = -h; | |
| dy_dm00 = Type(2) * h*h*h * (m.data[2][0] - m.data[0][2]); | |
| dy_dm11 = Type(2) * h*h*h * (m.data[2][0] - m.data[0][2]); | |
| dy_dm22 = Type(2) * h*h*h * (m.data[2][0] - m.data[0][2]); | |
| dz_dm10 = h; | |
| dz_dm01 = -h; | |
| dz_dm00 = Type(2) * h*h*h * (m.data[0][1] - m.data[1][0]); | |
| dz_dm11 = Type(2) * h*h*h * (m.data[0][1] - m.data[1][0]); | |
| dz_dm22 = Type(2) * h*h*h * (m.data[0][1] - m.data[1][0]); | |
| } else { | |
| size_t max_diag = 0; | |
| if (m.data[1][1] > m.data[0][0]) { | |
| max_diag = 1; | |
| } | |
| if (m.data[2][2] > m.data[max_diag][max_diag]) { | |
| max_diag = 2; | |
| } | |
| if (max_diag == 0) { | |
| h = sqrt((m.data[0][0] - (m.data[1][1] + m.data[2][2])) + Type(1)); | |
| x = Type(0.5) * h; | |
| h = Type(0.5) / h; | |
| y = (m.data[0][1] + m.data[1][0]) * h; | |
| z = (m.data[2][0] + m.data[0][2]) * h; | |
| w = (m.data[2][1] - m.data[1][2]) * h; | |
| dx_dm00 = Type(0.5) * h; | |
| dx_dm11 = -Type(0.5) * h; | |
| dx_dm22 = -Type(0.5) * h; | |
| dy_dm01 = h; | |
| dy_dm10 = h; | |
| dy_dm00 = -Type(2) * h*h*h * (m.data[0][1] + m.data[1][0]); | |
| dy_dm11 = Type(2) * h*h*h * (m.data[0][1] + m.data[1][0]); | |
| dy_dm22 = Type(2) * h*h*h * (m.data[0][1] + m.data[1][0]); | |
| dz_dm20 = h; | |
| dz_dm02 = h; | |
| dz_dm00 = -Type(2) * h*h*h * (m.data[2][0] + m.data[0][2]); | |
| dz_dm11 = Type(2) * h*h*h * (m.data[2][0] + m.data[0][2]); | |
| dz_dm22 = Type(2) * h*h*h * (m.data[2][0] + m.data[0][2]); | |
| dw_dm21 = h; | |
| dw_dm12 = -h; | |
| dw_dm00 = Type(2) * h*h*h * (m.data[1][2] - m.data[2][1]); | |
| dw_dm11 = Type(2) * h*h*h * (m.data[2][1] - m.data[1][2]); | |
| dw_dm22 = Type(2) * h*h*h * (m.data[2][1] - m.data[1][2]); | |
| } else if (max_diag == 1) { | |
| h = sqrt((m.data[1][1] - (m.data[2][2] + m.data[0][0])) + Type(1)); | |
| y = Type(0.5) * h; | |
| h = Type(0.5) / h; | |
| z = (m.data[1][2] + m.data[2][1]) * h; | |
| x = (m.data[0][1] + m.data[1][0]) * h; | |
| w = (m.data[0][2] - m.data[2][0]) * h; | |
| dy_dm00 = -Type(0.5) * h; | |
| dy_dm11 = Type(0.5) * h; | |
| dy_dm22 = -Type(0.5) * h; | |
| dz_dm12 = h; | |
| dz_dm21 = h; | |
| dz_dm00 = Type(2) * h*h*h * (m.data[1][2] + m.data[2][1]); | |
| dz_dm11 = -Type(2) * h*h*h * (m.data[1][2] + m.data[2][1]); | |
| dz_dm22 = Type(2) * h*h*h * (m.data[1][2] + m.data[2][1]); | |
| dx_dm01 = h; | |
| dx_dm10 = h; | |
| dx_dm00 = Type(2) * h*h*h * (m.data[0][1] + m.data[1][0]); | |
| dx_dm11 = -Type(2) * h*h*h * (m.data[0][1] + m.data[1][0]); | |
| dx_dm22 = Type(2) * h*h*h * (m.data[0][1] + m.data[1][0]); | |
| dw_dm02 = h; | |
| dw_dm20 = -h; | |
| dw_dm00 = Type(2) * h*h*h * (m.data[0][2] - m.data[2][0]); | |
| dw_dm11 = Type(2) * h*h*h * (m.data[2][0] - m.data[0][2]); | |
| dw_dm22 = Type(2) * h*h*h * (m.data[0][2] - m.data[2][0]); | |
| } if (max_diag == 2) { | |
| h = sqrt((m.data[2][2] - (m.data[0][0] + m.data[1][1])) + Type(1)); | |
| z = Type(0.5) * h; | |
| h = Type(0.5) / h; | |
| x = (m.data[2][0] + m.data[0][2]) * h; | |
| y = (m.data[1][2] + m.data[2][1]) * h; | |
| w = (m.data[1][0] - m.data[0][1]) * h; | |
| dz_dm00 = -Type(0.5) * h; | |
| dz_dm11 = -Type(0.5) * h; | |
| dz_dm22 = Type(0.5) * h; | |
| dx_dm20 = h; | |
| dx_dm02 = h; | |
| dx_dm00 = Type(2) * h*h*h * (m.data[2][0] + m.data[0][2]); | |
| dx_dm11 = Type(2) * h*h*h * (m.data[2][0] + m.data[0][2]); | |
| dx_dm22 = -Type(2) * h*h*h * (m.data[2][0] + m.data[0][2]); | |
| dy_dm12 = h; | |
| dy_dm21 = h; | |
| dy_dm00 = Type(2) * h*h*h * (m.data[1][2] + m.data[2][1]); | |
| dy_dm11 = Type(2) * h*h*h * (m.data[1][2] + m.data[2][1]); | |
| dy_dm22 = -Type(2) * h*h*h * (m.data[1][2] + m.data[2][1]); | |
| dw_dm10 = h; | |
| dw_dm01 = -h; | |
| dw_dm00 = Type(2) * h*h*h * (m.data[1][0] - m.data[0][1]); | |
| dw_dm11 = Type(2) * h*h*h * (m.data[1][0] - m.data[0][1]); | |
| dw_dm22 = Type(2) * h*h*h * (m.data[0][1] - m.data[1][0]); | |
| } | |
| } | |
| quat_t<Type> dq_dm00 = quat_t<Type>(dx_dm00, dy_dm00, dz_dm00, dw_dm00); | |
| quat_t<Type> dq_dm01 = quat_t<Type>(dx_dm01, dy_dm01, dz_dm01, dw_dm01); | |
| quat_t<Type> dq_dm02 = quat_t<Type>(dx_dm02, dy_dm02, dz_dm02, dw_dm02); | |
| quat_t<Type> dq_dm10 = quat_t<Type>(dx_dm10, dy_dm10, dz_dm10, dw_dm10); | |
| quat_t<Type> dq_dm11 = quat_t<Type>(dx_dm11, dy_dm11, dz_dm11, dw_dm11); | |
| quat_t<Type> dq_dm12 = quat_t<Type>(dx_dm12, dy_dm12, dz_dm12, dw_dm12); | |
| quat_t<Type> dq_dm20 = quat_t<Type>(dx_dm20, dy_dm20, dz_dm20, dw_dm20); | |
| quat_t<Type> dq_dm21 = quat_t<Type>(dx_dm21, dy_dm21, dz_dm21, dw_dm21); | |
| quat_t<Type> dq_dm22 = quat_t<Type>(dx_dm22, dy_dm22, dz_dm22, dw_dm22); | |
| quat_t<Type> adj_q; | |
| adj_normalize(quat_t<Type>(x, y, z, w), adj_q, adj_ret); | |
| adj_m.data[0][0] += dot(dq_dm00, adj_q); | |
| adj_m.data[0][1] += dot(dq_dm01, adj_q); | |
| adj_m.data[0][2] += dot(dq_dm02, adj_q); | |
| adj_m.data[1][0] += dot(dq_dm10, adj_q); | |
| adj_m.data[1][1] += dot(dq_dm11, adj_q); | |
| adj_m.data[1][2] += dot(dq_dm12, adj_q); | |
| adj_m.data[2][0] += dot(dq_dm20, adj_q); | |
| adj_m.data[2][1] += dot(dq_dm21, adj_q); | |
| adj_m.data[2][2] += dot(dq_dm22, adj_q); | |
| } | |
| template<typename Type> | |
| inline CUDA_CALLABLE void adj_mat_t(const vec_t<3,Type>& pos, const quat_t<Type>& rot, const vec_t<3,Type>& scale, | |
| vec_t<3,Type>& adj_pos, quat_t<Type>& adj_rot, vec_t<3,Type>& adj_scale, const mat_t<4,4,Type>& adj_ret) | |
| { | |
| mat_t<3,3,Type> R = quat_to_matrix(rot); | |
| mat_t<3,3,Type> adj_R(0); | |
| adj_pos[0] += adj_ret.data[0][3]; | |
| adj_pos[1] += adj_ret.data[1][3]; | |
| adj_pos[2] += adj_ret.data[2][3]; | |
| adj_mul(R.data[0][0], scale[0], adj_R.data[0][0], adj_scale[0], adj_ret.data[0][0]); | |
| adj_mul(R.data[1][0], scale[0], adj_R.data[1][0], adj_scale[0], adj_ret.data[1][0]); | |
| adj_mul(R.data[2][0], scale[0], adj_R.data[2][0], adj_scale[0], adj_ret.data[2][0]); | |
| adj_mul(R.data[0][1], scale[1], adj_R.data[0][1], adj_scale[1], adj_ret.data[0][1]); | |
| adj_mul(R.data[1][1], scale[1], adj_R.data[1][1], adj_scale[1], adj_ret.data[1][1]); | |
| adj_mul(R.data[2][1], scale[1], adj_R.data[2][1], adj_scale[1], adj_ret.data[2][1]); | |
| adj_mul(R.data[0][2], scale[2], adj_R.data[0][2], adj_scale[2], adj_ret.data[0][2]); | |
| adj_mul(R.data[1][2], scale[2], adj_R.data[1][2], adj_scale[2], adj_ret.data[1][2]); | |
| adj_mul(R.data[2][2], scale[2], adj_R.data[2][2], adj_scale[2], adj_ret.data[2][2]); | |
| adj_quat_to_matrix(rot, adj_rot, adj_R); | |
| } | |
| template<unsigned Rows, unsigned Cols, typename Type> | |
| inline CUDA_CALLABLE mat_t<Rows,Cols,Type>::mat_t(const vec_t<3,Type>& pos, const quat_t<Type>& rot, const vec_t<3,Type>& scale) | |
| { | |
| mat_t<3,3,Type> R = quat_to_matrix(rot); | |
| data[0][0] = R.data[0][0]*scale[0]; | |
| data[1][0] = R.data[1][0]*scale[0]; | |
| data[2][0] = R.data[2][0]*scale[0]; | |
| data[3][0] = Type(0); | |
| data[0][1] = R.data[0][1]*scale[1]; | |
| data[1][1] = R.data[1][1]*scale[1]; | |
| data[2][1] = R.data[2][1]*scale[1]; | |
| data[3][1] = Type(0); | |
| data[0][2] = R.data[0][2]*scale[2]; | |
| data[1][2] = R.data[1][2]*scale[2]; | |
| data[2][2] = R.data[2][2]*scale[2]; | |
| data[3][2] = Type(0); | |
| data[0][3] = pos[0]; | |
| data[1][3] = pos[1]; | |
| data[2][3] = pos[2]; | |
| data[3][3] = Type(1); | |
| } | |
| template<typename Type=float32> | |
| inline CUDA_CALLABLE quat_t<Type> quat_identity() | |
| { | |
| return quat_t<Type>(Type(0), Type(0), Type(0), Type(1)); | |
| } | |
| } // namespace wp |