# Quaternion rotation around center, undefined behavior

Here's my code:

vec4 qx, qy, qz;
mat4 mx, my, mz;

// rotating using quaternions

// turning the quaternions into matrices
glm_quat_mat4(qx, mx);
glm_quat_mat4(qy, my);
glm_quat_mat4(qz, mz);

mat4 trans = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};

mat4 rot = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
};

mat4 final;

// combining the rotations into one.
glm_mat4_mulN((mat4* []){&mx, &my, &mz}, 3, rot);

// translating the trans matrix.
glm_translate(trans, (vec3){ a->x, a->y, a->z });

// finally combining the translation with the rotation into one.
glm_mat4_mul(trans, rot, final);


My desired behavior is that the object rotates around its center, but here is what happens instead:

So , it seems that my object is rotating around some weird other undefined point. I have no idea why this happens.

Any ideas? Thank you.

• You applied the rotation and translation in the wrong order. To rotate an object around its center its center has to be at the origin (0,0,0). Note that multiplication of matrices is not commutative. In general: A·B != B·A Commented Jun 7, 2019 at 10:29
• @Socowi But when I change the order, then the Z axis becomes the Y axis, and my translation becomes messed up Commented Jun 7, 2019 at 10:31

## For similar questions;

cglm povides a few pe-defined rotation APIs (new more APIs may be added in the future if needed):

• rotate vector using axis/angle

glm_vec3_rotate(vec3 v, float angle, vec3 axis)

• apply rotation matrix to vectoo

glm_vec3_rotate_[m4 | m3](mat4 m, vec3 v, vec3 dest)

• rotate vector using quaternion

glm_quat_rotatev(versor q, vec3 v, vec3 dest)

• rotate existing transform matrix using quaternion

glm_quat_rotate(mat4 m, versor q, mat4 dest)

• rotate existing transform matrix using quaternion at pivot point

glm_quat_rotate_at(mat4 m, versor q, vec3 pivot)

• rotate NEW transform matrix using quaternion at pivot point

glm_quat_rotate_atm(mat4 m, versor q, vec3 pivot)

• rotate existing transform matrix around given axis by angle

glm_rotate(mat4 m, float angle, vec3 axis)

• rotate existing transform around given axis by angle at given pivot point (rotation center)

glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis)

• creates NEW rotation matrix by angle and axis at given point

glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis)

• rotate existing transform matrix around X axis by angle and store result in dest

glm_rotate_[x|y|z](mat4 m, float angle, mat4 dest)

• 2D: creates NEW rotation matrix by angle around Z axis

glm_rotate2d_make(mat3 m, float angle)

• 2D: rotate existing 2d transform matrix around Z axis by angle and store result in same matrix

glm_rotate2d(mat3 m, float angle)

• 2D: rotate existing 2d transform matrix around Z axis by angle and store result in dest

glm_rotate2d_to(mat3 m, float angle, mat3 dest)

• Euler Angles APIs (this will be updated)

CGLM_INLINE void glm_euler_angles(mat4 m, vec3 dest);
CGLM_INLINE void glm_euler(vec3 angles, mat4 dest);
CGLM_INLINE void glm_euler_xyz(vec3 angles, mat4 dest);
CGLM_INLINE void glm_euler_zyx(vec3 angles, mat4 dest);
CGLM_INLINE void glm_euler_zxy(vec3 angles, mat4 dest);
CGLM_INLINE void glm_euler_xzy(vec3 angles, mat4 dest);
CGLM_INLINE void glm_euler_yzx(vec3 angles, mat4 dest);
CGLM_INLINE void glm_euler_yxz(vec3 angles, mat4 dest);
CGLM_INLINE void glm_euler_by_order(vec3         angles,
glm_euler_seq ord,
mat4         dest);

• using matrix, quaternion... to rotate manually... or _look[_at]() for view matrix maybe...

• ...

Knowing existing APIs may help a lot. _rotate_at() and rotate_atm() functions will help to rotate around a point. Othewise you need to the math manually (translate to origin then rotate then tanslate back...) the existing APIs are optimized and may be more optimized by time...

Also converting and combining matrices are redundant, instead multiplying quaternions will do the job and then the quat can be converted to rotation matrix.

Affine transformations use the following order:

1. Translate
2. Rotate
3. Scale

I'm not sure what version of glm you are using, but the code looks very strange.

In C++ terms, it should look something like this:

// rotating using quaternions
glm::vec3 x(1.0f,.0f,.0f);
glm::vec3 y(.0f,1.0f,.0f);
glm::vec3 z(.0f,.0f,1.0f);

glm::quat q(1.0f);

glm::mat4 ident(1.0f), final(1.0f);

glm::mat4 translate = glm::translate(ident, a->position);
glm::mat4 rotate = glm::toMat4(q); // Or something like that
glm::mat4 scale = glm::scale(glm::mat4(1.0f), a->scale);

final = scale * rotate * translate * ident; // In code order is right to left.


The above code is using the current glm API, so I can only assume you are either using a very old version, or are intentionally abstracting the actual glm calls. In any case:

1. Order matters. To rotate around a point, rotate first, then translate. To rotate around the centre of the object translate first, then rotate: AB != BA. Read https://en.wikipedia.org/wiki/Affine_transformation for more information.

2. Resource Acquisition Is Initialization(RAII): ALWAYS initialize your matrices to the identity matrix values: GLM matrices are internally an array of floats, so when assigned, will just use whatever data happens to be in that memory at the time. If you're lucky, it will be zeroed. Don't count on that. In fact, follow RAII best practices and always initialize all your variables. It might seem tedious, but I guarantee you, as your code gets more complex, uninitialized numerical data will account for more than half your weird, hard to explain behavior. Read https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization for more information.