diff --git a/docs/source/affine.rst b/docs/source/affine.rst index c34921f..8eaf01c 100644 --- a/docs/source/affine.rst +++ b/docs/source/affine.rst @@ -5,6 +5,8 @@ affine transforms Header: cglm/affine.h +Initialize Transform Matrices +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Functions with **_make** prefix expect you don't have a matrix and they create a matrix for you. You don't need to pass identity matrix. @@ -15,6 +17,96 @@ before sending to transfrom functions. There are also functions to decompose transform matrix. These functions can't decompose matrix after projected. +Rotation Center +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Rotating functions uses origin as rotation center (pivot/anchor point), +since scale factors are stored in rotation matrix, same may also true for scalling. +cglm provides some functions for rotating around at given point e.g. +**glm_rotate_at**, **glm_quat_rotate_at**. Use them or follow next section for algorihm ("Rotate or Scale around specific Point (Pivot Point / Anchor Point)"). + +Rotate or Scale around specific Point (Anchor Point) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you want to rotate model around arbibtrary point follow these steps: + +1. Move model from pivot point to origin: **translate(-pivot.x, -pivot.y, -pivot.z)** +2. Apply rotation (or scaling maybe) +3. Move model back from origin to pivot (reverse of step-1): **translate(pivot.x, pivot.y, pivot.z)** + +**glm_rotate_at**, **glm_quat_rotate_at** and their helper functions works that way. + +Transforms Order +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is important to understand this part especially if you call transform +functions multiple times + +`glm_translate`, `glm_rotate`, `glm_scale` and `glm_quat_rotate` and their +helpers functions works like this (cglm may provide reverse order too as alternative in the future): + +.. code-block:: c + :linenos: + + TransformMatrix = TransformMatrix * TraslateMatrix; // glm_translate() + TransformMatrix = TransformMatrix * RotateMatrix; // glm_rotate(), glm_quat_rotate() + TransformMatrix = TransformMatrix * ScaleMatrix; // glm_scale() + +As you can see it is multipled as right matrix. For instance what will happen if you call `glm_translate` twice? + +.. code-block:: c + :linenos: + + glm_translate(transform, translate1); /* transform = transform * translate1 */ + glm_translate(transform, translate2); /* transform = transform * translate2 */ + glm_rotate(transform, angle, axis) /* transform = transform * rotation */ + +Now lets try to understand this: + +1. You call translate using `translate1` and you expect it will be first transform +because you call it first, do you? + +Result will be **`transform = transform * translate1`** + +2. Then you call translate using `translate2` and you expect it will be second transform, really? + +Result will be **`transform = transform * translate2`**. Now lets expand transform, +it was `transform * translate1` before second call. + +Now it is **`transform = transform * translate1 * translate2`**, now do you understand what I say? + +3. After last call transform will be: + +**`transform = transform * translate1 * translate2 * rotation`** + +The order will be; **rotation will be applied first**, then **translate2** then **translate1** + +It is all about matrix multiplication order. It is similar to MVP matrix: +`MVP = Projection * View * Model`, model will be applied first, then view then projection. + +**Confused?** + +As alternative way, you can create transform matrices individually then combine manually, +but don't forget that `glm_translate`, `glm_rotate`, `glm_scale`... are optimized and should be faster (an smaller assembly output) than manual multiplication + +.. code-block:: c + :linenos: + + mat4 transform1, transform2, transform3, finalTransform; + + glm_translate_make(transform1, translate1); + glm_translate_make(transform2, translate2); + glm_rotate_make(transform3, angle, axis); + + /* first apply transform1, then transform2, thentransform3 */ + glm_mat4_mulN((mat4 *[]){&transform3, &transform2, &transform1}, 3, finalTransform); + + /* if you don't want to use mulN, same as above */ + glm_mat4_mul(transform3, transform2, finalTransform); + glm_mat4_mul(finalTransform, transform1, finalTransform); + +Now transform1 will be applied first, then transform2 then transform3 + Table of contents (click to go): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -38,6 +130,8 @@ Functions: #. :c:func:`glm_rotate_make` #. :c:func:`glm_rotate_ndc` #. :c:func:`glm_rotate` +#. :c:func:`glm_rotate_at` +#. :c:func:`glm_rotate_atm` #. :c:func:`glm_decompose_scalev` #. :c:func:`glm_uniscaled` #. :c:func:`glm_decompose_rs` @@ -204,6 +298,29 @@ Functions documentation | *[in]* **angle** angle (radians) | *[in]* **axis** axis +.. c:function:: void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis) + + rotate existing transform around given axis by angle at given pivot point (rotation center) + + Parameters: + | *[in, out]* **m** affine transfrom + | *[in]* **pivot** pivot, anchor point, rotation center + | *[in]* **angle** angle (radians) + | *[in]* **axis** axis + +.. c:function:: void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis) + + | creates NEW rotation matrix by angle and axis at given point + | this creates rotation matrix, it assumes you don't have a matrix + + | this should work faster than glm_rotate_at because it reduces one glm_translate. + + Parameters: + | *[in, out]* **m** affine transfrom + | *[in]* **pivot** pivot, anchor point, rotation center + | *[in]* **angle** angle (radians) + | *[in]* **axis** axis + .. c:function:: void glm_decompose_scalev(mat4 m, vec3 s) decompose scale vector diff --git a/docs/source/quat.rst b/docs/source/quat.rst index ab99838..d9b4680 100644 --- a/docs/source/quat.rst +++ b/docs/source/quat.rst @@ -56,6 +56,9 @@ Functions: #. :c:func:`glm_quat_for` #. :c:func:`glm_quat_forp` #. :c:func:`glm_quat_rotatev` +#. :c:func:`glm_quat_rotate` +#. :c:func:`glm_quat_rotate_at` +#. :c:func:`glm_quat_rotate_atm` Functions documentation ~~~~~~~~~~~~~~~~~~~~~~~ @@ -354,3 +357,24 @@ Functions documentation | *[in]* **m** existing transform matrix to rotate | *[in]* **q** quaternion | *[out]* **dest** rotated matrix/transform + +.. c:function:: void glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) + + | rotate existing transform matrix using quaternion at pivot point + + Parameters: + | *[in, out]* **m** existing transform matrix to rotate + | *[in]* **q** quaternion + | *[in]* **pivot** pivot + +.. c:function:: void glm_quat_rotate(mat4 m, versor q, mat4 dest) + + | rotate NEW transform matrix using quaternion at pivot point + | this creates rotation matrix, it assumes you don't have a matrix + + | this should work faster than glm_quat_rotate_at because it reduces one glm_translate. + + Parameters: + | *[in, out]* **m** existing transform matrix to rotate + | *[in]* **q** quaternion + | *[in]* **pivot** pivot diff --git a/include/cglm/affine.h b/include/cglm/affine.h index a5abbb6..f855399 100644 --- a/include/cglm/affine.h +++ b/include/cglm/affine.h @@ -25,6 +25,8 @@ CGLM_INLINE void glm_rotate_make(mat4 m, float angle, vec3 axis); CGLM_INLINE void glm_rotate_ndc(mat4 m, float angle, vec3 axis); CGLM_INLINE void glm_rotate(mat4 m, float angle, vec3 axis); + CGLM_INLINE void glm_rotate_at(mat4 m, vec3 pivot, float angle, vec3 axis); + CGLM_INLINE void glm_rotate_atm(mat4 m, vec3 pivot, float angle, vec3 axis); CGLM_INLINE void glm_decompose_scalev(mat4 m, vec3 s); CGLM_INLINE bool glm_uniscaled(mat4 m); CGLM_INLINE void glm_decompose_rs(mat4 m, mat4 r, vec3 s); @@ -521,7 +523,7 @@ glm_decompose_scalev(mat4 m, vec3 s) { } /*! - * @brief returns true if matrix is uniform scaled. This is helpful for + * @brief returns true if matrix is uniform scaled. This is helpful for * creating normal matrix. * * @param[in] m m diff --git a/include/cglm/quat.h b/include/cglm/quat.h index 1139c1d..d1da27f 100644 --- a/include/cglm/quat.h +++ b/include/cglm/quat.h @@ -757,14 +757,14 @@ glm_quat_rotate(mat4 m, versor q, mat4 dest) { */ CGLM_INLINE void -glm_quat_rotate_at(mat4 model, versor q, vec3 pivot) { +glm_quat_rotate_at(mat4 m, versor q, vec3 pivot) { vec3 pivotInv; glm_vec_inv_to(pivot, pivotInv); - glm_translate(model, pivot); - glm_quat_rotate(model, q, model); - glm_translate(model, pivotInv); + glm_translate(m, pivot); + glm_quat_rotate(m, q, m); + glm_translate(m, pivotInv); } /*!