Преглед на файлове

math: implement quaternion creation from true Euler angles (as opposed

to the Tait-Bryan angles we had for now). Also, change quaternion storage
order to wxyz in order to match the constructors.
legacy
Sam Hocevar sam преди 12 години
родител
ревизия
552dfee5b1
променени са 2 файла, в които са добавени 81 реда и са изтрити 77 реда
  1. +29
    -12
      src/lol/math/vector.h
  2. +52
    -65
      src/math/vector.cpp

+ 29
- 12
src/lol/math/vector.h Целия файл

@@ -125,9 +125,9 @@ template<typename T, int N> struct XVec4
* Helper macro for vector type member functions
*/

#define DECLARE_MEMBER_OPS(tname) \
inline T& operator[](size_t n) { return *(&this->x + n); } \
inline T const& operator[](size_t n) const { return *(&this->x + n); } \
#define DECLARE_MEMBER_OPS(tname, first) \
inline T& operator[](size_t n) { return *(&this->first + n); } \
inline T const& operator[](size_t n) const { return *(&this->first + n); } \
\
/* Visual Studio insists on having an assignment operator. */ \
inline tname<T> const & operator =(tname<T> const &that) \
@@ -233,7 +233,7 @@ template <typename T> struct Vec2 : BVec2<T>
explicit inline Vec2(XVec2<U, N> const &v)
: BVec2<T>(v[0], v[1]) {}

DECLARE_MEMBER_OPS(Vec2)
DECLARE_MEMBER_OPS(Vec2, x)

#if !defined __ANDROID__
template<typename U>
@@ -251,7 +251,7 @@ template <typename T> struct Cmplx
inline Cmplx(T X) : x(X), y(0) {}
inline Cmplx(T X, T Y) : x(X), y(Y) {}

DECLARE_MEMBER_OPS(Cmplx)
DECLARE_MEMBER_OPS(Cmplx, x)

inline Cmplx<T> operator *(Cmplx<T> const &val) const
{
@@ -491,7 +491,7 @@ template <typename T> struct Vec3 : BVec3<T>

static Vec3<T> toeuler(Quat<T> const &q);

DECLARE_MEMBER_OPS(Vec3)
DECLARE_MEMBER_OPS(Vec3, x)

#if !defined __ANDROID__
template<typename U>
@@ -900,7 +900,7 @@ template <typename T> struct Vec4 : BVec4<T>
explicit inline Vec4(XVec4<U, N> const &v)
: BVec4<T>(v[0], v[1], v[2], v[3]) {}

DECLARE_MEMBER_OPS(Vec4)
DECLARE_MEMBER_OPS(Vec4, x)

#if !defined __ANDROID__
template<typename U>
@@ -915,17 +915,34 @@ template <typename T> struct Vec4 : BVec4<T>
template <typename T> struct Quat
{
inline Quat() {}
inline Quat(T W) : x(0), y(0), z(0), w(W) {}
inline Quat(T W, T X, T Y, T Z) : x(X), y(Y), z(Z), w(W) {}
inline Quat(T W) : w(W), x(0), y(0), z(0) {}
inline Quat(T W, T X, T Y, T Z) : w(W), x(X), y(Y), z(Z) {}

Quat(Mat3<T> const &m);
Quat(Mat4<T> const &m);

DECLARE_MEMBER_OPS(Quat)
DECLARE_MEMBER_OPS(Quat, w)

static Quat<T> rotate(T angle, T x, T y, T z);
static Quat<T> rotate(T angle, Vec3<T> const &v);

/* Convert from Euler angles. The axes in fromeuler_xyx are
* x, then y', then x", ie. the axes are attached to the model.
* If you want to rotate around static axes, just reverse the order
* of the arguments. */
static Quat<T> fromeuler_xyx(Vec3<T> const &v);
static Quat<T> fromeuler_xzx(Vec3<T> const &v);
static Quat<T> fromeuler_yxy(Vec3<T> const &v);
static Quat<T> fromeuler_yzy(Vec3<T> const &v);
static Quat<T> fromeuler_zxz(Vec3<T> const &v);
static Quat<T> fromeuler_zyz(Vec3<T> const &v);
static Quat<T> fromeuler_xyx(T phi, T theta, T psi);
static Quat<T> fromeuler_xzx(T phi, T theta, T psi);
static Quat<T> fromeuler_yxy(T phi, T theta, T psi);
static Quat<T> fromeuler_yzy(T phi, T theta, T psi);
static Quat<T> fromeuler_zxz(T phi, T theta, T psi);
static Quat<T> fromeuler_zyz(T phi, T theta, T psi);

/* Convert from Tait-Bryan angles (incorrectly called Euler angles,
* but since everyone does it…). The axes in fromeuler_xyz are
* x, then y', then z", ie. the axes are attached to the model.
@@ -978,8 +995,8 @@ template <typename T> struct Quat
friend std::ostream &operator<<(std::ostream &stream, Quat<U> const &v);
#endif

/* Storage order is still xyzw because operator[] uses &this->x */
T x, y, z, w;
/* XXX: storage order is wxyz, unlike vectors! */
T w, x, y, z;
};

template<typename T>


+ 52
- 65
src/math/vector.cpp Целия файл

@@ -538,7 +538,7 @@ template<> mat3 mat3::fromeuler(float x, float y, float z)
return mat3::fromeuler(vec3(x, y, z));
}

static inline quat fromeuler_generic(vec3 const &v, int s, int i, int j, int k)
static inline quat quat_fromeuler_generic(vec3 const &v, int i, int j, int k)
{
using std::sin;
using std::cos;
@@ -548,76 +548,63 @@ static inline quat fromeuler_generic(vec3 const &v, int s, int i, int j, int k)
float s1 = sin(half_angles[1]), c1 = cos(half_angles[1]);
float s2 = sin(half_angles[2]), c2 = cos(half_angles[2]);

vec4 v1(c0 * c1 * c2, c0 * c1 * s2, c0 * s1 * c2, s0 * c1 * c2);
vec4 v2(s0 * s1 * s2, -s0 * s1 * c2, s0 * c1 * s2, -c0 * s1 * s2);
quat ret;

if (s > 0)
v1 += v2;
if (i == k)
{
ret[0] = c1 * (c0 * c2 - s0 * s2);
ret[1 + i] = c1 * (c0 * s2 + s0 * c2);
ret[1 + j] = s1 * (c0 * c2 + s0 * s2);
if ((2 + i - j) % 3)
ret[4 - i - j] = s1 * (s0 * c2 - c0 * s2);
else
ret[4 - i - j] = s1 * (c0 * s2 - s0 * c2);
}
else
v1 -= v2;

return quat(v1[0], v1[i], v1[j], v1[k]);
}

template<> quat quat::fromeuler_xyz(vec3 const &v)
{
return fromeuler_generic(v, -1, 3, 2, 1);
}

template<> quat quat::fromeuler_xzy(vec3 const &v)
{
return fromeuler_generic(v, 1, 3, 1, 2);
}

template<> quat quat::fromeuler_yxz(vec3 const &v)
{
return fromeuler_generic(v, 1, 2, 3, 1);
}

template<> quat quat::fromeuler_yzx(vec3 const &v)
{
return fromeuler_generic(v, -1, 1, 3, 2);
}

template<> quat quat::fromeuler_zxy(vec3 const &v)
{
return fromeuler_generic(v, -1, 2, 1, 3);
}

template<> quat quat::fromeuler_zyx(vec3 const &v)
{
return fromeuler_generic(v, 1, 1, 2, 3);
}

template<> quat quat::fromeuler_xyz(float phi, float theta, float psi)
{
return quat::fromeuler_zyx(vec3(phi, theta, psi));
}

template<> quat quat::fromeuler_xzy(float phi, float theta, float psi)
{
return quat::fromeuler_yxz(vec3(phi, theta, psi));
}

template<> quat quat::fromeuler_yxz(float phi, float theta, float psi)
{
return quat::fromeuler_yxz(vec3(phi, theta, psi));
}
{
vec4 v1(c0 * c1 * c2, s0 * c1 * c2, c0 * s1 * c2, c0 * c1 * s2);
vec4 v2(s0 * s1 * s2, -c0 * s1 * s2, s0 * c1 * s2, -s0 * s1 * c2);

if ((2 + i - j) % 3)
v1 -= v2;
else
v1 += v2;

ret[0] = v1[0];
ret[1 + i] = v1[1];
ret[1 + j] = v1[2];
ret[4 - i - j] = v1[3];
}

template<> quat quat::fromeuler_yzx(float phi, float theta, float psi)
{
return quat::fromeuler_yxz(vec3(phi, theta, psi));
return ret;
}

template<> quat quat::fromeuler_zxy(float phi, float theta, float psi)
{
return quat::fromeuler_yxz(vec3(phi, theta, psi));
}
#define QUAT_FROMEULER_GENERIC(name, i, j, k) \
template<> quat quat::fromeuler_##name(vec3 const &v) \
{ \
return quat_fromeuler_generic(v, i, j, k); \
} \
\
template<> quat quat::fromeuler_##name(float phi, float theta, float psi) \
{ \
return quat::fromeuler_##name(vec3(phi, theta, psi)); \
}

template<> quat quat::fromeuler_zyx(float phi, float theta, float psi)
{
return quat::fromeuler_yxz(vec3(phi, theta, psi));
}
QUAT_FROMEULER_GENERIC(xyx, 0, 1, 0)
QUAT_FROMEULER_GENERIC(xzx, 0, 2, 0)
QUAT_FROMEULER_GENERIC(yxy, 1, 0, 1)
QUAT_FROMEULER_GENERIC(yzy, 1, 2, 1)
QUAT_FROMEULER_GENERIC(zxz, 2, 0, 2)
QUAT_FROMEULER_GENERIC(zyz, 2, 1, 2)

QUAT_FROMEULER_GENERIC(xyz, 0, 1, 2)
QUAT_FROMEULER_GENERIC(xzy, 0, 2, 1)
QUAT_FROMEULER_GENERIC(yxz, 1, 0, 2)
QUAT_FROMEULER_GENERIC(yzx, 1, 2, 0)
QUAT_FROMEULER_GENERIC(zxy, 2, 0, 1)
QUAT_FROMEULER_GENERIC(zyx, 2, 1, 0)

#undef QUAT_FROMEULER_GENERIC

template<> mat4 mat4::lookat(vec3 eye, vec3 center, vec3 up)
{


Зареждане…
Отказ
Запис