chinedufn / blender-actions-to-json

Write the joint data for all of a `.blend` file's actions to a JSON file
17 stars 8 forks source link

Deprecate in favor of new landon repo #6

Open chinedufn opened 5 years ago

chinedufn commented 5 years ago

landon is where I plan to continue to add support for exporting more and more data from Blender.

As of right now landon exports armature JSON - so I'd like to deprecate this library in favor of it.

@kevzettler can you describe exactly how you use blender-actions-to-json?

From there I can ensure that landon is just as easy or easier for you to use - and then once that goal is met blender-actions-to-json can be deprecated.

Basically I'll make whatever CLI or API changes (even if that means exposing something to be able to be easily called from Node.js with 0 Rust experience) that are necessary for you to migrate - just need to have a better understanding of your current process!

chinedufn commented 5 years ago

(I'm talking just about the exporting of Blender armature data)

kevzettler commented 5 years ago

Hi @chinedufn !

my workflow with blender-actions-to-json is as follows

I run the blender export like:

blender --background assets/WiP-punch.blend --python `actions2json` -- src/assets/mechsniper-actions.json

I then have a mechsniper-actions.js file which imports and wraps the mechsniper-actions.json output

import { mat4 } from 'gl-matrix';
import mat4ToDualQuat from 'mat4-to-dual-quat';
import changeMat4CoordinateSystem from 'change-mat4-coordinate-system';

const mechSniperActions = require('./mechsniper-actions.json');
const zReflection = mat4.identity([]);
zReflection[0] = -1; //x
zReflection[10] = -1; //z

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);
            mat4.multiply(matrix, matrix, zReflection);
            mat4.multiply(matrix, zReflection, matrix);
            matrix = mat4ToDualQuat(matrix)
            return matrix
          })

        return allKeyframes
      }, {})

    return allActions
  }, {});

//Convert Blender JointNames to match Qubicle Chunk names Foot.R -> FootR
Object.keys(mechSniperActions.jointNameIndices).forEach((jointName) => {
  if(jointName.match(/\./)){
    var newName = jointName.replace('.', '');
    mechSniperActions.jointNameIndices[newName] = mechSniperActions.jointNameIndices[jointName];
    delete mechSniperActions.jointNameIndices[jointName]
  }
});

//Sekeltal animation system was crapping out when only one key frame
// this might be fixed
mechSniperActions.actions.pose['0.041667'] = mechSniperActions.actions.pose['0.0'];

export default mechSniperActions;

I'm not 100% sure what this .js wrapper is doing. I believe its doing some massaging to satisfy https://github.com/chinedufn/skeletal-animation-system

chinedufn commented 5 years ago

Ahh perfect thanks.

Right now the landon CLI writes everything to stdout so I'd just have to supply a way to write to a file.

kevzettler commented 5 years ago

@chinedufn following up here...

The landon action export format differs significantly from the blender-actions-to-json format heres side by side comparison with blender-actions-to-json on the left and landon on the right.

Screenshot 2019-09-17 18 21 45

I can compensate for this format difference by updating the mechsniper-actions.js wrapper file I have with some code like

//
// Convert from landon format to skeletal-animation format
//
mechSniperActions.actions = Object.keys(mechSniperActions.actions)
      .reduce((allActions, actionName) => {
        allActions[actionName] = mechSniperActions.actions[actionName].reduce((keyframeMap, landonKeyFrameObject) => {
          keyframeMap[landonKeyFrameObject.frame_time_secs] = landonKeyFrameObject.bones.map((boneCollection) => boneCollection.Matrix);
          return keyframeMap;
        }, {});
        return allActions;
      }, {});

mechSniperActions.inverseBindPoses = mechSniperActions.inverse_bind_poses.map((ivp) => ivp.Matrix);
delete mechSniperActions.inverse_bind_poses;

mechSniperActions.jointNameIndices = mechSniperActions.joint_index;
delete mechSniperActions.joint_index;

This might work but I am having other issues mentioned at: https://github.com/chinedufn/landon/issues/6