6

I just started working with quaternions and noticed that the order of glm::quat elements are mixed. This is what I mean by this. If I declare a glm::quat like this

glm::quat quat = glm::quat(1, 2, 3, 4);

and then print the x,y,z,w like this

std::cout << quat.x << " " << quat.y << " " << quat.z << " " << quat.w;

it prints 2 3 4 1. Is this expected behavior? And if it is, what is the reason behind this?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Saik
  • 993
  • 1
  • 16
  • 40
  • With quaternions, w,x,y,z is no more or less correct than x,y,z,w. Or put another way, if you choose to print `quat.w` first, it is no longer "mixed". – Drew Dormann Jan 19 '18 at 19:52
  • Yes, so In my program, I just follow the order w,x,y,z instead or regular x,y,z,w (at least regular when I was working with vec4) and everything works out fine. I am just curious as to why this is done in such manner. – Saik Jan 19 '18 at 20:01
  • Ah. You are perhaps asking why `quat` and `vec4` chose _different_ orderings for variables that share the _same_ name. – Drew Dormann Jan 19 '18 at 21:44

1 Answers1

11

This is really frustrating. Various maths libs use different conventions, but GLM seems to be inconsistent even internally (at least as of early 2018).

The constructor glm::quat(...) is w, x, y, z:

quaternion.hpp:
GLM_FUNC_DECL GLM_CONSTEXPR tquat(T w, T x, T y, T z);

* beware empty constructors no longer initialize to the identity. See GLM_FORCE_CTOR_INIT. Could add to CFLAGS.

The internal order is x, y, z, w:

quaternion.hpp:
struct { T x, y, z, w;};

Using glm::make_quat simply does a memcpy, which is x, y, z, w:

type_ptr.inl:
memcpy(value_ptr(Result), ptr, sizeof(tquat<T, defaultp>));

Using glm::string_cast gives w, x, y, z:

string_cast.inl:

return detail::format(FormatStr.c_str(),
          static_cast<typename cast<T>::value_type>(x[3]),
          static_cast<typename cast<T>::value_type>(x[0]),
          static_cast<typename cast<T>::value_type>(x[1]),
          static_cast<typename cast<T>::value_type>(x[2]));

Note: The [] operator is return (&x)[i]; (which assumes x is first)

jozxyqk
  • 16,424
  • 12
  • 91
  • 180
  • Thank you for clarifying my frustration with quats better than I did :). This was exactly my problem. As a beginner in the field of 3D graphics, I suffered for about 6 hours because of those inconsistencies. I was trying to debug my program and was getting unexpected results because I had no clue that the constructor and the internal order place "W" component in different slots. – Saik Mar 24 '18 at 23:00
  • 1
    jozxyqk, just interested... did GLM stated somewhere that "empty constructors no longer initialize to the identity"? (This is a really important change that can cause big problems after migrating to the new GLM...) – Gediminas Jun 26 '18 at 17:51
  • 1
    @Gediminas yes. I had a small note about that and just expanded it to reference GLM_FORCE_CTOR_INIT. – jozxyqk Jun 26 '18 at 21:04