chinedufn / change-mat4-coordinate-system

Convert a 4x4 column major matrix from left handed to right handed coordinate system
0 stars 0 forks source link

facing opposite Z direction #1

Closed kevzettler closed 7 years ago

kevzettler commented 7 years ago

Hi @chinedufn so this isn't an issue with the change-mat4-coordinate module it works as advertised. This is a discussion and request for help with some relevant linear algebra.

i'm using this in my current pipeline and it does correctly flip the coordinate space from Z up to Z out. I'm using this on all the imported keyframe joint matrices. In a reducer like the one in blender-webgl-skinned-hot-reload-experiment

see:

mechSniperActions.actions = Object.keys(mechSniperActions.actions)
// Iterate over each action so that we can process the keyframe times
                                  .reduce(function (allActions, actionName) { 
                                    allActions[actionName] = Object.keys(mechSniperActions.actions[actionName])
                                    // Iterate over each keyframe time so that we can process the world bone space pose matrices
                                                                   .reduce(function (allKeyframes, keyframeTime) {
                                                                     allKeyframes[keyframeTime] = mechSniperActions.actions[actionName][keyframeTime]
                                                                     // Iterate over the matrices so that we can multiply them by inverse bind, and transpose
                                                                     // (transpose because they came from Blender which uses row major)
                                                                     // After fixing up our matrices we turn them into dual quaternions
                                                                                                          .map(function (matrix, index) {
                                                                                                            mat4.multiply(matrix, mechSniperActions.inverseBindPoses[index], matrix)
                                                                                                            mat4.transpose(matrix, matrix)
                                                                                                            matrix = changeMat4CoordinateSystem.rightToLeft(matrix);
                                                                                                            matrix = mat4ToDualQuat(matrix)
                                                                                                            return matrix
                                                                                                          })

                                                                     return allKeyframes
                                                                   }, {})

                                    return allActions
                                  }, {});

My problem now is that the keyframe joint matrices I apply this too are facing the opposite Z direction than the Mesh i'm binding to the keyframes.

I discovered this by binding the Left side limb Meshes to the Right side joints and saw that the transformations started looking correct, but opposite. You can kind of see this below.

botwalk

So I essentially need to reflect all the keyframe joint matrices into the opposite direction. I'm not sure how to do this and hitting the limits of my current linear algebra skills.

I attempted to insert an additional rotation Y axis rotation Quaternion into this module

  const yRotate = quat.fromEuler([], 0, 180, 0);
  quat.add(handRotationQuat, handRotationQuat, yRotate);

at https://github.com/chinedufn/change-mat4-coordinate-system/blob/master/change-mat4-coordinate-system.js#L28

But that unexpectedly distorted everything distort

Worst case scenario I guess I could rotate all my mesh imports 180 degress around the Y to match the Joint directions, but that would require revamping my current camera setup as well. Any ideas are much appreciated.

chinedufn commented 7 years ago

So if I'm understanding correctly, everything was exported properly but your mesh just so happens to be facing the opposite direction? Trying to understand whether this is an expected issue or not.


Aside from them - It sounds like you want to reflect your transformations about the Z axis. This is different from rotating them 180 degrees about the Y axis.

A 180 degrees y rotation would take something that was pointing north east and make it point south west.

While a reflection about the Z axis would take something pointing northeast and make it point south east. Which is what it sounds like you want here?

kevzettler commented 7 years ago

Aside from them - It sounds like you want to reflect your transformations about the Z axis. This is different from rotating them 180 degrees about the Y axis.

Correct this is the desired result, a reflection

kevzettler commented 7 years ago

Ok here's a recap of the situation. I'm going to isolate the code to the inner map function that modifies the joint key frame matrices. The initial setup I had was:

mat4.multiply(matrix, mechSniperActions.inverseBindPoses[index], matrix)
mat4.transpose(matrix, matrix)
matrix = changeMat4CoordinateSystem.rightToLeft(matrix);
matrix = mat4ToDualQuat(matrix)
return matrix

this produced the following: broken

Like I mentioned in the first post of this thread. I confirmed that the joints were facing the opposite Z direction than the mesh.

I then created a reflection matrix

const zReflection = mat4.identity([]);
zReflection[0] = -1;  
zReflection[10] = -1; 

and added that to the inner map like

mat4.multiply(matrix, mechSniperActions.inverseBindPoses[index], matrix)
mat4.transpose(matrix, matrix)
matrix = changeMat4CoordinateSystem.rightToLeft(matrix);
mat4.multiply(matrix, matrix, zReflection);
matrix = mat4ToDualQuat(matrix)
return matrix

This gave me: backwards

The joints had been corrected however the entire mesh was now reflected as well. This took me a while to resolve and I'm not sure what happened. I updated the inner loop with another mat4 multiply:

mat4.multiply(matrix, mechSniperActions.inverseBindPoses[index], matrix)
mat4.transpose(matrix, matrix)
matrix = changeMat4CoordinateSystem.rightToLeft(matrix);
mat4.multiply(matrix, matrix, zReflection);
mat4.multiply(matrix, zReflection, matrix);
matrix = mat4ToDualQuat(matrix)
return matrix

Which I guess reverse the reflection? but doesn't undo the joint?

corrected

I'm not entirely sure whats going on but it works!

kevzettler commented 7 years ago

Again I don't think this is an issue with the change-mat4-coordinate-system it just seems that Blender and Qubicle were facing the forward/back axis in opposite directions.

chinedufn commented 7 years ago

Ah thank you so much for this detail

I'm thinking you can try z reflecting not only the pose matrix but also z reflect the inverse bind poses

I'm thinking that'll then prevent your mesh from getting turned around. Could be wrong but at a quick glance that looks like the issue

chinedufn commented 7 years ago

Since you're not reflecting your bind you are still binding your mesh onto the bones backwards

So yeah just multiplying each inverse bind matrix and then also multiplying the pose matrix by your z reflection before doing anything else might do the trick here

chinedufn commented 7 years ago

OH WAIT NEVERMIND, just realizing that your solution already works for you

NICE!

chinedufn commented 7 years ago

woohoo pumped that you figured it out!! yeah does seem like they Qubicle may just have a reversed Z axis