Collada translation matrix problem

Hi i just did a collada parser,first of all i just rendered each transformation matrix of each frame(without blending) and the animation looks perfect,now i was trying to implement blending,so i’ve extracted the quat rotation from the top left 3x3 of the node matrix and the position vec3 from the last row of the matrix(last row cause i transposed the matrix from the collada),and each frame i just interpolate the 2 frames value but the bones position just go randomly around,now what i’m doing is just this ->

for (UINT16 a = 0;a< model_ptr->bone_count;++a)

      {

        VEC3 vec_pos = {0.0f,0.0f,0.0f};

        vec3_interpolate(vec_pos,model_ptr->bone[a].anim[anim_id].position[model_ptr->frame_id],model_ptr->bone[a].anim[anim_id].position[model_ptr->frame_id + 1],model_ptr->progression);

        MAT4 temp_pos_mat;  

        mat4_init(temp_pos_mat);       

        mat4_translate(temp_pos_mat,vec_pos); 

        QUAT quat_rotation = {0.0f,0.0f,0.0f,0.0f}; 

        quat_interpolate(quat_rotation,model_ptr->bone[a].anim[anim_id].rotation[model_ptr->frame_id],model_ptr->bone[a].anim[anim_id].rotation[model_ptr->frame_id + 1],model_ptr->progression);

        

        for(UINT16 k = 0;k<3;++k)

        {

        printf("POSITION OF FRAME %d = %f\n",model_ptr->frame_id,model_ptr->bone[a].anim[anim_id].position[model_ptr->frame_id][k]);

        

        }

        MAT4 temp_quat_mat; 

        mat4_init(temp_quat_mat);

        mat4_from_quat(temp_quat_mat,quat_rotation);

        mat4_clear(model_ptr->bone[a].current_local);  

        mat4_multiply(model_ptr->bone[a].current_local,temp_pos_mat,temp_quat_mat);

      }

i’m using blender to export my models,and i found out that the animation doesn’t render properly if for example i don’t move a bone in the animation or the animation is in the first or last frame(where the bones are in the rest pose),i export all keyframes also while bones don’t have any transformation to make the parse easier,so i think basically the position in the translation matrix if the bones don’t have transform is not correct,but it’s been a week trying everything i can’t simply find a way to get the correct positions,i hope someone here that maybe encountered this problem too can help me cause i’m desperate hugs

wouldn’t the 3x3 rotation be displaced in the matrix, like the position … that you pick the wrong rotation. If the transpose mirrors data in the diagonal, the rotate needs a transpose back.
It doesn’t sound like the error you look for though.

well it shouldn’t be displaced,also there is always an empty column with 0 0 0 1 value, so like my matrix is like this -> rot rot rot 0
rot rot rot 0
rot rot rot 0
pos pos pos 1

also these matrices render correctly each frame,but i’m not a math guru,maybe i’m missing something,are these rotation values in eulers? and i must put them in quaternions?in blender i just used quaternions …btw some frames like i said have correct blending so i’m really confused right now …i’ve also followed the thinmatrix tutorial and he just takes directly quaternions and positions from their local matrices i really have no clue xd
ah ps: i’ve already tried to transpose everything ,i tried many times every different approach that came in my mind but nothing to do

matrices…

You must transpose COLLADA matrices since they are column-major in spec and row-major in file for readability.

are these rotation values in eulers?

They are just rotation matrices (not quaternions) which can be constructed by quaternion, euler angles, axis angles…

and i must put them in quaternions?

You can convert rotations to quaternion but you don’t need/have to. There are many tutorials out there and each one may used a different approach…


i can’t simply find a way to get the correct positions

I was tried to answer similar question (I guess) at stackoverflow which you may want to read (c++ - How do I calculate a COLLADA file's parent and children joint transforms? - Stack Overflow)

After read that answer, please ask any question if you have any


Also make sure that your math calculations are correct. If you use C than I suggest to use cglm (GitHub - recp/cglm: 📽 Highly Optimized Graphics Math (glm) for C) which is highly optimized (probably fastest) and easy-to use math library, it contains lot of features (struct api, array api, inline, library-call, helpers…)

hi thank you for the reply,i already did all of that and i’m able to display each frame transform (using directly the collada matrix),the problem i’m having is decomposing this matrix and blending 2 frames; i already checked all the maths i used and there are no errors i mean i used as reference the euclideanspace site
and i checked my functions results with their app

i show you some code of my implementation:
this is where i transpose the matrices(i mean i directly put them in column major)

for(UINT16 a = 0;a < model_ptr->bone_count; ++a)

   {      

      mat_array_index = 0;

      for(UINT16 b = 0;b < model_ptr->animation_count;++b)

      {   

        model_ptr->bone[a].anim[b].bone_local_matrix = (MAT4*)malloc(sizeof(MAT4)*model_ptr->bone[a].anim[b].frame_count);

        for(UINT16 c = 0;c < model_ptr->bone[a].anim[b].frame_count;++c)

        {             

            for (UINT16 r1 = 0;r1<4;++r1)

            {

               for(UINT16 r2 = 0;r2<4;++r2)

               {                  

                  model_ptr->bone[a].anim[b].bone_local_matrix[c][r2][r1] = parser_ptr->mat_array[a][mat_array_index];

                  printf("MATRIX BONE %d NUM %d  = %f \n",a,c,model_ptr->bone[a].anim[b].bone_local_matrix[c][r2][r1]);

                  mat_array_index++;                       

               }

            }

                  

        }

      }       

   }

and this is how i calculate the global transform matrix of each bone(i already did a bone map but now i’m trying to blending and calculate the local transform so i hardcoded a little to have the steps clear),also i’m using 4 bones to keep stuffs simple and each bone is child of the previous one so no tree for now :smiley:

MAT4 global0;

  MAT4 global1;

  MAT4 global2;

  MAT4 global3;

  mat4_init(global0);

  mat4_init(global1);

  mat4_init(global2);

  mat4_init(global3);  

  

  mat4_multiply(global0,model_ptr->identity,model_ptr->bone[0].anim[0].bone_local_matrix[frame]);

  mat4_multiply(bot_bones->final_transform[0],global0,model_ptr->bone[0].inverse_model_space_bind_transform);

  

  mat4_multiply(global1,global0,model_ptr->bone[1].anim[0].bone_local_matrix[frame]);

  mat4_multiply(bot_bones->final_transform[1],global1,model_ptr->bone[1].inverse_model_space_bind_transform);

  

  mat4_multiply(global2,global1,model_ptr->bone[2].anim[0].bone_local_matrix[frame]);

  mat4_multiply(bot_bones->final_transform[2],global2,model_ptr->bone[2].inverse_model_space_bind_transform);

  mat4_multiply(global3,global2,model_ptr->bone[3].anim[0].bone_local_matrix[frame]);

  mat4_multiply(bot_bones->final_transform[3],global3,model_ptr->bone[3].inverse_model_space_bind_transform);

for the math i have only an header where i put functions that i do myself or that i find online,for the quaternion math i took a function from linmath library and for the interpolations i followed the previous site,but i repeat i checked thousand of times the math with different matrices and the result compared with the site are correct…so the problem now can be

  1. i’m extrapolating the wrong values from the bone_local_matrix -> i repeat my matrix is already transposed like you see in the function so if in the collada there is 1 2 3 4 5 6 7 8 etc
    in my matrix they are 1 5 9 13 etc
  2. i’m missing some step during blending
  3. my math is wrong and i’m blind

so to be complete i post you also the other functions where maybe someone will see mistakes :smiley:

quaternion math (copied by linmath library)

static inline void quat_from_mat4(QUAT q, MAT4 M) 

{

    float r = 0.f;

    int i;

    int perm[] = {0, 1, 2, 0, 1};

    int *p = perm;

    for (i = 0; i < 3; i++) {

        float m = M[i][i];

        if (m < r) continue;

        m = r;

        p = &perm[i];

    }

    r = sqrtf(1.f + M[p[0]][p[0]] - M[p[1]][p[1]] - M[p[2]][p[2]]);

    if (r < 1e-6) {

        q[0] = 1.f;

        q[1] = q[2] = q[3] = 0.f;

        return;

    }

    q[0] = r / 2.f;

    q[1] = (M[p[0]][p[1]] - M[p[1]][p[0]]) / (2.f * r);

    q[2] = (M[p[2]][p[0]] - M[p[0]][p[2]]) / (2.f * r);

    q[3] = (M[p[2]][p[1]] - M[p[1]][p[2]]) / (2.f * r);

} 

static inline void quat_interpolate(QUAT output,QUAT quat_1,QUAT quat_2, FLOAT progression)

{

    

  output[0] = 0.0f; 

  output[1] = 0.0f; 

  output[2] = 0.0f; 

  output[3] = 1.0f; 

  FLOAT dot = (quat_1[0] * quat_2[0]) + (quat_1[1] * quat_2[1]) + (quat_1[2] * quat_2[2]) + (quat_1[3] * quat_2[3]); 

  FLOAT k = 1.0f - progression;

  if (dot < 0)

  {

    output[0] = (k * quat_1[0]) + (progression * (-quat_2[0]));

    output[1] = (k * quat_1[1]) + (progression * (-quat_2[1]));

    output[2] = (k * quat_1[2]) + (progression * (-quat_2[2]));

    output[3] = (k * quat_1[3]) + (progression * (-quat_2[3]));

  }

  else

  {

    output[0] = (k * quat_1[0]) + (progression * quat_2[0]);

    output[1] = (k * quat_1[1]) + (progression * quat_2[1]);

    output[2] = (k * quat_1[2]) + (progression * quat_2[2]);

    output[3] = (k * quat_1[3]) + (progression * quat_2[3]);

  }

  vec4_normalize(output);

}

and the last vec3 

static inline void  vec3_interpolate(VEC3 output,VEC3 vec_1,VEC3 vec_2,FLOAT progression)

{

    FLOAT x = vec_1[0] + (vec_2[0] - vec_1[0]) * progression;

    FLOAT y = vec_1[1] + (vec_2[1] - vec_1[1]) * progression;

    FLOAT z = vec_1[2] + (vec_2[2] - vec_1[2]) * progression;

    output[0] = x;

    output[1] = y;

    output[2] = z;

}

well i know it’s a lot of stuff and i won’t expect nothing,it’s just desperation :smiley: bye and thanks again

i already did all of that

Then you must be able to load and render COLLADA Skin Animations because I’m doing it as well and it works nice for me. :tada:

Maybe you have bugs in importer or maybe in renderer, you must validate both.


i’m using 4 bones to keep stuffs simple

I think 4 or 8 is common which is fine (especially for performance)

each bone is child of the previous one so no tree for now

global0, global1, global2, global3… I’m not sure which one is most parent. You must multiply parent with child to convert local transform of each node to root bode’s coordinate system. If the root bone is child of a node then you must also multiply with them until root node.

boneTransform1 = parentBoneTransform * boneLocalTransform1

Maybe you should check the parent-child matrix multiplication order (recursively). I mean if global0 is parent of global1 then;

try

mat4_multiply(global0,global1,model_ptr->bone[1].anim[0].bone_local_matrix[frame]);

instead of

mat4_multiply(global1,global0,model_ptr->bone[1].anim[0].bone_local_matrix[frame]);

EDIT:

I have guessed that mat4_multiply’s first parameter is left matrix, second one is right matrix and last one is destination. In C first param is out/destination in general but in cglm I’m using last param as destination/out…

hi yes first param is the output matrix in my case…:smiley: btw i meant that i can already render the matrices without blending so these multiplication must be correct,and last hour i did a little progress i could render one model animation properly (with blending) i checked again rotations and idk why i forgot to set last frame rotation to 0 0 0 1(cause i use like i said first frame and last frame as rest pose) but the bones were all on the same axes with the same rotation,now i’m trying to render another simple model with bones in different rotations and position but with no luck the model is like a reverse L and it gets distorted especially in the point where there is the last bone with different rotation from the others,also another strange stuff is that the model is rotated by -180 rad on the y,instead if i just sent directly the matrices everything look right and at his place(so the problem is not related to positions but to rotations at this point)…btw i feel like i’m close i will check again the interpolations every frame and if i find a solution i will post it here hugs

You may already know and already did but I must remind; COLLADA uses degrees for angles. Probably you use radians so you may forgot to convert degrees to radians? Angles in rotations, angles in key frames / samplers e.g. in tangent or out tangent… all must be converted to radians… You may already converted angles for rotations but may forgot for in/out tangents (animation samplers) or else…

No wait i didn’t any conversion :d and i use radians but how does this affect quaternions? which values should i convert? the 3x3 matrix?

We found a bug then :wink:

No need to convert rotation matrices, you must convert any explicit angle in COLLADA file, for instance:

  • Angles in <rotate> element (in node)
  • Angles in <source> which you access via accessor of animation samples. Check the accessor params and if you find any param named “ANGLE” then convert it to radians.
  • Angles in <falloff_angle> element (in light)
  • Angles in <skew> element (in node)
  • Angles in <yfov> element (in camera)
  • … and probably more

For animations you must find something like this:

...
<animation id="root.rotateX">
  <source>
    <float_array...
    <technique_common>
        <accessor source="#root.rotateX-..." count="26" stride="1">
            <param name="ANGLE" type="float"/>
        </accessor>
...

You must access source via accessor by using <param name="ANGLE" ...> parameter and convert angle to radians. There may be multiple params and you must access correct data by using accessor/params…

When initializing quaternions you probably use cosf() and sinf(). They are expecting radians so this is the relation between quaternion and radians. You may continue with degrees if you want, you just need to update initializing quaternion with degrees instead of radians, I guess.


FWIW, I’m using radians.

mmm i don’t have any of these,with blender i just output the rotlocscale of the frames as a matrix so i have this line for example:

<float_array id=“Armature_ArmatureAction_Bone_002_pose_matrix-output-array” count=“144”>0.9996496 0.02646583 7.34962e-8 -9.31323e-10 -0.02646583 0.9996497 -4.16366e-9 1.355464 -7.35806e-8 2.21706e-9 1 -2.22045e-16 0 0 0 1 0.9963862 0.08493727 7.34962e-8 2.23517e-8 -0.08493727 0.9963863 -4.16366e-9 1.355464 -7.35842e-8 -2.09396e-9 1 1.77636e-15 0 0 0 1 0.9770746 0.2128974 7.34962e-8 -2.98023e-8 -0.2128973 0.9770746 -4.16366e-9 1.355464 -7.26977e-8 -1.15789e-8 1 -3.55271e-15 0 0 0 1 0.9413999 0.3372922 7.34962e-8 0 -0.3372922 0.9414001 -4.16365e-9 1.355464 -7.05937e-8 -2.087e-8 1 0 0 0 0 1 0.9200416 0.3918209 6.09721e-8 -5.96046e-8 -0.3918209 0.9200416 -6.1642e-8 1.355464 -8.02495e-8 3.28231e-8 1 0 0 0 0 1 0.9414001 0.3372922 6.26352e-8 -5.96046e-8 -0.3372921 0.9414001 -6.2119e-8 1.355464 -7.9917e-8 3.73525e-8 1 3.55271e-15 0 0 0 1 0.9770746 0.2128974 6.6393e-8 -2.98023e-8 -0.2128973 0.9770746 -6.28232e-8 1.355464 -7.82458e-8 4.72481e-8 1 -7.10543e-15 0 0 0 1 0.9963862 0.0849373 7.02104e-8 2.23517e-8 -0.0849373 0.9963862 -6.30363e-8 1.355464 -7.53108e-8 5.6845e-8 1 0 0 0 0 1 0.9996496 0.02646583 7.34962e-8 -9.31323e-10 -0.02646583 0.9996497 -4.16366e-9 1.355464 -7.35806e-8 2.21706e-9 1 -2.22045e-16 0 0 0 1</float_array>

the count 144 is 16 floats * 9 frames
and i don’t have a camera neither lights or a skew node xd,and i don’t think quaternions are related to this btw i tried to convert the values from the mat3x3 to rad to be sure but the result was a lot worse,thank you anyway for the suggestion :smiley: now i go to search deeply about this :smiley:

That is your array/data but you must have accessor and param inside source/accessor. You must access the data with accessor (offset + stride) + param (offset + type)


see my previous comment.

yes i know but the rotation is inside these matrices wait i post you more :smiley:

    <source id="Armature_ArmatureAction_Bone_001_pose_matrix-input">

      <float_array id="Armature_ArmatureAction_Bone_001_pose_matrix-input-array" count="9">0 0.04166662 0.08333331 0.125 0.1666666 0.2083333 0.25 0.2916666 0.3333333</float_array>

      <technique_common>

        <accessor source="#Armature_ArmatureAction_Bone_001_pose_matrix-input-array" count="9" stride="1">

          <param name="TIME" type="float"/>

        </accessor>

      </technique_common>

    </source>

    <source id="Armature_ArmatureAction_Bone_001_pose_matrix-output">

      <float_array id="Armature_ArmatureAction_Bone_001_pose_matrix-output-array" count="144">0.9999308 -0.01176386 8.37649e-8 0 0.01176386 0.9999308 -5.005e-8 0.8564902 -8.31703e-8 5.1032e-8 1 0 0 0 0 1 0.9966182 0.0821733 8.37649e-8 3.72529e-9 -0.0821733 0.9966182 -5.005e-8 0.8564902 -8.75944e-8 4.29975e-8 1 0 0 0 0 1 0.9577146 0.2877202 8.37649e-8 -4.75328e-16 -0.2877202 0.9577146 -5.005e-8 0.8564903 -9.46233e-8 2.38328e-8 1 3.55271e-15 0 0 0 1 0.8768985 0.4806756 8.37649e-8 -7.55012e-16 -0.4806756 0.8768985 -5.005e-8 0.8564901 -9.75112e-8 3.62503e-9 1 0 0 0 0 1 0.8278933 0.5608855 6.93532e-8 2.98023e-8 -0.5608855 0.8278933 -9.80213e-8 0.8564903 -1.12396e-7 4.22519e-8 1 0 0 0 0 1 0.8768985 0.4806755 7.15498e-8 0 -0.4806755 0.8768985 -9.89413e-8 0.8564901 -1.10301e-7 5.23692e-8 1 3.55271e-15 0 0 0 1 0.9577145 0.2877201 7.66919e-8 4.98832e-16 -0.2877201 0.9577145 -1.00226e-7 0.8564902 -1.02286e-7 7.39221e-8 1 0 0 0 0 1 0.9966182 0.0821733 8.19889e-8 8.34516e-16 -0.0821733 0.9966182 -1.00413e-7 0.8564902 -8.99628e-8 9.33359e-8 1 0 0 0 0 1 0.9999308 -0.01176386 8.37649e-8 0 0.01176386 0.9999308 -5.005e-8 0.8564902 -8.31703e-8 5.1032e-8 1 0 0 0 0 1</float_array>

      <technique_common>

        <accessor source="#Armature_ArmatureAction_Bone_001_pose_matrix-output-array" count="9" stride="16">

          <param name="TRANSFORM" type="float4x4"/>

        </accessor>

      </technique_common>

    </source>

    <source id="Armature_ArmatureAction_Bone_001_pose_matrix-interpolation">

      <Name_array id="Armature_ArmatureAction_Bone_001_pose_matrix-interpolation-array" count="9">LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR LINEAR</Name_array>

      <technique_common>

        <accessor source="#Armature_ArmatureAction_Bone_001_pose_matrix-interpolation-array" count="9" stride="1">

          <param name="INTERPOLATION" type="name"/>

        </accessor>

      </technique_common>

    </source>

    <sampler id="Armature_ArmatureAction_Bone_001_pose_matrix-sampler">

      <input semantic="INPUT" source="#Armature_ArmatureAction_Bone_001_pose_matrix-input"/>

      <input semantic="OUTPUT" source="#Armature_ArmatureAction_Bone_001_pose_matrix-output"/>

      <input semantic="INTERPOLATION" source="#Armature_ArmatureAction_Bone_001_pose_matrix-interpolation"/>

    </sampler>

    <channel source="#Armature_ArmatureAction_Bone_001_pose_matrix-sampler" target="Armature_Bone_001/transform"/>

  </animation>

i can also output the rotlocscale decomposed in eulers but when i started the parser i wanted to use the transform matrix so if i want to change i should write thousand of lines now to get the values :confused:

Wow, you have matrix for each frame it is probably lot of data to store. You must decompose matrix into quaternion and translation then interpolation between two quaternion (slerp) and translation (lerp) is easy. And probably you must divide all columns to the element at 4x4 if it is not 1.0f before decompose.

Yes, in this case there are no explicit angles and must work without rad -> deg conversations. But if you are writing generic importer/parser then you must handle all cases…


I must implement interpolating between two matrices in cglm later like glm_mat4_lerp()

Hi again yes i checked everywhere and given a rotation matrix you should not have these kind of conversion problems with quaternions,about the data stored i think with a single matrix there are less elements to store but i have no clue about this,btw with slerp and lerp you made me remember a thing and i found a huge error in my math code,i was using nlerp, but i used vec4 normalize function to normalize my quaternion…how can i be so stupid :d i will try to normalize my quaternion i hope this is was the issue,i go to sleep soon btw thank you for all your support today,you were really kind <3 tomorrow i post if this was the issue bye

1 Like

nothing to do xd,btw i found an article about my same issue " Problem converting matrix to quaternion and back" but my transformation matrices are orthonormal so i should not have problems…now i’m rewriting all the functions trying to understand better what’s happening in every step i will let you know bye <3

Ok i solved it,there was an error in my math after a day spent debugging every value i found out that the quat functions of the linmath header were wrong i post here the functions that are working for me if you want to use them in your library or someone else need them (i copied them basically from the euclideanspace site ) i repeat you must use nlerp and be sure that the rotation matrices that you are using are orthonormal so :

static inline void quat_from_mat4(QUAT output, MAT4 matrix) 
{

   

    FLOAT trace = matrix[0][0] + matrix[1][1] + matrix[2][2];

    if( trace > 0 ) 

    {

      FLOAT s = 0.5f / sqrtf(trace+ 1.0f);

      output[3] = 0.25f / s;

      output[0] = ( matrix[2][1] - matrix[1][2] ) * s;

      output[1] = ( matrix[0][2] - matrix[2][0] ) * s;

      output[2] = ( matrix[1][0] - matrix[0][1] ) * s;

    } 

    else 

    {

      if ( matrix[0][0] > matrix[1][1] && matrix[0][0] > matrix[2][2] ) 

      {

        FLOAT s = 2.0f * sqrtf( 1.0f + matrix[0][0] - matrix[1][1] - matrix[2][2]);

        output[3] = (matrix[2][1] - matrix[1][2] ) / s;

        output[0] = 0.25f * s;

        output[1] = (matrix[0][1] + matrix[1][0] ) / s;

        output[2] = (matrix[0][2] + matrix[2][0] ) / s;

      } 

      else if (matrix[1][1] > matrix[2][2]) 

      {

        FLOAT s = 2.0f * sqrtf( 1.0f + matrix[1][1] - matrix[0][0] - matrix[2][2]);

       output[3] = (matrix[0][2] - matrix[2][0] ) / s;

       output[0] = (matrix[0][1] + matrix[1][0] ) / s;

       output[1] = 0.25f * s;

       output[2] = (matrix[1][2] + matrix[2][1] ) / s;

      }

      else 

      {

        FLOAT s = 2.0f * sqrtf( 1.0f + matrix[2][2] - matrix[0][0] - matrix[1][1] );

       output[3] = (matrix[1][0] - matrix[0][1] ) / s;

       output[0] = (matrix[0][2] + matrix[2][0] ) / s;

       output[1] = (matrix[1][2] + matrix[2][1] ) / s;

       output[2] = 0.25f * s;

      }

    }

}

static inline void mat4_from_quat(MAT4 output,QUAT quat_input)

{

    

        FLOAT xy = quat_input[0] * quat_input[1];

        FLOAT xz = quat_input[0] * quat_input[2];

        FLOAT xw = quat_input[0] * quat_input[3];

        FLOAT yz = quat_input[1] * quat_input[2];

        FLOAT yw = quat_input[1] * quat_input[3];

        FLOAT zw = quat_input[2] * quat_input[3];

        FLOAT xsqr = quat_input[0] * quat_input[0];

        FLOAT ysqr = quat_input[1] * quat_input[1];

        FLOAT zsqr = quat_input[2] * quat_input[2];

        output[0][0] = 1 - 2 * (ysqr + zsqr);

        output[0][1] = 2 * (xy - zw);

        output[0][2] = 2 * (xz + yw);

        output[0][3] = 0;

        output[1][0] = 2 * (xy + zw);

        output[1][1] = 1 - 2 * (xsqr + zsqr);

        output[1][2] = 2 * (yz - xw);

        output[1][3] = 0;

        output[2][0] = 2 * (xz - yw);

        output[2][1] = 2 * (yz + xw);

        output[2][2] = 1 - 2 * (xsqr + ysqr);

        output[2][3] = 0;

        output[3][0] = 0;

        output[3][1] = 0;

        output[3][2] = 0;

        output[3][3] = 1;

        

}

static inline void quat_nlerp(QUAT output,QUAT quat_1,QUAT quat_2, FLOAT progression)

{

    

  output[0] = 0.0f; 

  output[1] = 0.0f; 

  output[2] = 0.0f; 

  output[3] = 1.0f; 

  FLOAT trace = (quat_1[0] * quat_2[0]) + (quat_1[1] * quat_2[1]) + (quat_1[2] * quat_2[2]) + (quat_1[3] * quat_2[3]); 

  FLOAT k = 1.0f - progression;

  if (trace < 0)

  {

    output[0] = (k * quat_1[0]) + (progression * (-quat_2[0]));

    output[1] = (k * quat_1[1]) + (progression * (-quat_2[1]));

    output[2] = (k * quat_1[2]) + (progression * (-quat_2[2]));

    output[3] = (k * quat_1[3]) + (progression * (-quat_2[3]));

  }

  else

  {

    output[0] = (k * quat_1[0]) + (progression * quat_2[0]);

    output[1] = (k * quat_1[1]) + (progression * quat_2[1]);

    output[2] = (k * quat_1[2]) + (progression * quat_2[2]);

    output[3] = (k * quat_1[3]) + (progression * quat_2[3]);

  }

  quat_normalize(output);

}

bye thanks good life

Great! :tada:

I already implemented them in cglm which looks fine and similar. I had suggested it :slight_smile:
Thanks for sharing the math.

Glad to see that the issue is resolved.

:+1:

1 Like