├── .gitignore ├── README.md ├── assets ├── body_mesh.ply ├── charuco_board.png ├── freemocap_logo.png └── readme.md ├── freemocap_adapter ├── README.md ├── __init__.py ├── addon_interface.py ├── assets │ ├── skelly_lowpoly_mesh.fbx │ └── skelly_parts_meshes │ │ ├── Skelly_f_index.01.L.fbx │ │ ├── Skelly_f_index.01.R.fbx │ │ ├── Skelly_f_index.02.L.fbx │ │ ├── Skelly_f_index.02.R.fbx │ │ ├── Skelly_f_index.03.L.fbx │ │ ├── Skelly_f_index.03.R.fbx │ │ ├── Skelly_f_middle.01.L.fbx │ │ ├── Skelly_f_middle.01.R.fbx │ │ ├── Skelly_f_middle.02.L.fbx │ │ ├── Skelly_f_middle.02.R.fbx │ │ ├── Skelly_f_middle.03.L.fbx │ │ ├── Skelly_f_middle.03.R.fbx │ │ ├── Skelly_f_pinky.01.L.fbx │ │ ├── Skelly_f_pinky.01.R.fbx │ │ ├── Skelly_f_pinky.02.L.fbx │ │ ├── Skelly_f_pinky.02.R.fbx │ │ ├── Skelly_f_pinky.03.L.fbx │ │ ├── Skelly_f_pinky.03.R.fbx │ │ ├── Skelly_f_ring.01.L.fbx │ │ ├── Skelly_f_ring.01.R.fbx │ │ ├── Skelly_f_ring.02.L.fbx │ │ ├── Skelly_f_ring.02.R.fbx │ │ ├── Skelly_f_ring.03.L.fbx │ │ ├── Skelly_f_ring.03.R.fbx │ │ ├── Skelly_foot.L.fbx │ │ ├── Skelly_foot.R.fbx │ │ ├── Skelly_forearm.L.fbx │ │ ├── Skelly_forearm.R.fbx │ │ ├── Skelly_hand.L.fbx │ │ ├── Skelly_hand.R.fbx │ │ ├── Skelly_head.fbx │ │ ├── Skelly_heel.02.L.fbx │ │ ├── Skelly_heel.02.R.fbx │ │ ├── Skelly_palm.01.L.fbx │ │ ├── Skelly_palm.01.R.fbx │ │ ├── Skelly_palm.02.L.fbx │ │ ├── Skelly_palm.02.R.fbx │ │ ├── Skelly_palm.03.L.fbx │ │ ├── Skelly_palm.03.R.fbx │ │ ├── Skelly_palm.04.L.fbx │ │ ├── Skelly_palm.04.R.fbx │ │ ├── Skelly_shin.L.fbx │ │ ├── Skelly_shin.R.fbx │ │ ├── Skelly_spine.fbx │ │ ├── Skelly_thigh.L.fbx │ │ ├── Skelly_thigh.R.fbx │ │ ├── Skelly_thumb.01.L.fbx │ │ ├── Skelly_thumb.01.R.fbx │ │ ├── Skelly_thumb.02.L.fbx │ │ ├── Skelly_thumb.02.R.fbx │ │ ├── Skelly_thumb.03.L.fbx │ │ ├── Skelly_thumb.03.R.fbx │ │ ├── Skelly_upper_arm.L.fbx │ │ └── Skelly_upper_arm.R.fbx ├── core_functions.py ├── data_definitions │ ├── __init__.py │ ├── anthropomorphic_dimensions.py │ ├── armatures │ │ ├── __init__.py │ │ ├── bone_name_map.py │ │ ├── freemocap.py │ │ └── ue_metahuman_simple.py │ ├── bone_constraints.py │ ├── empties_dict.py │ ├── foot_locking_markers.py │ ├── ik_control_bones.py │ ├── ik_pole_bones.py │ ├── interface │ │ ├── __init__.py │ │ ├── panels │ │ │ ├── __init__.py │ │ │ ├── add_armature_panel.py │ │ │ ├── add_body_mesh_panel.py │ │ │ ├── add_finger_rotation_limits_panel.py │ │ │ ├── adjust_empties_panel.py │ │ │ ├── apply_butterworth_filters_panel.py │ │ │ ├── apply_foot_locking_panel.py │ │ │ ├── export_fbx_panel.py │ │ │ ├── reduce_bone_length_dispersion_panel.py │ │ │ └── retarget_animation_panel.py │ │ └── properties │ │ │ ├── __init__.py │ │ │ ├── add_armature_properties.py │ │ │ ├── add_body_mesh_properties.py │ │ │ ├── add_finger_rotation_limits_properties.py │ │ │ ├── adjust_empties_properties.py │ │ │ ├── apply_butterworth_filters_properties.py │ │ │ ├── apply_foot_locking_properties.py │ │ │ ├── export_fbx_properties.py │ │ │ ├── property_types.py │ │ │ ├── reduce_bone_length_dispersion_properties.py │ │ │ └── retarget_animation_properties.py │ ├── poses │ │ ├── __init__.py │ │ ├── freemocap_apose.py │ │ ├── freemocap_tpose.py │ │ ├── ue_metahuman_default.py │ │ ├── ue_metahuman_realtime.py │ │ └── ue_metahuman_tpose.py │ ├── skelly_parts.py │ └── virtual_bones.py ├── io_scene_fbx_functions_blender3.py └── io_scene_fbx_functions_blender4.py ├── freemocap_video_export ├── README.md ├── __init__.py ├── addon_interface.py ├── assets │ ├── charuco_board.png │ └── freemocap_logo.png ├── classes.py ├── config_variables.py ├── freemocap_video_export_addon.zip └── functions.py ├── freemocap_visualizer ├── README.md ├── __init__.py ├── addon_interface.py ├── auxiliary_functions.py ├── data_definitions.py └── functions.py └── video_sync_script ├── README.md └── video_sync.py /.gitignore: -------------------------------------------------------------------------------- 1 | freemocap_video_export/__pycache__/functions.cpython-310.pyc 2 | freemocap_video_export/__pycache__/config_variables.cpython-310.pyc 3 | freemocap_video_export/__pycache__/classes.cpython-310.pyc 4 | freemocap_video_export/__pycache__/addon_interface.cpython-310.pyc 5 | freemocap_video_export/__pycache__/__init__.cpython-310.pyc 6 | freemocap_adapter/__pycache__/__init__.cpython-310.pyc 7 | .vscode/launch.json 8 | freemocap_tools.code-workspace 9 | freemocap_adapter/__pycache__/io_scene_fbx_functions_blender3.cpython-310.pyc 10 | freemocap_adapter/__pycache__/io_scene_fbx_functions_blender4.cpython-310.pyc 11 | freemocap_visualizer/__pycache__/__init__.cpython-310.pyc 12 | freemocap_visualizer/__pycache__/addon_interface.cpython-310.pyc 13 | freemocap_visualizer/__pycache__/auxiliary_functions.cpython-310.pyc 14 | freemocap_visualizer/__pycache__/data_definitions.cpython-310.pyc 15 | freemocap_visualizer/__pycache__/functions.cpython-310.pyc 16 | freemocap_adapter/__pycache__/data_definitions.cpython-310.pyc 17 | freemocap_adapter/__pycache__/addon_interface.cpython-310.pyc 18 | freemocap_adapter/__pycache__/core_functions.cpython-310.pyc 19 | freemocap_adapter/data_definitions/__pycache__/__init__.cpython-310.pyc 20 | freemocap_adapter/data_definitions/__pycache__/anthropomorphic_dimensions.cpython-310.pyc 21 | freemocap_adapter/data_definitions/__pycache__/bone_constraints.cpython-310.pyc 22 | freemocap_adapter/data_definitions/__pycache__/empties_dict.cpython-310.pyc 23 | freemocap_adapter/data_definitions/__pycache__/foot_locking_markers.cpython-310.pyc 24 | freemocap_adapter/data_definitions/__pycache__/ik_pole_bones.cpython-310.pyc 25 | freemocap_adapter/data_definitions/__pycache__/skelly_parts.cpython-310.pyc 26 | freemocap_adapter/data_definitions/__pycache__/virtual_bones.cpython-310.pyc 27 | freemocap_adapter/data_definitions/armatures/__pycache__/__init__.cpython-310.pyc 28 | freemocap_adapter/data_definitions/armatures/__pycache__/freemocap.cpython-310.pyc 29 | freemocap_adapter/data_definitions/__pycache__/ik_control_bones.cpython-310.pyc 30 | freemocap_adapter/data_definitions/armatures/__pycache__/bone_name_map.cpython-310.pyc 31 | freemocap_adapter/data_definitions/armatures/__pycache__/ue_metahuman_simple.cpython-310.pyc 32 | freemocap_adapter/data_definitions/poses/__pycache__/__init__.cpython-310.pyc 33 | freemocap_adapter/data_definitions/poses/__pycache__/freemocap_apose.cpython-310.pyc 34 | freemocap_adapter/data_definitions/poses/__pycache__/freemocap_metahuman.cpython-310.pyc 35 | freemocap_adapter/data_definitions/poses/__pycache__/freemocap_tpose.cpython-310.pyc 36 | freemocap_adapter/data_definitions/poses/__pycache__/ue_metahuman_default.cpython-310.pyc 37 | freemocap_adapter/data_definitions/poses/__pycache__/ue_metahuman_tpose.cpython-310.pyc 38 | freemocap_adapter/data_definitions/poses/__pycache__/ue_metahuman_realtime.cpython-310.pyc 39 | freemocap_live_viewer/__pycache__/__init__.cpython-310.pyc 40 | freemocap_live_viewer/data_definitions/__pycache__/bones_rotation_adjustments.cpython-310.pyc 41 | freemocap_live_viewer/data_definitions/__pycache__/__init__.cpython-310.pyc 42 | freemocap_adapter/data_definitions/interface/__pycache__/__init__.cpython-310.pyc 43 | freemocap_adapter/data_definitions/interface/panels/__pycache__/__init__.cpython-310.pyc 44 | freemocap_adapter/data_definitions/interface/panels/__pycache__/adjust_empties_interface.cpython-310.pyc 45 | freemocap_adapter/data_definitions/interface/properties/__pycache__/__init__.cpython-310.pyc 46 | freemocap_adapter/data_definitions/interface/properties/__pycache__/adjust_empties_properties.cpython-310.pyc 47 | freemocap_adapter/data_definitions/interface/properties/__pycache__/property_types.cpython-310.pyc 48 | freemocap_adapter/data_definitions/interface/panels/__pycache__/add_armature_panel.cpython-310.pyc 49 | freemocap_adapter/data_definitions/interface/panels/__pycache__/add_body_mesh_panel.cpython-310.pyc 50 | freemocap_adapter/data_definitions/interface/panels/__pycache__/add_finger_rotation_limits_panel.cpython-310.pyc 51 | freemocap_adapter/data_definitions/interface/panels/__pycache__/add_finger_rotation_limits_properties_panel.cpython-310.pyc 52 | freemocap_adapter/data_definitions/interface/panels/__pycache__/adjust_empties_panel.cpython-310.pyc 53 | freemocap_adapter/data_definitions/interface/panels/__pycache__/apply_butterworth_filters_panel.cpython-310.pyc 54 | freemocap_adapter/data_definitions/interface/panels/__pycache__/apply_foot_locking_panel.cpython-310.pyc 55 | freemocap_adapter/data_definitions/interface/panels/__pycache__/export_fbx_panel.cpython-310.pyc 56 | freemocap_adapter/data_definitions/interface/panels/__pycache__/reduce_bone_length_dispersion_interface.cpython-310.pyc 57 | freemocap_adapter/data_definitions/interface/panels/__pycache__/reduce_bone_length_dispersion_panel.cpython-310.pyc 58 | freemocap_adapter/data_definitions/interface/panels/__pycache__/retarget_animation_panel.cpython-310.pyc 59 | freemocap_adapter/data_definitions/interface/properties/__pycache__/add_armature_properties.cpython-310.pyc 60 | freemocap_adapter/data_definitions/interface/properties/__pycache__/add_body_mesh_properties.cpython-310.pyc 61 | freemocap_adapter/data_definitions/interface/properties/__pycache__/add_finger_rotation_limits_properties.cpython-310.pyc 62 | freemocap_adapter/data_definitions/interface/properties/__pycache__/apply_butterworth_filters_properties.cpython-310.pyc 63 | freemocap_adapter/data_definitions/interface/properties/__pycache__/apply_foot_locking_properties.cpython-310.pyc 64 | freemocap_adapter/data_definitions/interface/properties/__pycache__/export_fbx_properties.cpython-310.pyc 65 | freemocap_adapter/data_definitions/interface/properties/__pycache__/reduce_bone_length_dispersion_properties.cpython-310.pyc 66 | freemocap_adapter/data_definitions/interface/properties/__pycache__/retarget_animation_properties.cpython-310.pyc 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Freemocap Tools 2 | Set of tools to adapt and export Freemocap data. 3 | -------------------------------------------------------------------------------- /assets/body_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/assets/body_mesh.ply -------------------------------------------------------------------------------- /assets/charuco_board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/assets/charuco_board.png -------------------------------------------------------------------------------- /assets/freemocap_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/assets/freemocap_logo.png -------------------------------------------------------------------------------- /assets/readme.md: -------------------------------------------------------------------------------- 1 | Group of assets to be used with the Freemocap Tools 2 | -------------------------------------------------------------------------------- /freemocap_adapter/README.md: -------------------------------------------------------------------------------- 1 | # Freemocap Adapter 2 | Add-on to adapt the Freemocap Blender output. It can adjust the markers position, add an armature and a body mesh among other functions. The resulting armature and animation can be imported in platforms like Unreal Engine. 3 | 4 | # Requirements 5 | 1. Activate the Rigify add-on in Blender preferences. 6 | 2. Make sure the scipy python package is installed in your Blender's python folder. If it's not installed you will get a "ModuleNotFoundError: No module named scipy" 7 | when installing the addon. To install the scipy package run the command `python -m pip install scipy` inside your Blender python folder. 8 | 9 | For example: 10 | `C:\Program Files\Blender Foundation\Blender 3.6\3.6\python\bin> .\python.exe -m pip install scipy`. 11 | 12 | 13 | # Installation 14 | Download the latest freemocap_adapter addon zip file and install as a regular *.zip add-on in Edit->Preferences-Add-ons. 15 | 16 | # Function Instructions (v1.6.1). 17 | ## Adjust Empties 18 | This function is no longer necessary as in the current version of FreeMoCap, the marker empties come already aligned to the world origin. The purpose of this function was to rotate the empties to align to Blender world origin assuming the character had a standing still position in the frame were the function was executed. For best results, when the adjust empties function is executed the empties should be forming a standing still pose with arms open similar to A or T Pose. 19 | 20 | ![image](https://github.com/user-attachments/assets/bec7b4d5-90d8-46e7-afcf-6599fc94356b) 21 | 22 | Parameter description: 23 | - Align Reference: Marker to use as reference to align the empties on the z axis. Knee or trunk center are the options. 24 | - Vertical Angle Offset: Adds an angle offset to the z axis alignement. 25 | - Ground Reference: Marker to use for aligning the body to the ground level (z=0) 26 | - Vertical Position Offset: A distance offset to add to the z alignment. 27 | - Correct Fingers Empties: Fingers markers used to come separately from the wrist empties so this option was for align them to the wrist. This now comes by default with the export. 28 | - Add Hand Middle Empty: This additional empty between the index and middle mcp was for the hand orientation. 29 | 30 | ## Reduce Bone Length Dispersion 31 | This function was also useful for previous versions of FreeMoCap, now this comes by default with the export. The objective of this function was to reduce the variation of the bone segments formed by the marker empties. As the capture process is not 100% correct the lengths of the bones vary from frame to frame. This can produce unwanted armature bone rotations as the the bones have a fixed length. 32 | 33 | Currently, this function is used to fix the lengths to the median value of the whole capture. For example the upperarm bone segment formed by the shoulder and elbow empties. The function will register the distance between these two empties for every frame of the capture and then calculate the median length from that. 34 | 35 | ![image](https://github.com/user-attachments/assets/449b1286-78f0-4ff2-8a74-5f812d8dae69) 36 | 37 | Parameter description: 38 | - Dispersion Interval Variable: Variable used to define the new length dispersion interval. 39 | - Dispersion Interval Factor: Factor to multiply the variable and form the limits of the dispersion interval. If the factor is set to zero then it will force each frame bone length to be equal to the interval variable. 40 | - Body (Rig) Height [m]: Body height in meters. This value is used when the interval variable is set to standard length. If a rig is added after using Reduce Dispersion with standard length, it will have this value as height and the bones length will be proporions of this height. 41 | 42 | ## Apply Butterworth Filters (Blender 4.0+) 43 | This function helps to smooth the animation curves by applying a Butterworth filter to them. This filter can be applied manually using the curve editor in Blender. This functions allows to easily apply the filter for different sections of the body and with different cut-off frequencies. It also allows to apply a local filter with an origin point different than the world origin. For example, a filter can be applied to the fingers markers based on their variation related to the wrist empty. 44 | 45 | ![image](https://github.com/user-attachments/assets/e552139e-696d-4657-b261-633c11e709cf) 46 | 47 | Parameter description: 48 | - Section: Part of the body to apply the filter to. 49 | - Global (Freq.): Cut-off frequency of the global filter. 50 | - Local (Freq.): Cut-off frequency of the local filter. 51 | - Origin: Marker empty origin for the local filter. 52 | 53 | Here is a tutorial of this function: https://youtu.be/33OhM5xFUlg 54 | 55 | ## Add Finger Rotation Limits 56 | This function translates the finger marker empties so the bones respect the human normal rotation constraints. The idea is that the armature finger bones rotate according to human normal limits. This function was developed as enforcing this limits directly on the armature didn't produce decent results. The function is totally experimental and might produce awkward results. Only use it if the overall benefit is greater than the errors. The function works better if the empties orign has not been rotated. 57 | 58 | ![image](https://github.com/user-attachments/assets/cabb4ea8-509f-497f-8295-9577bf628f38) 59 | 60 | Here is a tutorial of this function: https://youtu.be/vPz6cTT_Iug 61 | 62 | ## Apply Foot Locking 63 | The objective of this function is to lock the feet markers based on their z axis position. The function's logic tries to fix the z position of the markers gradually when their z position is under a certain threshold for some consecutive frames. It also fix markers positions that are below a ground level. It also has a compensation logic to adjust the markers of the rest of the body. 64 | 65 | ![image](https://github.com/user-attachments/assets/12d7e5d0-65e2-43a4-8e75-7aa77bb29959) 66 | 67 | The following is a representation of the foot locking logic: 68 | ![image](https://github.com/user-attachments/assets/41dfef7f-998d-4d73-9891-860ef8170e36) 69 | 70 | Parameter description: 71 | - Target Foot: Foot to apply the locking to. 72 | - Target foot base markers: Markers to consider for the locking logic. 73 | - Z Threshold (m): Vertical threshold under which foot markers are considered for applying foot locking. 74 | - Ground Level (m): Ground level for applying foot locking. Markers with z global coordinate lower than this value will be fixed to this level. It must be lower than the z threshold. 75 | - Frame Window Minimum Size: Minimum frame window size for applying foot locking. A marker's z global coordinate has to be lower than the z threshold for a consecutive frames count equal or bigger than this value. It must be equal or greater than initial_attenuation_count + final_attenuation_count. 76 | - Initial Attenuation Count: This are the first frames of the window which have their z coordinate attenuated by the the initial quadratic attenuation function. 77 | - Final Attenuation Count: This are the last frames of the window which have their z coordinate attenuated by the the final quadratic attenuation function. 78 | - Lock XY at Ground Level: When applying foot locking, lock also the x and y coordinates at the ground level. This is useful only when character is standing still as it might leed to "sticky" or "lead" feet effect. 79 | - Knee Hip Compensation Coefficient: After calculating the ankle new z global coordinate, the knee and hip markers will be adjusted on the z axis by the same delta multiplied by this coefficient. A value of 1.0 means knee and hip have the same adjustment as the ankle. A value of 0 means knee and hip have no adjustment at all. Values lower than 1.0 are useful when the rig has IK constraints on the legs. This way the ankle adjustment is compensated by the knee IK bending. 80 | - Compensate Upper Body Markers: Compensate the upper body markers by setting the new z coordinate of the hips_center marker as the average z coordinate of left and right hips markers. Then propagate the new z delta to the upper body markers starting from the trunk_center. 81 | 82 | Here is a tutorial of the function: https://youtu.be/OE0ZlG9_My8 83 | 84 | ## Add Armature 85 | This function deletes the default armature and creates a new one. It was more useful when the default export had a simpler armature. Now the default armature is made using part of this function's logic. 86 | 87 | ![image](https://github.com/user-attachments/assets/238a2a7a-2d64-4acd-9794-478d67e378c8) 88 | 89 | Parameter description: 90 | - Add Armature Method: Method used to create the armature. 91 | - Armature: Armature type. 92 | - Pose: Pose that will be used as rest pose. 93 | - Keep right/left symmetry: Keep right/left side symmetry (use average right/left side bone length). 94 | - Add finger constraints: Add bone constraints for the fingers. 95 | - Add IK constraints: Add IK constraints for arms and legs. 96 | - IK transition threshold: Threshold of parallel degree (dot product) between base and target ik vectors. It is used to transition between vectors to determine the pole bone position. 97 | - Add rotation limits: Add rotation limits (human skeleton) to the bones constraints (experimental). 98 | - Clear constraints: Clear added constraints after baking animation. 99 | 100 | ## Add Body Mesh 101 | Function to add a mesh to the armature. It was more useful when the export didn't have a body mesh. 102 | 103 | ![image](https://github.com/user-attachments/assets/4c813c8d-f0cb-4845-a060-f27df47c8397) 104 | 105 | Parameter description: 106 | - Body Mesh Mode: Mode for adding the mesh to the armature. The Skelly Parts mode uses the length and rotation of the bones to adjust individual bone meshes to adapt them to the capture armature. 107 | 108 | ## FBX Export 109 | This function exports an FBX file of the armature and mesh (including animation) to a folder named "FBX" inside the same folder where the capture .blend file is. 110 | 111 | ![image](https://github.com/user-attachments/assets/16bf6eb1-1842-4090-ac57-0ea96687d9a4) 112 | 113 | Parameter description: 114 | - FBX Export Type: The type of export based on the final platform destination. The Unreal Engine option was necessary when exporting from Blender versions 4.0 or older. In newer Blender versions the Standard mode exports a correct FBX file for importing in UE (tested on UE version 5.3 and 5.4). 115 | 116 | ## Retarget Animation 117 | This functions helps to retarget the animation from a source armature to a target armature. A source and target armature should be selected in the options. Then the internal logic tries to figure it out the armature type of the target. Currently it has preloaded the bones naming of Rigify, Mixamo and Daz armatures. The function will try to apply bone constraints based on the bone name equivalence detected in the previous step. 118 | The function is just a first iteration so it won't work as expected in most cases, this because of different bone naming and different bone local axis orientation that requires additional bone roll. The target armature should have a T-Pose (equal to the FreeMoCap rest pose) as rest pose so it doesn't add rotationn offsets to the retargeting. 119 | 120 | ![image](https://github.com/user-attachments/assets/48250e15-be05-4922-b936-a0320624366c) 121 | 122 | Parameter description: 123 | - Source FreeMoCap Armature: Source FreeMoCap armature. 124 | - Target Armature: The armature that the constraints will be aplied to. 125 | - Bake Animation: Bake the animation to the pose bones. 126 | - Clear Constraints: Clear the constraints after the animation bake is made. 127 | 128 | 129 | # Mesh attribution 130 | The meshes used in some assets come from the following sources: 131 | 1. https://sketchfab.com/3d-models/free-low-poly-pbr-bsdf-textured-human-skeleton-d0c9919aec004fd39d65ce7a7960969b 132 | 2. https://free3d.com/3d-model/skull-v3--785914.html 133 | -------------------------------------------------------------------------------- /freemocap_adapter/__init__.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | 'name' : 'Freemocap Adapter Alt', 3 | 'author' : 'ajc27', 4 | 'version' : (1, 6, 1), 5 | 'blender' : (3, 0, 0), 6 | 'location' : '3D Viewport > Sidebar > Freemocap Adapter Alt', 7 | 'description' : 'Add-on to adapt the Freemocap Blender output', 8 | 'category' : 'Development', 9 | } 10 | 11 | import bpy 12 | 13 | from .data_definitions.interface.properties.adjust_empties_properties import AdjustEmptiesProperties 14 | from .data_definitions.interface.properties.reduce_bone_length_dispersion_properties import ReduceBoneLengthDispersionProperties 15 | from .data_definitions.interface.properties.apply_butterworth_filters_properties import ApplyButterworthFiltersProperties 16 | from .data_definitions.interface.properties.add_finger_rotation_limits_properties import AddFingerRotationLimitsProperties 17 | from .data_definitions.interface.properties.apply_foot_locking_properties import ApplyFootLockingProperties 18 | from .data_definitions.interface.properties.add_armature_properties import AddArmatureProperties 19 | from .data_definitions.interface.properties.add_body_mesh_properties import AddBodyMeshProperties 20 | from .data_definitions.interface.properties.export_fbx_properties import ExportFBXProperties 21 | from .data_definitions.interface.properties.retarget_animation_properties import RetargetAnimationProperties 22 | 23 | from .addon_interface import (FMC_ADAPTER_PROPERTIES, 24 | VIEW3D_PT_freemocap_adapter, 25 | FMC_ADAPTER_OT_adjust_empties, 26 | FMC_ADAPTER_OT_reduce_bone_length_dispersion, 27 | FMC_ADAPTER_OT_apply_butterworth_filters, 28 | FMC_ADAPTER_OT_add_finger_rotation_limits, 29 | FMC_ADAPTER_OT_apply_foot_locking, 30 | FMC_ADAPTER_OT_add_rig, 31 | FMC_ADAPTER_OT_add_body_mesh, 32 | FMC_ADAPTER_OT_export_fbx, 33 | FMC_ADAPTER_OT_retarget_animation, 34 | ) 35 | 36 | classes = [AdjustEmptiesProperties, 37 | ReduceBoneLengthDispersionProperties, 38 | ApplyButterworthFiltersProperties, 39 | AddFingerRotationLimitsProperties, 40 | ApplyFootLockingProperties, 41 | AddArmatureProperties, 42 | AddBodyMeshProperties, 43 | ExportFBXProperties, 44 | RetargetAnimationProperties, 45 | FMC_ADAPTER_PROPERTIES, 46 | VIEW3D_PT_freemocap_adapter, 47 | FMC_ADAPTER_OT_adjust_empties, 48 | FMC_ADAPTER_OT_reduce_bone_length_dispersion, 49 | FMC_ADAPTER_OT_apply_butterworth_filters, 50 | FMC_ADAPTER_OT_add_finger_rotation_limits, 51 | FMC_ADAPTER_OT_apply_foot_locking, 52 | FMC_ADAPTER_OT_add_rig, 53 | FMC_ADAPTER_OT_add_body_mesh, 54 | FMC_ADAPTER_OT_export_fbx, 55 | FMC_ADAPTER_OT_retarget_animation, 56 | ] 57 | 58 | def register(): 59 | """ 60 | A function to register classes and assign a pointer property to 61 | bpy.types.Scene. 62 | """ 63 | for cls in classes: 64 | bpy.utils.register_class(cls) 65 | 66 | bpy.types.Scene.fmc_adapter_tool = bpy.props.PointerProperty(type = FMC_ADAPTER_PROPERTIES) 67 | 68 | def unregister(): 69 | """ 70 | Function to unregister classes and delete an attribute 71 | from bpy.types.Scene. 72 | """ 73 | for cls in classes: 74 | bpy.utils.unregister_class(cls) 75 | 76 | del bpy.types.Scene.fmc_adapter_tool 77 | 78 | # Register the Add-on 79 | if __name__ == "__main__": 80 | register() 81 | -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_lowpoly_mesh.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_lowpoly_mesh.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.01.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.01.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.01.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.01.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.02.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.02.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.02.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.02.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.03.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.03.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.03.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_index.03.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.01.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.01.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.01.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.01.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.02.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.02.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.02.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.02.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.03.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.03.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.03.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_middle.03.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.01.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.01.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.01.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.01.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.02.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.02.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.02.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.02.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.03.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.03.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.03.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_pinky.03.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.01.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.01.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.01.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.01.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.02.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.02.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.02.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.02.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.03.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.03.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.03.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_f_ring.03.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_foot.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_foot.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_foot.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_foot.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_forearm.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_forearm.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_forearm.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_forearm.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_hand.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_hand.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_hand.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_hand.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_head.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_head.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_heel.02.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_heel.02.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_heel.02.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_heel.02.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.01.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.01.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.01.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.01.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.02.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.02.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.02.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.02.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.03.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.03.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.03.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.03.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.04.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.04.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.04.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_palm.04.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_shin.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_shin.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_shin.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_shin.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_spine.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_spine.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_thigh.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_thigh.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_thigh.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_thigh.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.01.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.01.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.01.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.01.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.02.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.02.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.02.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.02.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.03.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.03.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.03.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_thumb.03.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_upper_arm.L.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_upper_arm.L.fbx -------------------------------------------------------------------------------- /freemocap_adapter/assets/skelly_parts_meshes/Skelly_upper_arm.R.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/assets/skelly_parts_meshes/Skelly_upper_arm.R.fbx -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/data_definitions/__init__.py -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/anthropomorphic_dimensions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary with the Anthropomorphic human dimensions by Winter, D. 3 | This values will be used the specified actor height when using 4 | standard bone lengths 5 | """ 6 | anthropomorphic_dimensions = { 7 | 'pelvis.R': { 8 | 'dimension': 0.0955}, 9 | 'pelvis.L': { 10 | 'dimension': 0.0955}, 11 | 'spine': { 12 | 'dimension': 0.144}, 13 | 'spine.001': { 14 | 'dimension': 0.144}, 15 | 'neck': { 16 | 'dimension': 0.118}, 17 | 'head_nose': { # Aux bone from head center to nose tip to align face bones 18 | 'dimension': 0.0743}, 19 | 'shoulder.R': { 20 | 'dimension': 0.129}, 21 | 'shoulder.L': { 22 | 'dimension': 0.129}, 23 | 'upper_arm.R': { 24 | 'dimension': 0.186}, 25 | 'upper_arm.L': { 26 | 'dimension': 0.186}, 27 | 'forearm.R': { 28 | 'dimension': 0.146}, 29 | 'forearm.L': { 30 | 'dimension': 0.146}, 31 | 'hand.R': { 32 | 'dimension': 0.054}, 33 | 'hand.L': { 34 | 'dimension': 0.054}, 35 | 'thumb.carpal.R': { # Auxiliary bone to align right_hand_thumb_cmc empty 36 | 'dimension': 0.03}, 37 | 'thumb.carpal.L': { # Auxiliary bone to align left_hand_thumb_cmc empty 38 | 'dimension': 0.03}, 39 | 'thumb.01.R': { 40 | 'dimension': 0.021}, 41 | 'thumb.01.L': { 42 | 'dimension': 0.021}, 43 | 'thumb.02.R': { 44 | 'dimension': 0.024}, 45 | 'thumb.02.L': { 46 | 'dimension': 0.024}, 47 | 'thumb.03.R': { 48 | 'dimension': 0.0192}, 49 | 'thumb.03.L': { 50 | 'dimension': 0.0192}, 51 | 'palm.01.R': { 52 | 'dimension': 0.054}, 53 | 'palm.01.L': { 54 | 'dimension': 0.054}, 55 | 'f_index.01.R': { 56 | 'dimension': 0.0282}, 57 | 'f_index.01.L': { 58 | 'dimension': 0.0282}, 59 | 'f_index.02.R': { 60 | 'dimension': 0.0186}, 61 | 'f_index.02.L': { 62 | 'dimension': 0.0186}, 63 | 'f_index.03.R': { 64 | 'dimension': 0.015}, 65 | 'f_index.03.L': { 66 | 'dimension': 0.015}, 67 | 'palm.02.R': { 68 | 'dimension': 0.054}, 69 | 'palm.02.L': { 70 | 'dimension': 0.054}, 71 | 'f_middle.01.R': { 72 | 'dimension': 0.03}, 73 | 'f_middle.01.L': { 74 | 'dimension': 0.03}, 75 | 'f_middle.02.R': { 76 | 'dimension': 0.0192}, 77 | 'f_middle.02.L': { 78 | 'dimension': 0.0192}, 79 | 'f_middle.03.R': { 80 | 'dimension': 0.0156}, 81 | 'f_middle.03.L': { 82 | 'dimension': 0.0156}, 83 | 'palm.03.R': { 84 | 'dimension': 0.0522}, 85 | 'palm.03.L': { 86 | 'dimension': 0.0522}, 87 | 'f_ring.01.R': { 88 | 'dimension': 0.0282}, 89 | 'f_ring.01.L': { 90 | 'dimension': 0.0282}, 91 | 'f_ring.02.R': { 92 | 'dimension': 0.0186}, 93 | 'f_ring.02.L': { 94 | 'dimension': 0.0186}, 95 | 'f_ring.03.R': { 96 | 'dimension': 0.0156}, 97 | 'f_ring.03.L': { 98 | 'dimension': 0.0156}, 99 | 'palm.04.R': { 100 | 'dimension': 0.0498}, 101 | 'palm.04.L': { 102 | 'dimension': 0.0498}, 103 | 'f_pinky.01.R': { 104 | 'dimension': 0.0264}, 105 | 'f_pinky.01.L': { 106 | 'dimension': 0.0264}, 107 | 'f_pinky.02.R': { 108 | 'dimension': 0.0156}, 109 | 'f_pinky.02.L': { 110 | 'dimension': 0.0156}, 111 | 'f_pinky.03.R': { 112 | 'dimension': 0.0144}, 113 | 'f_pinky.03.L': { 114 | 'dimension': 0.0144}, 115 | 'thigh.R': { 116 | 'dimension': 0.245}, 117 | 'thigh.L': { 118 | 'dimension': 0.245}, 119 | 'shin.R': { 120 | 'dimension': 0.246}, 121 | 'shin.L': { 122 | 'dimension': 0.246}, 123 | 'foot.R': { 124 | 'dimension': 0.152}, 125 | 'foot.L': { 126 | 'dimension': 0.152}, 127 | 'heel.02.R': { 128 | 'dimension': 0.039}, 129 | 'heel.02.L': { 130 | 'dimension': 0.039}, 131 | } 132 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/armatures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/data_definitions/armatures/__init__.py -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/armatures/bone_name_map.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary to map the default armature bone names with the different 3 | armatures bone names. 4 | """ 5 | bone_name_map = { 6 | 'armature_ue_metahuman_simple': { 7 | 'pelvis': 'pelvis', 8 | 'pelvis.R': 'pelvis_r', 9 | 'pelvis.L': 'pelvis_l', 10 | 'spine': 'spine_01', 11 | 'spine.001': 'spine_04', 12 | 'neck': 'neck_01', 13 | 'face': 'face', 14 | 'shoulder.R': 'clavicle_r', 15 | 'shoulder.L': 'clavicle_l', 16 | 'upper_arm.R': 'upperarm_r', 17 | 'upper_arm.L': 'upperarm_l', 18 | 'forearm.R': 'lowerarm_r', 19 | 'forearm.L': 'lowerarm_l', 20 | 'hand.R': 'hand_r', 21 | 'hand.L': 'hand_l', 22 | 'thumb.carpal.R': 'thumb_metacarpal_r', 23 | 'palm.01.R': 'index_metacarpal_r', 24 | 'palm.02.R': 'middle_metacarpal_r', 25 | 'palm.03.R': 'ring_metacarpal_r', 26 | 'palm.04.R': 'pinky_metacarpal_r', 27 | 'thumb.carpal.L': 'thumb_metacarpal_l', 28 | 'palm.01.L': 'index_metacarpal_l', 29 | 'palm.02.L': 'middle_metacarpal_l', 30 | 'palm.03.L': 'ring_metacarpal_l', 31 | 'palm.04.L': 'pinky_metacarpal_l', 32 | 'thumb.01.R': 'thumb_01_r', 33 | 'thumb.01.L': 'thumb_01_l', 34 | 'thumb.02.R': 'thumb_02_r', 35 | 'thumb.02.L': 'thumb_02_l', 36 | 'thumb.03.R': 'thumb_03_r', 37 | 'thumb.03.L': 'thumb_03_l', 38 | 'f_index.01.R': 'index_01_r', 39 | 'f_index.01.L': 'index_01_l', 40 | 'f_index.02.R': 'index_02_r', 41 | 'f_index.02.L': 'index_02_l', 42 | 'f_index.03.R': 'index_03_r', 43 | 'f_index.03.L': 'index_03_l', 44 | 'f_middle.01.R': 'middle_01_r', 45 | 'f_middle.01.L': 'middle_01_l', 46 | 'f_middle.02.R': 'middle_02_r', 47 | 'f_middle.02.L': 'middle_02_l', 48 | 'f_middle.03.R': 'middle_03_r', 49 | 'f_middle.03.L': 'middle_03_l', 50 | 'f_ring.01.R': 'ring_01_r', 51 | 'f_ring.01.L': 'ring_01_l', 52 | 'f_ring.02.R': 'ring_02_r', 53 | 'f_ring.02.L': 'ring_02_l', 54 | 'f_ring.03.R': 'ring_03_r', 55 | 'f_ring.03.L': 'ring_03_l', 56 | 'f_pinky.01.R': 'pinky_01_r', 57 | 'f_pinky.01.L': 'pinky_01_l', 58 | 'f_pinky.02.R': 'pinky_02_r', 59 | 'f_pinky.02.L': 'pinky_02_l', 60 | 'f_pinky.03.R': 'pinky_03_r', 61 | 'f_pinky.03.L': 'pinky_03_l', 62 | 'thigh.R': 'thigh_r', 63 | 'thigh.L': 'thigh_l', 64 | 'shin.R': 'calf_r', 65 | 'shin.L': 'calf_l', 66 | 'foot.R': 'foot_r', 67 | 'foot.L': 'foot_l', 68 | 'heel.02.R': 'heel_r', 69 | 'heel.02.L': 'heel_l', 70 | 'hand.IK.R': 'hand.IK.R', 71 | 'hand.IK.L': 'hand.IK.L', 72 | 'foot.IK.R': 'foot.IK.R', 73 | 'foot.IK.L': 'foot.IK.L', 74 | 'arm_pole_target.R': 'arm_pole_target.R', 75 | 'arm_pole_target.L': 'arm_pole_target.L', 76 | 'leg_pole_target.R': 'leg_pole_target.R', 77 | 'leg_pole_target.L': 'leg_pole_target.L', 78 | }, 79 | 'armature_freemocap': { 80 | 'pelvis': 'pelvis', 81 | 'pelvis.R': 'pelvis.R', 82 | 'pelvis.L': 'pelvis.L', 83 | 'spine': 'spine', 84 | 'spine.001': 'spine.001', 85 | 'neck': 'neck', 86 | 'face': 'face', 87 | 'shoulder.R': 'shoulder.R', 88 | 'shoulder.L': 'shoulder.L', 89 | 'upper_arm.R': 'upper_arm.R', 90 | 'upper_arm.L': 'upper_arm.L', 91 | 'forearm.R': 'forearm.R', 92 | 'forearm.L': 'forearm.L', 93 | 'hand.R': 'hand.R', 94 | 'hand.L': 'hand.L', 95 | 'thumb.carpal.R': 'thumb.carpal.R', 96 | 'palm.01.R': 'palm.01.R', 97 | 'palm.02.R': 'palm.02.R', 98 | 'palm.03.R': 'palm.03.R', 99 | 'palm.04.R': 'palm.04.R', 100 | 'thumb.carpal.L': 'thumb.carpal.L', 101 | 'palm.01.L': 'palm.01.L', 102 | 'palm.02.L': 'palm.02.L', 103 | 'palm.03.L': 'palm.03.L', 104 | 'palm.04.L': 'palm.04.L', 105 | 'thumb.01.R': 'thumb.01.R', 106 | 'thumb.01.L': 'thumb.01.L', 107 | 'thumb.02.R': 'thumb.02.R', 108 | 'thumb.02.L': 'thumb.02.L', 109 | 'thumb.03.R': 'thumb.03.R', 110 | 'thumb.03.L': 'thumb.03.L', 111 | 'f_index.01.R': 'f_index.01.R', 112 | 'f_index.01.L': 'f_index.01.L', 113 | 'f_index.02.R': 'f_index.02.R', 114 | 'f_index.02.L': 'f_index.02.L', 115 | 'f_index.03.R': 'f_index.03.R', 116 | 'f_index.03.L': 'f_index.03.L', 117 | 'f_middle.01.R': 'f_middle.01.R', 118 | 'f_middle.01.L': 'f_middle.01.L', 119 | 'f_middle.02.R': 'f_middle.02.R', 120 | 'f_middle.02.L': 'f_middle.02.L', 121 | 'f_middle.03.R': 'f_middle.03.R', 122 | 'f_middle.03.L': 'f_middle.03.L', 123 | 'f_ring.01.R': 'f_ring.01.R', 124 | 'f_ring.01.L': 'f_ring.01.L', 125 | 'f_ring.02.R': 'f_ring.02.R', 126 | 'f_ring.02.L': 'f_ring.02.L', 127 | 'f_ring.03.R': 'f_ring.03.R', 128 | 'f_ring.03.L': 'f_ring.03.L', 129 | 'f_pinky.01.R': 'f_pinky.01.R', 130 | 'f_pinky.01.L': 'f_pinky.01.L', 131 | 'f_pinky.02.R': 'f_pinky.02.R', 132 | 'f_pinky.02.L': 'f_pinky.02.L', 133 | 'f_pinky.03.R': 'f_pinky.03.R', 134 | 'f_pinky.03.L': 'f_pinky.03.L', 135 | 'thigh.R': 'thigh.R', 136 | 'thigh.L': 'thigh.L', 137 | 'shin.R': 'shin.R', 138 | 'shin.L': 'shin.L', 139 | 'foot.R': 'foot.R', 140 | 'foot.L': 'foot.L', 141 | 'heel.02.R': 'heel.02.R', 142 | 'heel.02.L': 'heel.02.L', 143 | 'hand.IK.R': 'hand.IK.R', 144 | 'hand.IK.L': 'hand.IK.L', 145 | 'foot.IK.R': 'foot.IK.R', 146 | 'foot.IK.L': 'foot.IK.L', 147 | 'arm_pole_target.R': 'arm_pole_target.R', 148 | 'arm_pole_target.L': 'arm_pole_target.L', 149 | 'leg_pole_target.R': 'leg_pole_target.R', 150 | 'leg_pole_target.L': 'leg_pole_target.L', 151 | }, 152 | 'armature_mixamo': { 153 | 'pelvis': 'mixamorig:Hips', 154 | 'pelvis.R': 'null', 155 | 'pelvis.L': 'null', 156 | 'spine': 'mixamorig:Spine', 157 | 'spine.001': 'mixamorig:Spine1', 158 | 'neck': 'mixamorig:Neck', 159 | 'face': 'null', 160 | 'shoulder.R': 'mixamorig:RightShoulder', 161 | 'shoulder.L': 'mixamorig:LeftShoulder', 162 | 'upper_arm.R': 'mixamorig:RightArm', 163 | 'upper_arm.L': 'mixamorig:LeftArm', 164 | 'forearm.R': 'mixamorig:RightForeArm', 165 | 'forearm.L': 'mixamorig:LeftForeArm', 166 | 'hand.R': 'mixamorig:RightHand', 167 | 'hand.L': 'mixamorig:LeftHand', 168 | 'thumb.carpal.R': 'null', 169 | 'palm.01.R': 'null', 170 | 'palm.02.R': 'null', 171 | 'palm.03.R': 'null', 172 | 'palm.04.R': 'null', 173 | 'thumb.carpal.L': 'null', 174 | 'palm.01.L': 'null', 175 | 'palm.02.L': 'null', 176 | 'palm.03.L': 'null', 177 | 'palm.04.L': 'null', 178 | 'thumb.01.R': 'mixamorig:RightHandThumb1', 179 | 'thumb.01.L': 'mixamorig:LeftHandThumb1', 180 | 'thumb.02.R': 'mixamorig:RightHandThumb2', 181 | 'thumb.02.L': 'mixamorig:LeftHandThumb2', 182 | 'thumb.03.R': 'mixamorig:RightHandThumb3', 183 | 'thumb.03.L': 'mixamorig:LeftHandThumb3', 184 | 'f_index.01.R': 'mixamorig:RightHandIndex1', 185 | 'f_index.01.L': 'mixamorig:LeftHandIndex1', 186 | 'f_index.02.R': 'mixamorig:RightHandIndex2', 187 | 'f_index.02.L': 'mixamorig:LeftHandIndex2', 188 | 'f_index.03.R': 'mixamorig:RightHandIndex3', 189 | 'f_index.03.L': 'mixamorig:LeftHandIndex3', 190 | 'f_middle.01.R': 'mixamorig:RightHandMiddle1', 191 | 'f_middle.01.L': 'mixamorig:LeftHandMiddle1', 192 | 'f_middle.02.R': 'mixamorig:RightHandMiddle2', 193 | 'f_middle.02.L': 'mixamorig:LeftHandMiddle2', 194 | 'f_middle.03.R': 'mixamorig:RightHandMiddle3', 195 | 'f_middle.03.L': 'mixamorig:LeftHandMiddle3', 196 | 'f_ring.01.R': 'mixamorig:RightHandRing1', 197 | 'f_ring.01.L': 'mixamorig:LeftHandRing1', 198 | 'f_ring.02.R': 'mixamorig:RightHandRing2', 199 | 'f_ring.02.L': 'mixamorig:LeftHandRing2', 200 | 'f_ring.03.R': 'mixamorig:RightHandRing3', 201 | 'f_ring.03.L': 'mixamorig:LeftHandRing3', 202 | 'f_pinky.01.R': 'mixamorig:RightHandPinky1', 203 | 'f_pinky.01.L': 'mixamorig:LeftHandPinky1', 204 | 'f_pinky.02.R': 'mixamorig:RightHandPinky2', 205 | 'f_pinky.02.L': 'mixamorig:LeftHandPinky2', 206 | 'f_pinky.03.R': 'mixamorig:RightHandPinky3', 207 | 'f_pinky.03.L': 'mixamorig:LeftHandPinky3', 208 | 'thigh.R': 'mixamorig:RightUpLeg', 209 | 'thigh.L': 'mixamorig:LeftUpLeg', 210 | 'shin.R': 'mixamorig:RightLeg', 211 | 'shin.L': 'mixamorig:LeftLeg', 212 | 'foot.R': 'mixamorig:RightFoot', 213 | 'foot.L': 'mixamorig:LeftFoot', 214 | 'heel.02.R': 'null', 215 | 'heel.02.L': 'null', 216 | 'hand.IK.R': 'null', 217 | 'hand.IK.L': 'null', 218 | 'foot.IK.R': 'null', 219 | 'foot.IK.L': 'null', 220 | 'arm_pole_target.R': 'null', 221 | 'arm_pole_target.L': 'null', 222 | 'leg_pole_target.R': 'null', 223 | 'leg_pole_target.L': 'null', 224 | }, 225 | 'armature_daz': { 226 | 'pelvis': 'hip', 227 | 'pelvis.R': 'null', 228 | 'pelvis.L': 'null', 229 | 'spine': 'spine1', 230 | 'spine.001': 'spine3', 231 | 'neck': 'neck1', 232 | 'face': 'head', 233 | 'shoulder.R': 'r_shoulder', 234 | 'shoulder.L': 'l_shoulder', 235 | 'upper_arm.R': 'r_upperarm', 236 | 'upper_arm.L': 'l_upperarm', 237 | 'forearm.R': 'r_forearm', 238 | 'forearm.L': 'l_forearm', 239 | 'hand.R': 'r_hand', 240 | 'hand.L': 'l_hand', 241 | 'thumb.carpal.R': 'null', 242 | 'palm.01.R': 'null', 243 | 'palm.02.R': 'null', 244 | 'palm.03.R': 'null', 245 | 'palm.04.R': 'null', 246 | 'thumb.carpal.L': 'null', 247 | 'palm.01.L': 'null', 248 | 'palm.02.L': 'null', 249 | 'palm.03.L': 'null', 250 | 'palm.04.L': 'null', 251 | 'thumb.01.R': 'r_thumb1', 252 | 'thumb.01.L': 'l_thumb1', 253 | 'thumb.02.R': 'r_thumb2', 254 | 'thumb.02.L': 'l_thumb2', 255 | 'thumb.03.R': 'r_thumb3', 256 | 'thumb.03.L': 'l_thumb3', 257 | 'f_index.01.R': 'r_index1', 258 | 'f_index.01.L': 'l_index1', 259 | 'f_index.02.R': 'r_index2', 260 | 'f_index.02.L': 'l_index2', 261 | 'f_index.03.R': 'r_index3', 262 | 'f_index.03.L': 'l_index3', 263 | 'f_middle.01.R': 'r_mid1', 264 | 'f_middle.01.L': 'l_mid1', 265 | 'f_middle.02.R': 'r_mid2', 266 | 'f_middle.02.L': 'l_mid2', 267 | 'f_middle.03.R': 'r_mid3', 268 | 'f_middle.03.L': 'l_mid3', 269 | 'f_ring.01.R': 'r_ring1', 270 | 'f_ring.01.L': 'l_ring1', 271 | 'f_ring.02.R': 'r_ring2', 272 | 'f_ring.02.L': 'l_ring2', 273 | 'f_ring.03.R': 'r_ring3', 274 | 'f_ring.03.L': 'l_ring3', 275 | 'f_pinky.01.R': 'r_pinky1', 276 | 'f_pinky.01.L': 'l_pinky1', 277 | 'f_pinky.02.R': 'r_pinky2', 278 | 'f_pinky.02.L': 'l_pinky2', 279 | 'f_pinky.03.R': 'r_pinky3', 280 | 'f_pinky.03.L': 'l_pinky3', 281 | 'thigh.R': 'r_thigh', 282 | 'thigh.L': 'l_thigh', 283 | 'shin.R': 'r_shin', 284 | 'shin.L': 'l_shin', 285 | 'foot.R': 'r_foot', 286 | 'foot.L': 'l_foot', 287 | 'heel.02.R': 'null', 288 | 'heel.02.L': 'null', 289 | 'hand.IK.R': 'null', 290 | 'hand.IK.L': 'null', 291 | 'foot.IK.R': 'null', 292 | 'foot.IK.L': 'null', 293 | 'arm_pole_target.R': 'null', 294 | 'arm_pole_target.L': 'null', 295 | 'leg_pole_target.R': 'null', 296 | 'leg_pole_target.L': 'null', 297 | }, 298 | } 299 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/armatures/freemocap.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary with the bones comforming the freemocap armature. 3 | """ 4 | 5 | armature_freemocap = { 6 | 'pelvis': { 7 | 'parent_bone' : 'root', 8 | 'connected' : False, 9 | 'parent_position' : 'head', 10 | 'default_length' : 0.05, 11 | }, 12 | 'pelvis.R': { 13 | 'parent_bone' : 'pelvis', 14 | 'connected' : False, 15 | 'parent_position' : 'head', 16 | 'default_length' : 0, 17 | }, 18 | 'pelvis.L': { 19 | 'parent_bone' : 'pelvis', 20 | 'connected' : False, 21 | 'parent_position' : 'head', 22 | 'default_length' : 0, 23 | }, 24 | 'spine': { 25 | 'parent_bone' : 'pelvis', 26 | 'connected' : False, 27 | 'parent_position' : 'head', 28 | 'default_length' : 0, 29 | }, 30 | 'spine.001': { 31 | 'parent_bone' : 'spine', 32 | 'connected' : True, 33 | 'parent_position' : 'tail', 34 | 'default_length' : 0, 35 | }, 36 | 'neck': { 37 | 'parent_bone' : 'spine.001', 38 | 'connected' : True, 39 | 'parent_position' : 'tail', 40 | 'default_length' : 0, 41 | }, 42 | 'face': { 43 | 'parent_bone' : 'neck', 44 | 'connected' : True, 45 | 'parent_position' : 'tail', 46 | 'default_length' : 0, 47 | }, 48 | 'shoulder.R': { 49 | 'parent_bone' : 'spine.001', 50 | 'connected' : True, 51 | 'parent_position' : 'tail', 52 | 'default_length' : 0, 53 | }, 54 | 'shoulder.L': { 55 | 'parent_bone' : 'spine.001', 56 | 'connected' : True, 57 | 'parent_position' : 'tail', 58 | 'default_length' : 0, 59 | }, 60 | 'upper_arm.R': { 61 | 'parent_bone' : 'shoulder.R', 62 | 'connected' : True, 63 | 'parent_position' : 'tail', 64 | 'default_length' : 0, 65 | }, 66 | 'upper_arm.L': { 67 | 'parent_bone' : 'shoulder.L', 68 | 'connected' : True, 69 | 'parent_position' : 'tail', 70 | 'default_length' : 0, 71 | }, 72 | 'forearm.R': { 73 | 'parent_bone' : 'upper_arm.R', 74 | 'connected' : True, 75 | 'parent_position' : 'tail', 76 | 'default_length' : 0, 77 | }, 78 | 'forearm.L': { 79 | 'parent_bone' : 'upper_arm.L', 80 | 'connected' : True, 81 | 'parent_position' : 'tail', 82 | 'default_length' : 0, 83 | }, 84 | 'hand.R': { 85 | 'parent_bone' : 'forearm.R', 86 | 'connected' : True, 87 | 'parent_position' : 'tail', 88 | 'default_length' : 0, 89 | }, 90 | 'hand.L': { 91 | 'parent_bone' : 'forearm.L', 92 | 'connected' : True, 93 | 'parent_position' : 'tail', 94 | 'default_length' : 0, 95 | }, 96 | 'thumb.carpal.R': { 97 | 'parent_bone' : 'hand.R', 98 | 'connected' : False, 99 | 'parent_position' : 'head', 100 | 'default_length' : 0, 101 | }, 102 | 'thumb.carpal.L': { 103 | 'parent_bone' : 'hand.L', 104 | 'connected' : False, 105 | 'parent_position' : 'head', 106 | 'default_length' : 0, 107 | }, 108 | 'thumb.01.R': { 109 | 'parent_bone' : 'thumb.carpal.R', 110 | 'connected' : True, 111 | 'parent_position' : 'tail', 112 | 'default_length' : 0, 113 | }, 114 | 'thumb.01.L': { 115 | 'parent_bone' : 'thumb.carpal.L', 116 | 'connected' : True, 117 | 'parent_position' : 'tail', 118 | 'default_length' : 0, 119 | }, 120 | 'thumb.02.R': { 121 | 'parent_bone' : 'thumb.01.R', 122 | 'connected' : True, 123 | 'parent_position' : 'tail', 124 | 'default_length' : 0, 125 | }, 126 | 'thumb.02.L': { 127 | 'parent_bone' : 'thumb.01.L', 128 | 'connected' : True, 129 | 'parent_position' : 'tail', 130 | 'default_length' : 0, 131 | }, 132 | 'thumb.03.R': { 133 | 'parent_bone' : 'thumb.02.R', 134 | 'connected' : True, 135 | 'parent_position' : 'tail', 136 | 'default_length' : 0, 137 | }, 138 | 'thumb.03.L': { 139 | 'parent_bone' : 'thumb.02.L', 140 | 'connected' : True, 141 | 'parent_position' : 'tail', 142 | 'default_length' : 0, 143 | }, 144 | 'palm.01.R': { 145 | 'parent_bone' : 'hand.R', 146 | 'connected' : False, 147 | 'parent_position' : 'head', 148 | 'default_length' : 0, 149 | }, 150 | 'palm.01.L': { 151 | 'parent_bone' : 'hand.L', 152 | 'connected' : False, 153 | 'parent_position' : 'head', 154 | 'default_length' : 0, 155 | }, 156 | 'f_index.01.R': { 157 | 'parent_bone' : 'palm.01.R', 158 | 'connected' : True, 159 | 'parent_position' : 'tail', 160 | 'default_length' : 0, 161 | }, 162 | 'f_index.01.L': { 163 | 'parent_bone' : 'palm.01.L', 164 | 'connected' : True, 165 | 'parent_position' : 'tail', 166 | 'default_length' : 0, 167 | }, 168 | 'f_index.02.R': { 169 | 'parent_bone' : 'f_index.01.R', 170 | 'connected' : True, 171 | 'parent_position' : 'tail', 172 | 'default_length' : 0, 173 | }, 174 | 'f_index.02.L': { 175 | 'parent_bone' : 'f_index.01.L', 176 | 'connected' : True, 177 | 'parent_position' : 'tail', 178 | 'default_length' : 0, 179 | }, 180 | 'f_index.03.R': { 181 | 'parent_bone' : 'f_index.02.R', 182 | 'connected' : True, 183 | 'parent_position' : 'tail', 184 | 'default_length' : 0, 185 | }, 186 | 'f_index.03.L': { 187 | 'parent_bone' : 'f_index.02.L', 188 | 'connected' : True, 189 | 'parent_position' : 'tail', 190 | 'default_length' : 0, 191 | }, 192 | 'palm.02.R': { 193 | 'parent_bone' : 'hand.R', 194 | 'connected' : False, 195 | 'parent_position' : 'head', 196 | 'default_length' : 0, 197 | }, 198 | 'palm.02.L': { 199 | 'parent_bone' : 'hand.L', 200 | 'connected' : False, 201 | 'parent_position' : 'head', 202 | 'default_length' : 0, 203 | }, 204 | 'f_middle.01.R': { 205 | 'parent_bone' : 'palm.02.R', 206 | 'connected' : True, 207 | 'parent_position' : 'tail', 208 | 'default_length' : 0, 209 | }, 210 | 'f_middle.01.L': { 211 | 'parent_bone' : 'palm.02.L', 212 | 'connected' : True, 213 | 'parent_position' : 'tail', 214 | 'default_length' : 0, 215 | }, 216 | 'f_middle.02.R': { 217 | 'parent_bone' : 'f_middle.01.R', 218 | 'connected' : True, 219 | 'parent_position' : 'tail', 220 | 'default_length' : 0, 221 | }, 222 | 'f_middle.02.L': { 223 | 'parent_bone' : 'f_middle.01.L', 224 | 'connected' : True, 225 | 'parent_position' : 'tail', 226 | 'default_length' : 0, 227 | }, 228 | 'f_middle.03.R': { 229 | 'parent_bone' : 'f_middle.02.R', 230 | 'connected' : True, 231 | 'parent_position' : 'tail', 232 | 'default_length' : 0, 233 | }, 234 | 'f_middle.03.L': { 235 | 'parent_bone' : 'f_middle.02.L', 236 | 'connected' : True, 237 | 'parent_position' : 'tail', 238 | 'default_length' : 0, 239 | }, 240 | 'palm.03.R': { 241 | 'parent_bone' : 'hand.R', 242 | 'connected' : False, 243 | 'parent_position' : 'head', 244 | 'default_length' : 0, 245 | }, 246 | 'palm.03.L': { 247 | 'parent_bone' : 'hand.L', 248 | 'connected' : False, 249 | 'parent_position' : 'head', 250 | 'default_length' : 0, 251 | }, 252 | 'f_ring.01.R': { 253 | 'parent_bone' : 'palm.03.R', 254 | 'connected' : True, 255 | 'parent_position' : 'tail', 256 | 'default_length' : 0, 257 | }, 258 | 'f_ring.01.L': { 259 | 'parent_bone' : 'palm.03.L', 260 | 'connected' : True, 261 | 'parent_position' : 'tail', 262 | 'default_length' : 0, 263 | }, 264 | 'f_ring.02.R': { 265 | 'parent_bone' : 'f_ring.01.R', 266 | 'connected' : True, 267 | 'parent_position' : 'tail', 268 | 'default_length' : 0, 269 | }, 270 | 'f_ring.02.L': { 271 | 'parent_bone' : 'f_ring.01.L', 272 | 'connected' : True, 273 | 'parent_position' : 'tail', 274 | 'default_length' : 0, 275 | }, 276 | 'f_ring.03.R': { 277 | 'parent_bone' : 'f_ring.02.R', 278 | 'connected' : True, 279 | 'parent_position' : 'tail', 280 | 'default_length' : 0, 281 | }, 282 | 'f_ring.03.L': { 283 | 'parent_bone' : 'f_ring.02.L', 284 | 'connected' : True, 285 | 'parent_position' : 'tail', 286 | 'default_length' : 0, 287 | }, 288 | 'palm.04.R': { 289 | 'parent_bone' : 'hand.R', 290 | 'connected' : False, 291 | 'parent_position' : 'head', 292 | 'default_length' : 0, 293 | }, 294 | 'palm.04.L': { 295 | 'parent_bone' : 'hand.L', 296 | 'connected' : False, 297 | 'parent_position' : 'head', 298 | 'default_length' : 0, 299 | }, 300 | 'f_pinky.01.R': { 301 | 'parent_bone' : 'palm.04.R', 302 | 'connected' : True, 303 | 'parent_position' : 'tail', 304 | 'default_length' : 0, 305 | }, 306 | 'f_pinky.01.L': { 307 | 'parent_bone' : 'palm.04.L', 308 | 'connected' : True, 309 | 'parent_position' : 'tail', 310 | 'default_length' : 0, 311 | }, 312 | 'f_pinky.02.R': { 313 | 'parent_bone' : 'f_pinky.01.R', 314 | 'connected' : True, 315 | 'parent_position' : 'tail', 316 | 'default_length' : 0, 317 | }, 318 | 'f_pinky.02.L': { 319 | 'parent_bone' : 'f_pinky.01.L', 320 | 'connected' : True, 321 | 'parent_position' : 'tail', 322 | 'default_length' : 0, 323 | }, 324 | 'f_pinky.03.R': { 325 | 'parent_bone' : 'f_pinky.02.R', 326 | 'connected' : True, 327 | 'parent_position' : 'tail', 328 | 'default_length' : 0, 329 | }, 330 | 'f_pinky.03.L': { 331 | 'parent_bone' : 'f_pinky.02.L', 332 | 'connected' : True, 333 | 'parent_position' : 'tail', 334 | 'default_length' : 0, 335 | }, 336 | 'thigh.R': { 337 | 'parent_bone' : 'pelvis.R', 338 | 'connected' : True, 339 | 'parent_position' : 'tail', 340 | 'default_length' : 0, 341 | }, 342 | 'thigh.L': { 343 | 'parent_bone' : 'pelvis.L', 344 | 'connected' : True, 345 | 'parent_position' : 'tail', 346 | 'default_length' : 0, 347 | }, 348 | 'shin.R': { 349 | 'parent_bone' : 'thigh.R', 350 | 'connected' : True, 351 | 'parent_position' : 'tail', 352 | 'default_length' : 0, 353 | }, 354 | 'shin.L': { 355 | 'parent_bone' : 'thigh.L', 356 | 'connected' : True, 357 | 'parent_position' : 'tail', 358 | 'default_length' : 0, 359 | }, 360 | 'foot.R': { 361 | 'parent_bone' : 'shin.R', 362 | 'connected' : True, 363 | 'parent_position' : 'tail', 364 | 'default_length' : 0, 365 | }, 366 | 'foot.L': { 367 | 'parent_bone' : 'shin.L', 368 | 'connected' : True, 369 | 'parent_position' : 'tail', 370 | 'default_length' : 0, 371 | }, 372 | 'heel.02.R': { 373 | 'parent_bone' : 'shin.R', 374 | 'connected' : True, 375 | 'parent_position' : 'tail', 376 | 'default_length' : 0, 377 | }, 378 | 'heel.02.L': { 379 | 'parent_bone' : 'shin.L', 380 | 'connected' : True, 381 | 'parent_position' : 'tail', 382 | 'default_length' : 0, 383 | }, 384 | } 385 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/armatures/ue_metahuman_simple.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary with the bones comforming the ue_metahuman_simple armature. 3 | """ 4 | 5 | armature_ue_metahuman_simple = { 6 | 'pelvis': { 7 | 'parent_bone' : 'root', 8 | 'connected' : False, 9 | 'parent_position' : 'head', 10 | 'default_length' : 0.05, 11 | }, 12 | 'pelvis_r': { 13 | 'parent_bone' : 'pelvis', 14 | 'connected' : False, 15 | 'parent_position' : 'head', 16 | 'default_length' : 0, 17 | }, 18 | 'pelvis_l': { 19 | 'parent_bone' : 'pelvis', 20 | 'connected' : False, 21 | 'parent_position' : 'head', 22 | 'default_length' : 0, 23 | }, 24 | 'spine_01': { 25 | 'parent_bone' : 'pelvis', 26 | 'connected' : False, 27 | 'parent_position' : 'head', 28 | 'default_length' : 0, 29 | }, 30 | 'spine_04': { 31 | 'parent_bone' : 'spine_01', 32 | 'connected' : True, 33 | 'parent_position' : 'tail', 34 | 'default_length' : 0, 35 | }, 36 | 'neck_01': { 37 | 'parent_bone' : 'spine_04', 38 | 'connected' : True, 39 | 'parent_position' : 'tail', 40 | 'default_length' : 0, 41 | }, 42 | 'face': { 43 | 'parent_bone' : 'neck_01', 44 | 'connected' : True, 45 | 'parent_position' : 'tail', 46 | 'default_length' : 0, 47 | }, 48 | 'clavicle_r': { 49 | 'parent_bone' : 'spine_04', 50 | 'connected' : True, 51 | 'parent_position' : 'tail', 52 | 'default_length' : 0, 53 | }, 54 | 'clavicle_l': { 55 | 'parent_bone' : 'spine_04', 56 | 'connected' : True, 57 | 'parent_position' : 'tail', 58 | 'default_length' : 0, 59 | }, 60 | 'upperarm_r': { 61 | 'parent_bone' : 'clavicle_r', 62 | 'connected' : True, 63 | 'parent_position' : 'tail', 64 | 'default_length' : 0, 65 | }, 66 | 'upperarm_l': { 67 | 'parent_bone' : 'clavicle_l', 68 | 'connected' : True, 69 | 'parent_position' : 'tail', 70 | 'default_length' : 0, 71 | }, 72 | 'lowerarm_r': { 73 | 'parent_bone' : 'upperarm_r', 74 | 'connected' : True, 75 | 'parent_position' : 'tail', 76 | 'default_length' : 0, 77 | }, 78 | 'lowerarm_l': { 79 | 'parent_bone' : 'upperarm_l', 80 | 'connected' : True, 81 | 'parent_position' : 'tail', 82 | 'default_length' : 0, 83 | }, 84 | 'hand_r': { 85 | 'parent_bone' : 'lowerarm_r', 86 | 'connected' : True, 87 | 'parent_position' : 'tail', 88 | 'default_length' : 0, 89 | }, 90 | 'hand_l': { 91 | 'parent_bone' : 'lowerarm_l', 92 | 'connected' : True, 93 | 'parent_position' : 'tail', 94 | 'default_length' : 0, 95 | }, 96 | 'thumb_metacarpal_r': { 97 | 'parent_bone' : 'hand_r', 98 | 'connected' : False, 99 | 'parent_position' : 'head', 100 | 'default_length' : 0, 101 | }, 102 | 'thumb_metacarpal_l': { 103 | 'parent_bone' : 'hand_l', 104 | 'connected' : False, 105 | 'parent_position' : 'head', 106 | 'default_length' : 0, 107 | }, 108 | 'thumb_01_r': { 109 | 'parent_bone' : 'thumb_metacarpal_r', 110 | 'connected' : True, 111 | 'parent_position' : 'tail', 112 | 'default_length' : 0, 113 | }, 114 | 'thumb_01_l': { 115 | 'parent_bone' : 'thumb_metacarpal_l', 116 | 'connected' : True, 117 | 'parent_position' : 'tail', 118 | 'default_length' : 0, 119 | }, 120 | 'thumb_02_r': { 121 | 'parent_bone' : 'thumb_01_r', 122 | 'connected' : True, 123 | 'parent_position' : 'tail', 124 | 'default_length' : 0, 125 | }, 126 | 'thumb_02_l': { 127 | 'parent_bone' : 'thumb_01_l', 128 | 'connected' : True, 129 | 'parent_position' : 'tail', 130 | 'default_length' : 0, 131 | }, 132 | 'thumb_03_r': { 133 | 'parent_bone' : 'thumb_02_r', 134 | 'connected' : True, 135 | 'parent_position' : 'tail', 136 | 'default_length' : 0, 137 | }, 138 | 'thumb_03_l': { 139 | 'parent_bone' : 'thumb_02_l', 140 | 'connected' : True, 141 | 'parent_position' : 'tail', 142 | 'default_length' : 0, 143 | }, 144 | 'index_metacarpal_r': { 145 | 'parent_bone' : 'hand_r', 146 | 'connected' : False, 147 | 'parent_position' : 'head', 148 | 'default_length' : 0, 149 | }, 150 | 'index_metacarpal_l': { 151 | 'parent_bone' : 'hand_l', 152 | 'connected' : False, 153 | 'parent_position' : 'head', 154 | 'default_length' : 0, 155 | }, 156 | 'index_01_r': { 157 | 'parent_bone' : 'index_metacarpal_r', 158 | 'connected' : True, 159 | 'parent_position' : 'tail', 160 | 'default_length' : 0, 161 | }, 162 | 'index_01_l': { 163 | 'parent_bone' : 'index_metacarpal_l', 164 | 'connected' : True, 165 | 'parent_position' : 'tail', 166 | 'default_length' : 0, 167 | }, 168 | 'index_02_r': { 169 | 'parent_bone' : 'index_01_r', 170 | 'connected' : True, 171 | 'parent_position' : 'tail', 172 | 'default_length' : 0, 173 | }, 174 | 'index_02_l': { 175 | 'parent_bone' : 'index_01_l', 176 | 'connected' : True, 177 | 'parent_position' : 'tail', 178 | 'default_length' : 0, 179 | }, 180 | 'index_03_r': { 181 | 'parent_bone' : 'index_02_r', 182 | 'connected' : True, 183 | 'parent_position' : 'tail', 184 | 'default_length' : 0, 185 | }, 186 | 'index_03_l': { 187 | 'parent_bone' : 'index_02_l', 188 | 'connected' : True, 189 | 'parent_position' : 'tail', 190 | 'default_length' : 0, 191 | }, 192 | 'middle_metacarpal_r': { 193 | 'parent_bone' : 'hand_r', 194 | 'connected' : False, 195 | 'parent_position' : 'head', 196 | 'default_length' : 0, 197 | }, 198 | 'middle_metacarpal_l': { 199 | 'parent_bone' : 'hand_l', 200 | 'connected' : False, 201 | 'parent_position' : 'head', 202 | 'default_length' : 0, 203 | }, 204 | 'middle_01_r': { 205 | 'parent_bone' : 'middle_metacarpal_r', 206 | 'connected' : True, 207 | 'parent_position' : 'tail', 208 | 'default_length' : 0, 209 | }, 210 | 'middle_01_l': { 211 | 'parent_bone' : 'middle_metacarpal_l', 212 | 'connected' : True, 213 | 'parent_position' : 'tail', 214 | 'default_length' : 0, 215 | }, 216 | 'middle_02_r': { 217 | 'parent_bone' : 'middle_01_r', 218 | 'connected' : True, 219 | 'parent_position' : 'tail', 220 | 'default_length' : 0, 221 | }, 222 | 'middle_02_l': { 223 | 'parent_bone' : 'middle_01_l', 224 | 'connected' : True, 225 | 'parent_position' : 'tail', 226 | 'default_length' : 0, 227 | }, 228 | 'middle_03_r': { 229 | 'parent_bone' : 'middle_02_r', 230 | 'connected' : True, 231 | 'parent_position' : 'tail', 232 | 'default_length' : 0, 233 | }, 234 | 'middle_03_l': { 235 | 'parent_bone' : 'middle_02_l', 236 | 'connected' : True, 237 | 'parent_position' : 'tail', 238 | 'default_length' : 0, 239 | }, 240 | 'ring_metacarpal_r': { 241 | 'parent_bone' : 'hand_r', 242 | 'connected' : False, 243 | 'parent_position' : 'head', 244 | 'default_length' : 0, 245 | }, 246 | 'ring_metacarpal_l': { 247 | 'parent_bone' : 'hand_l', 248 | 'connected' : False, 249 | 'parent_position' : 'head', 250 | 'default_length' : 0, 251 | }, 252 | 'ring_01_r': { 253 | 'parent_bone' : 'ring_metacarpal_r', 254 | 'connected' : True, 255 | 'parent_position' : 'tail', 256 | 'default_length' : 0, 257 | }, 258 | 'ring_01_l': { 259 | 'parent_bone' : 'ring_metacarpal_l', 260 | 'connected' : True, 261 | 'parent_position' : 'tail', 262 | 'default_length' : 0, 263 | }, 264 | 'ring_02_r': { 265 | 'parent_bone' : 'ring_01_r', 266 | 'connected' : True, 267 | 'parent_position' : 'tail', 268 | 'default_length' : 0, 269 | }, 270 | 'ring_02_l': { 271 | 'parent_bone' : 'ring_01_l', 272 | 'connected' : True, 273 | 'parent_position' : 'tail', 274 | 'default_length' : 0, 275 | }, 276 | 'ring_03_r': { 277 | 'parent_bone' : 'ring_02_r', 278 | 'connected' : True, 279 | 'parent_position' : 'tail', 280 | 'default_length' : 0, 281 | }, 282 | 'ring_03_l': { 283 | 'parent_bone' : 'ring_02_l', 284 | 'connected' : True, 285 | 'parent_position' : 'tail', 286 | 'default_length' : 0, 287 | }, 288 | 'pinky_metacarpal_r': { 289 | 'parent_bone' : 'hand_r', 290 | 'connected' : False, 291 | 'parent_position' : 'head', 292 | 'default_length' : 0, 293 | }, 294 | 'pinky_metacarpal_l': { 295 | 'parent_bone' : 'hand_l', 296 | 'connected' : False, 297 | 'parent_position' : 'head', 298 | 'default_length' : 0, 299 | }, 300 | 'pinky_01_r': { 301 | 'parent_bone' : 'pinky_metacarpal_r', 302 | 'connected' : True, 303 | 'parent_position' : 'tail', 304 | 'default_length' : 0, 305 | }, 306 | 'pinky_01_l': { 307 | 'parent_bone' : 'pinky_metacarpal_l', 308 | 'connected' : True, 309 | 'parent_position' : 'tail', 310 | 'default_length' : 0, 311 | }, 312 | 'pinky_02_r': { 313 | 'parent_bone' : 'pinky_01_r', 314 | 'connected' : True, 315 | 'parent_position' : 'tail', 316 | 'default_length' : 0, 317 | }, 318 | 'pinky_02_l': { 319 | 'parent_bone' : 'pinky_01_l', 320 | 'connected' : True, 321 | 'parent_position' : 'tail', 322 | 'default_length' : 0, 323 | }, 324 | 'pinky_03_r': { 325 | 'parent_bone' : 'pinky_02_r', 326 | 'connected' : True, 327 | 'parent_position' : 'tail', 328 | 'default_length' : 0, 329 | }, 330 | 'pinky_03_l': { 331 | 'parent_bone' : 'pinky_02_l', 332 | 'connected' : True, 333 | 'parent_position' : 'tail', 334 | 'default_length' : 0, 335 | }, 336 | 'thigh_r': { 337 | 'parent_bone' : 'pelvis_r', 338 | 'connected' : True, 339 | 'parent_position' : 'tail', 340 | 'default_length' : 0, 341 | }, 342 | 'thigh_l': { 343 | 'parent_bone' : 'pelvis_l', 344 | 'connected' : True, 345 | 'parent_position' : 'tail', 346 | 'default_length' : 0, 347 | }, 348 | 'calf_r': { 349 | 'parent_bone' : 'thigh_r', 350 | 'connected' : True, 351 | 'parent_position' : 'tail', 352 | 'default_length' : 0, 353 | }, 354 | 'calf_l': { 355 | 'parent_bone' : 'thigh_l', 356 | 'connected' : True, 357 | 'parent_position' : 'tail', 358 | 'default_length' : 0, 359 | }, 360 | 'foot_r': { 361 | 'parent_bone' : 'calf_r', 362 | 'connected' : True, 363 | 'parent_position' : 'tail', 364 | 'default_length' : 0, 365 | }, 366 | 'foot_l': { 367 | 'parent_bone' : 'calf_l', 368 | 'connected' : True, 369 | 'parent_position' : 'tail', 370 | 'default_length' : 0, 371 | }, 372 | 'heel_r': { 373 | 'parent_bone' : 'calf_r', 374 | 'connected' : True, 375 | 'parent_position' : 'tail', 376 | 'default_length' : 0, 377 | }, 378 | 'heel_l': { 379 | 'parent_bone' : 'calf_l', 380 | 'connected' : True, 381 | 'parent_position' : 'tail', 382 | 'default_length' : 0, 383 | }, 384 | } 385 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/empties_dict.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary containing empty children for each of the capture empties. 3 | Also has categories for implementing butterworth filters. 4 | """ 5 | empties_dict = { 6 | 'hips_center': { 7 | 'children' : ['right_hip', 'left_hip', 'trunk_center'], 8 | 'category' : 'core', 9 | 'tail_of_bone' : ''}, 10 | 'trunk_center': { 11 | 'children' : ['neck_center'], 12 | 'category' : 'core', 13 | 'tail_of_bone' : 'spine'}, 14 | 'neck_center': { 15 | 'children' : ['right_shoulder', 'left_shoulder', 'head_center'], 16 | 'category' : 'core', 17 | 'tail_of_bone' : 'spine.001'}, 18 | 'head_center': { 19 | 'children' : [ 20 | 'nose', 21 | 'mouth_right', 22 | 'mouth_left', 23 | 'right_eye', 24 | 'right_eye_inner', 25 | 'right_eye_outer', 26 | 'left_eye', 27 | 'left_eye_inner', 28 | 'left_eye_outer', 29 | 'right_ear', 30 | 'left_ear'], 31 | 'category' : 'core', 32 | 'tail_of_bone' : 'neck'}, 33 | 'right_shoulder': { 34 | 'children' : ['right_elbow'], 35 | 'category' : 'arms', 36 | 'tail_of_bone' : 'shoulder.R'}, 37 | 'left_shoulder': { 38 | 'children' : ['left_elbow'], 39 | 'category' : 'arms', 40 | 'tail_of_bone' : 'shoulder.L'}, 41 | 'right_elbow': { 42 | 'children' : ['right_wrist'], 43 | 'category' : 'arms', 44 | 'tail_of_bone' : 'upper_arm.R'}, 45 | 'left_elbow': { 46 | 'children' : ['left_wrist'], 47 | 'category' : 'arms', 48 | 'tail_of_bone' : 'upper_arm.L'}, 49 | 'right_wrist': { 50 | 'children' : [ 51 | 'right_thumb', 52 | 'right_index', 53 | 'right_pinky', 54 | 'right_hand', 55 | 'right_hand_middle', 56 | 'right_hand_wrist'], 57 | 'category' : 'hands', 58 | 'tail_of_bone' : 'forearm.R'}, 59 | 'left_wrist': { 60 | 'children' : [ 61 | 'left_thumb', 62 | 'left_index', 63 | 'left_pinky', 64 | 'left_hand', 65 | 'left_hand_middle', 66 | 'left_hand_wrist'], 67 | 'category' : 'hands', 68 | 'tail_of_bone' : 'forearm.L'}, 69 | 'right_hand_middle': { 70 | 'children' : [], 71 | 'category' : 'hands', 72 | 'tail_of_bone' : 'hand.R'}, 73 | 'left_hand_middle': { 74 | 'children' : [], 75 | 'category' : 'hands', 76 | 'tail_of_bone' : 'hand.L'}, 77 | 'right_hand_wrist': { 78 | 'children' : [ 79 | 'right_hand_thumb_cmc', 80 | 'right_hand_index_finger_mcp', 81 | 'right_hand_middle_finger_mcp', 82 | 'right_hand_ring_finger_mcp', 83 | 'right_hand_pinky_mcp'], 84 | 'category' : 'hands', 85 | 'tail_of_bone' : ''}, 86 | 'left_hand_wrist': { 87 | 'children' : [ 88 | 'left_hand_thumb_cmc', 89 | 'left_hand_index_finger_mcp', 90 | 'left_hand_middle_finger_mcp', 91 | 'left_hand_ring_finger_mcp', 92 | 'left_hand_pinky_mcp'], 93 | 'category' : 'hands', 94 | 'tail_of_bone' : ''}, 95 | 'right_hand_thumb_cmc': { 96 | 'children' : ['right_hand_thumb_mcp'], 97 | 'category' : 'fingers', 98 | 'tail_of_bone' : 'thumb.carpal.R'}, 99 | 'left_hand_thumb_cmc': { 100 | 'children' : ['left_hand_thumb_mcp'], 101 | 'category' : 'fingers', 102 | 'tail_of_bone' : 'thumb.carpal.L'}, 103 | 'right_hand_thumb_mcp': { 104 | 'children' : ['right_hand_thumb_ip'], 105 | 'category' : 'fingers', 106 | 'tail_of_bone' : 'thumb.01.R'}, 107 | 'left_hand_thumb_mcp': { 108 | 'children' : ['left_hand_thumb_ip'], 109 | 'category' : 'fingers', 110 | 'tail_of_bone' : 'thumb.01.L'}, 111 | 'right_hand_thumb_ip': { 112 | 'children' : ['right_hand_thumb_tip'], 113 | 'category' : 'fingers', 114 | 'tail_of_bone' : 'thumb.02.R'}, 115 | 'left_hand_thumb_ip': { 116 | 'children' : ['left_hand_thumb_tip'], 117 | 'category' : 'fingers', 118 | 'tail_of_bone' : 'thumb.02.L'}, 119 | 'right_hand_thumb_tip': { 120 | 'children' : [], 121 | 'category' : 'fingers', 122 | 'tail_of_bone' : 'thumb.03.R'}, 123 | 'left_hand_thumb_tip': { 124 | 'children' : [], 125 | 'category' : 'fingers', 126 | 'tail_of_bone' : 'thumb.03.L'}, 127 | 'right_hand_index_finger_mcp': { 128 | 'children' : ['right_hand_index_finger_pip'], 129 | 'category' : 'fingers', 130 | 'tail_of_bone' : 'palm.01.R'}, 131 | 'left_hand_index_finger_mcp': { 132 | 'children' : ['left_hand_index_finger_pip'], 133 | 'category' : 'fingers', 134 | 'tail_of_bone' : 'palm.01.L'}, 135 | 'right_hand_index_finger_pip': { 136 | 'children' : ['right_hand_index_finger_dip'], 137 | 'category' : 'fingers', 138 | 'tail_of_bone' : 'f_index.01.R'}, 139 | 'left_hand_index_finger_pip': { 140 | 'children' : ['left_hand_index_finger_dip'], 141 | 'category' : 'fingers', 142 | 'tail_of_bone' : 'f_index.01.L'}, 143 | 'right_hand_index_finger_dip': { 144 | 'children' : ['right_hand_index_finger_tip'], 145 | 'category' : 'fingers', 146 | 'tail_of_bone' : 'f_index.02.R'}, 147 | 'left_hand_index_finger_dip': { 148 | 'children' : ['left_hand_index_finger_tip'], 149 | 'category' : 'fingers', 150 | 'tail_of_bone' : 'f_index.02.L'}, 151 | 'right_hand_index_finger_tip': { 152 | 'children' : [], 153 | 'category' : 'fingers', 154 | 'tail_of_bone' : 'f_index.03.R'}, 155 | 'left_hand_index_finger_tip': { 156 | 'children' : [], 157 | 'category' : 'fingers', 158 | 'tail_of_bone' : 'f_index.03.L'}, 159 | 'right_hand_middle_finger_mcp': { 160 | 'children' : ['right_hand_middle_finger_pip'], 161 | 'category' : 'fingers', 162 | 'tail_of_bone' : 'palm.02.R'}, 163 | 'left_hand_middle_finger_mcp': { 164 | 'children' : ['left_hand_middle_finger_pip'], 165 | 'category' : 'fingers', 166 | 'tail_of_bone' : 'palm.02.L'}, 167 | 'right_hand_middle_finger_pip': { 168 | 'children' : ['right_hand_middle_finger_dip'], 169 | 'category' : 'fingers', 170 | 'tail_of_bone' : 'f_middle.01.R'}, 171 | 'left_hand_middle_finger_pip': { 172 | 'children' : ['left_hand_middle_finger_dip'], 173 | 'category' : 'fingers', 174 | 'tail_of_bone' : 'f_middle.01.L'}, 175 | 'right_hand_middle_finger_dip': { 176 | 'children' : ['right_hand_middle_finger_tip'], 177 | 'category' : 'fingers', 178 | 'tail_of_bone' : 'f_middle.02.R'}, 179 | 'left_hand_middle_finger_dip': { 180 | 'children' : ['left_hand_middle_finger_tip'], 181 | 'category' : 'fingers', 182 | 'tail_of_bone' : 'f_middle.02.L'}, 183 | 'right_hand_middle_finger_tip': { 184 | 'children' : [], 185 | 'category' : 'fingers', 186 | 'tail_of_bone' : 'f_middle.03.R'}, 187 | 'left_hand_middle_finger_tip': { 188 | 'children' : [], 189 | 'category' : 'fingers', 190 | 'tail_of_bone' : 'f_middle.03.L'}, 191 | 'right_hand_ring_finger_mcp': { 192 | 'children' : ['right_hand_ring_finger_pip'], 193 | 'category' : 'fingers', 194 | 'tail_of_bone' : 'palm.03.R'}, 195 | 'left_hand_ring_finger_mcp': { 196 | 'children' : ['left_hand_ring_finger_pip'], 197 | 'category' : 'fingers', 198 | 'tail_of_bone' : 'palm.03.L'}, 199 | 'right_hand_ring_finger_pip': { 200 | 'children' : ['right_hand_ring_finger_dip'], 201 | 'category' : 'fingers', 202 | 'tail_of_bone' : 'f_ring.01.R'}, 203 | 'left_hand_ring_finger_pip': { 204 | 'children' : ['left_hand_ring_finger_dip'], 205 | 'category' : 'fingers', 206 | 'tail_of_bone' : 'f_ring.01.L'}, 207 | 'right_hand_ring_finger_dip': { 208 | 'children' : ['right_hand_ring_finger_tip'], 209 | 'category' : 'fingers', 210 | 'tail_of_bone' : 'f_ring.02.R'}, 211 | 'left_hand_ring_finger_dip': { 212 | 'children' : ['left_hand_ring_finger_tip'], 213 | 'category' : 'fingers', 214 | 'tail_of_bone' : 'f_ring.02.L'}, 215 | 'right_hand_ring_finger_tip': { 216 | 'children' : [], 217 | 'category' : 'fingers', 218 | 'tail_of_bone' : 'f_ring.03.R'}, 219 | 'left_hand_ring_finger_tip': { 220 | 'children' : [], 221 | 'category' : 'fingers', 222 | 'tail_of_bone' : 'f_ring.03.L'}, 223 | 'right_hand_pinky_mcp': { 224 | 'children' : ['right_hand_pinky_pip'], 225 | 'category' : 'fingers', 226 | 'tail_of_bone' : 'palm.04.R'}, 227 | 'left_hand_pinky_mcp': { 228 | 'children' : ['left_hand_pinky_pip'], 229 | 'category' : 'fingers', 230 | 'tail_of_bone' : 'palm.04.L'}, 231 | 'right_hand_pinky_pip': { 232 | 'children' : ['right_hand_pinky_dip'], 233 | 'category' : 'fingers', 234 | 'tail_of_bone' : 'f_pinky.01.R'}, 235 | 'left_hand_pinky_pip': { 236 | 'children' : ['left_hand_pinky_dip'], 237 | 'category' : 'fingers', 238 | 'tail_of_bone' : 'f_pinky.01.L'}, 239 | 'right_hand_pinky_dip': { 240 | 'children' : ['right_hand_pinky_tip'], 241 | 'category' : 'fingers', 242 | 'tail_of_bone' : 'f_pinky.02.R'}, 243 | 'left_hand_pinky_dip': { 244 | 'children' : ['left_hand_pinky_tip'], 245 | 'category' : 'fingers', 246 | 'tail_of_bone' : 'f_pinky.02.L'}, 247 | 'right_hand_pinky_tip': { 248 | 'children' : [], 249 | 'category' : 'fingers', 250 | 'tail_of_bone' : 'f_pinky.03.R'}, 251 | 'left_hand_pinky_tip': { 252 | 'children' : [], 253 | 'category' : 'fingers', 254 | 'tail_of_bone' : 'f_pinky.03.L'}, 255 | 'right_hip': { 256 | 'children' : ['right_knee'], 257 | 'category' : 'legs', 258 | 'tail_of_bone' : 'pelvis.R'}, 259 | 'left_hip': { 260 | 'children' : ['left_knee'], 261 | 'category' : 'legs', 262 | 'tail_of_bone' : 'pelvis.L'}, 263 | 'right_knee': { 264 | 'children' : ['right_ankle'], 265 | 'category' : 'legs', 266 | 'tail_of_bone' : 'thigh.R'}, 267 | 'left_knee': { 268 | 'children' : ['left_ankle'], 269 | 'category' : 'legs', 270 | 'tail_of_bone' : 'thigh.L'}, 271 | 'right_ankle': { 272 | 'children' : ['right_foot_index', 'right_heel'], 273 | 'category' : 'feet', 274 | 'tail_of_bone' : 'shin.R'}, 275 | 'left_ankle': { 276 | 'children' : ['left_foot_index', 'left_heel'], 277 | 'category' : 'feet', 278 | 'tail_of_bone' : 'shin.L'}, 279 | 'right_heel': { 280 | 'children' : [], 281 | 'category' : 'feet', 282 | 'tail_of_bone' : 'heel.02.R'}, 283 | 'left_heel': { 284 | 'children' : [], 285 | 'category' : 'feet', 286 | 'tail_of_bone' : 'heel.02.L'}, 287 | 'right_foot_index': { 288 | 'children' : [], 289 | 'category' : 'feet', 290 | 'tail_of_bone' : 'foot.R'}, 291 | 'left_foot_index': { 292 | 'children' : [], 293 | 'category' : 'feet', 294 | 'tail_of_bone' : 'foot.L'}, 295 | } 296 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/foot_locking_markers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary containing markers for foot locking, including base, ankle, 3 | bones, and compensation markers for left and right feet. 4 | """ 5 | foot_locking_markers = { 6 | 'left_foot': { 7 | 'base': ['left_foot_index', 'left_heel'], 8 | 'ankle': ['left_ankle'], 9 | 'bones': ['foot.L', 'heel.02.L'], 10 | 'compensation_markers': ['left_knee', 'left_hip'] 11 | }, 12 | 'right_foot': { 13 | 'base': ['right_foot_index', 'right_heel'], 14 | 'ankle': ['right_ankle'], 15 | 'bones': ['foot.R', 'heel.02.R'], 16 | 'compensation_markers': ['right_knee', 'right_hip'] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/ik_control_bones.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary of the control bones parameters to animate when adding the 3 | rig with IK constraints. 4 | """ 5 | ik_control_bones = { 6 | 'hand.IK.R': { 7 | 'controlled_bone': 'hand.R', 8 | 'tail_relative_position': (-0.1, 0, 0), 9 | }, 10 | 'hand.IK.L': { 11 | 'controlled_bone': 'hand.L', 12 | 'tail_relative_position': (0.1, 0, 0), 13 | }, 14 | 'foot.IK.R': { 15 | 'controlled_bone': 'foot.R', 16 | 'tail_relative_position': (-0.1, 0, 0), 17 | }, 18 | 'foot.IK.L': { 19 | 'controlled_bone': 'foot.L', 20 | 'tail_relative_position': (0.1, 0, 0), 21 | }, 22 | } -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/ik_pole_bones.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary of the pole bones parameters to animate when adding the 3 | rig with IK constraints. 4 | """ 5 | ik_pole_bones = { 6 | 'arm_pole_target.R': { 7 | 'base_marker': 'right_shoulder', 8 | 'pole_marker': 'right_elbow', 9 | 'target_marker': 'right_wrist', 10 | 'aux_markers': ['right_wrist', 'right_hand_thumb_cmc'], 11 | 'head_position': (0, 0, 0), 12 | 'tail_position': (0, 0.25, 0), 13 | }, 14 | 'arm_pole_target.L': { 15 | 'base_marker': 'left_shoulder', 16 | 'pole_marker': 'left_elbow', 17 | 'target_marker': 'left_wrist', 18 | 'aux_markers': ['left_wrist', 'left_hand_thumb_cmc'], 19 | 'head_position': (0, 0, 0), 20 | 'tail_position': (0, 0.25, 0), 21 | }, 22 | 'leg_pole_target.R': { 23 | 'base_marker': 'right_hip', 24 | 'pole_marker': 'right_knee', 25 | 'target_marker': 'right_ankle', 26 | 'aux_markers': ['right_ankle', 'right_heel'], 27 | 'head_position': (0, 0, 0), 28 | 'tail_position': (0, 0.25, 0), 29 | }, 30 | 'leg_pole_target.L': { 31 | 'base_marker': 'left_hip', 32 | 'pole_marker': 'left_knee', 33 | 'target_marker': 'left_ankle', 34 | 'aux_markers': ['left_ankle', 'left_heel'], 35 | 'head_position': (0, 0, 0), 36 | 'tail_position': (0, 0.25, 0), 37 | }, 38 | } 39 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/data_definitions/interface/__init__.py -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/data_definitions/interface/panels/__init__.py -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/add_armature_panel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | 4 | def draw_add_armature_panel(context, layout): 5 | fmc_adapter_tool = context.scene.fmc_adapter_tool 6 | 7 | # Create a button to toggle Add Armature Options 8 | row = layout.row(align=True) 9 | row.prop( 10 | fmc_adapter_tool.add_armature_properties, 11 | "show_add_rig", 12 | text="", 13 | icon='TRIA_DOWN' if 14 | fmc_adapter_tool.add_armature_properties.show_add_rig 15 | else 'TRIA_RIGHT', 16 | emboss=False 17 | ) 18 | row.label(text="Add Armature") 19 | 20 | if fmc_adapter_tool.add_armature_properties.show_add_rig: 21 | 22 | # Add Rig Options 23 | box = layout.box() 24 | 25 | split = box.column().row().split(factor=0.6) 26 | split.column().label(text='Add Armature Method') 27 | split.split().column().prop( 28 | fmc_adapter_tool.add_armature_properties, 29 | 'add_rig_method' 30 | ) 31 | 32 | split = box.column().row().split(factor=0.6) 33 | split.column().label(text='Armature') 34 | split.split().column().prop( 35 | fmc_adapter_tool.add_armature_properties, 36 | 'armature' 37 | ) 38 | 39 | split = box.column().row().split(factor=0.6) 40 | split.column().label(text='Pose') 41 | split.split().column().prop( 42 | fmc_adapter_tool.add_armature_properties, 43 | 'pose' 44 | ) 45 | 46 | split = box.column().row().split(factor=0.6) 47 | split.column().label(text='Keep right/left symmetry') 48 | split.split().column().prop( 49 | fmc_adapter_tool.add_armature_properties, 50 | 'keep_symmetry' 51 | ) 52 | 53 | split = box.column().row().split(factor=0.6) 54 | split.column().label(text='Add finger constraints') 55 | split.split().column().prop( 56 | fmc_adapter_tool.add_armature_properties, 57 | 'add_fingers_constraints' 58 | ) 59 | 60 | split = box.column().row().split(factor=0.6) 61 | split.column().label(text='Add IK constraints') 62 | split.split().column().prop( 63 | fmc_adapter_tool.add_armature_properties, 64 | 'add_ik_constraints' 65 | ) 66 | 67 | split = box.column().row().split(factor=0.6) 68 | split.column().label(text='IK transition threshold') 69 | split.split().column().prop( 70 | fmc_adapter_tool.add_armature_properties, 71 | 'ik_transition_threshold' 72 | ) 73 | 74 | split = box.column().row().split(factor=0.6) 75 | split.column().label(text='Add rotation limits') 76 | split.split().column().prop( 77 | fmc_adapter_tool.add_armature_properties, 78 | 'use_limit_rotation' 79 | ) 80 | 81 | split = box.column().row().split(factor=0.6) 82 | split.column().label(text='Clear constraints') 83 | split.split().column().prop( 84 | fmc_adapter_tool.add_armature_properties, 85 | 'clear_constraints' 86 | ) 87 | 88 | box.operator( 89 | 'fmc_adapter.add_rig', 90 | text='6. Add Armature' 91 | ) 92 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/add_body_mesh_panel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | 4 | def draw_add_body_mesh_panel(context, layout): 5 | fmc_adapter_tool = context.scene.fmc_adapter_tool 6 | 7 | # Create a button to toggle Add Body Mesh Options 8 | row = layout.row(align=True) 9 | row.prop( 10 | fmc_adapter_tool.add_body_mesh_properties, 11 | "show_add_body_mesh", 12 | text="", 13 | icon='TRIA_DOWN' if 14 | fmc_adapter_tool.add_body_mesh_properties.show_add_body_mesh 15 | else 'TRIA_RIGHT', 16 | emboss=False 17 | ) 18 | row.label(text="Add Body Mesh") 19 | 20 | if fmc_adapter_tool.add_body_mesh_properties.show_add_body_mesh: 21 | 22 | # Add Body Mesh Options 23 | box = layout.box() 24 | 25 | split = box.column().row().split(factor=0.6) 26 | split.column().label(text='Body Mesh Mode') 27 | split.split().column().prop( 28 | fmc_adapter_tool.add_body_mesh_properties, 29 | 'body_mesh_mode' 30 | ) 31 | 32 | box.operator( 33 | 'fmc_adapter.add_body_mesh', 34 | text='7. Add Body Mesh' 35 | ) 36 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/add_finger_rotation_limits_panel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | 4 | def draw_add_finger_rotation_limits_panel(context, layout): 5 | fmc_adapter_tool = context.scene.fmc_adapter_tool 6 | 7 | # Create a button to toggle Add Finger Rotation Limits Options 8 | row = layout.row(align=True) 9 | row.prop( 10 | fmc_adapter_tool.add_finger_rotation_limits_properties, 11 | "show_add_finger_rotation_limits", 12 | text="", 13 | icon='TRIA_DOWN' if 14 | fmc_adapter_tool.add_finger_rotation_limits_properties.show_add_finger_rotation_limits 15 | else 'TRIA_RIGHT', 16 | emboss=False 17 | ) 18 | row.label(text="Add Finger Rotation Limits") 19 | 20 | if fmc_adapter_tool.add_finger_rotation_limits_properties.show_add_finger_rotation_limits: 21 | 22 | # Add Finger Rotation Limits 23 | box = layout.box() 24 | box.operator( 25 | 'fmc_adapter.add_finger_rotation_limits', 26 | text='4. Add Finger Rotation Limits' 27 | ) 28 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/adjust_empties_panel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | 4 | def draw_adjust_empties_panel(context, layout): 5 | fmc_adapter_tool = context.scene.fmc_adapter_tool 6 | 7 | # Create a button to toggle Adjust Empties Options 8 | row = layout.row(align=True) 9 | row.prop( 10 | fmc_adapter_tool.adjust_empties_properties, 11 | "show_adjust_empties", 12 | text="", 13 | icon='TRIA_DOWN' if 14 | fmc_adapter_tool.adjust_empties_properties.show_adjust_empties 15 | else 'TRIA_RIGHT', 16 | emboss=False 17 | ) 18 | row.label(text="Adjust Empties") 19 | 20 | if fmc_adapter_tool.adjust_empties_properties.show_adjust_empties: 21 | 22 | # Adjust Empties Options 23 | box = layout.box() 24 | 25 | split = box.column().row().split(factor=0.6) 26 | split.column().label(text='Align Reference') 27 | split.split().column().prop( 28 | fmc_adapter_tool.adjust_empties_properties, 29 | 'vertical_align_reference' 30 | ) 31 | 32 | split = box.column().row().split(factor=0.6) 33 | split.column().label(text='Vertical Angle Offset') 34 | split.split().column().prop( 35 | fmc_adapter_tool.adjust_empties_properties, 36 | 'vertical_align_angle_offset' 37 | ) 38 | 39 | split = box.column().row().split(factor=0.6) 40 | split.column().label(text='Ground Reference') 41 | split.split().column().prop( 42 | fmc_adapter_tool.adjust_empties_properties, 43 | 'ground_align_reference' 44 | ) 45 | 46 | split = box.column().row().split(factor=0.6) 47 | split.column().label(text='Vertical Position Offset') 48 | split.split().column().prop( 49 | fmc_adapter_tool.adjust_empties_properties, 50 | 'vertical_align_position_offset' 51 | ) 52 | 53 | split = box.column().row().split(factor=0.6) 54 | split.column().label(text='Correct Fingers Empties') 55 | split.split().column().prop( 56 | fmc_adapter_tool.adjust_empties_properties, 57 | 'correct_fingers_empties' 58 | ) 59 | 60 | split = box.column().row().split(factor=0.6) 61 | split.column().label(text='Add hand middle empty') 62 | split.split().column().prop( 63 | fmc_adapter_tool.adjust_empties_properties, 64 | 'add_hand_middle_empty' 65 | ) 66 | 67 | box.operator( 68 | 'fmc_adapter.adjust_empties', 69 | text='1. Adjust Empties' 70 | ) 71 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/apply_butterworth_filters_panel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | 4 | def draw_apply_butterworth_filters_panel(context, layout, scipy_available): 5 | fmc_adapter_tool = context.scene.fmc_adapter_tool 6 | 7 | # Create a button to toggle Apply Butterwort Filters Options 8 | row = layout.row(align=True) 9 | row.prop( 10 | fmc_adapter_tool.apply_butterworth_filters_properties, 11 | "show_apply_butterworth_filters", 12 | text="", 13 | icon='TRIA_DOWN' if 14 | fmc_adapter_tool.apply_butterworth_filters_properties.show_apply_butterworth_filters 15 | else 'TRIA_RIGHT', 16 | emboss=False 17 | ) 18 | row.label(text="Apply Butterworth Filters (Blender 4.0+)") 19 | 20 | if fmc_adapter_tool.apply_butterworth_filters_properties.show_apply_butterworth_filters: 21 | 22 | # Apply Butterworth Filters 23 | box = layout.box() 24 | 25 | split = box.column().row().split(factor=0.15) 26 | split.column().label(text='Section') 27 | split_titles = split.column().split(factor=0.3) 28 | split_titles.split().column().label(text='Global (Freq)') 29 | split_titles.split().column().label(text='Local (Freq, Origin)') 30 | 31 | split = box.column().row().split(factor=0.15) 32 | split.column().label(text='Core') 33 | split_params = split.column().split(factor=0.3) 34 | split1 = split_params.column().split(factor=0.15) 35 | split1.column().prop( 36 | fmc_adapter_tool.apply_butterworth_filters_properties, 37 | 'apply_global_filter_core' 38 | ) 39 | split1.column().prop( 40 | fmc_adapter_tool.apply_butterworth_filters_properties, 41 | 'global_filter_core_frequency' 42 | ) 43 | if not scipy_available: 44 | split_params.column().label(text='Install scipy module') 45 | else: 46 | split2 = split_params.column().split(factor=0.07) 47 | split2.column().prop( 48 | fmc_adapter_tool.apply_butterworth_filters_properties, 49 | 'apply_local_filter_core' 50 | ) 51 | split3 = split2.column().split(factor=0.5) 52 | split3.column().prop( 53 | fmc_adapter_tool.apply_butterworth_filters_properties, 54 | 'local_filter_core_frequency' 55 | ) 56 | split3.column().prop( 57 | fmc_adapter_tool.apply_butterworth_filters_properties, 58 | 'local_filter_origin_core' 59 | ) 60 | 61 | split = box.column().row().split(factor=0.15) 62 | split.column().label(text='Arms') 63 | split_params = split.column().split(factor=0.3) 64 | split1 = split_params.column().split(factor=0.15) 65 | split1.column().prop( 66 | fmc_adapter_tool.apply_butterworth_filters_properties, 67 | 'apply_global_filter_arms' 68 | ) 69 | split1.column().prop( 70 | fmc_adapter_tool.apply_butterworth_filters_properties, 71 | 'global_filter_arms_frequency' 72 | ) 73 | if not scipy_available: 74 | split_params.column().label(text='Install scipy module') 75 | else: 76 | split2 = split_params.column().split(factor=0.07) 77 | split2.column().prop( 78 | fmc_adapter_tool.apply_butterworth_filters_properties, 79 | 'apply_local_filter_arms' 80 | ) 81 | split3 = split2.column().split(factor=0.5) 82 | split3.column().prop( 83 | fmc_adapter_tool.apply_butterworth_filters_properties, 84 | 'local_filter_arms_frequency' 85 | ) 86 | split3.column().prop( 87 | fmc_adapter_tool.apply_butterworth_filters_properties, 88 | 'local_filter_origin_arms' 89 | ) 90 | 91 | split = box.column().row().split(factor=0.15) 92 | split.column().label(text='Hands') 93 | split_params = split.column().split(factor=0.3) 94 | split1 = split_params.column().split(factor=0.15) 95 | split1.column().prop( 96 | fmc_adapter_tool.apply_butterworth_filters_properties, 97 | 'apply_global_filter_hands' 98 | ) 99 | split1.column().prop( 100 | fmc_adapter_tool.apply_butterworth_filters_properties, 101 | 'global_filter_hands_frequency' 102 | ) 103 | if not scipy_available: 104 | split_params.column().label(text='Install scipy module') 105 | else: 106 | split2 = split_params.column().split(factor=0.07) 107 | split2.column().prop( 108 | fmc_adapter_tool.apply_butterworth_filters_properties, 109 | 'apply_local_filter_hands' 110 | ) 111 | split3 = split2.column().split(factor=0.5) 112 | split3.column().prop( 113 | fmc_adapter_tool.apply_butterworth_filters_properties, 114 | 'local_filter_hands_frequency' 115 | ) 116 | split3.column().prop( 117 | fmc_adapter_tool.apply_butterworth_filters_properties, 118 | 'local_filter_origin_hands' 119 | ) 120 | 121 | split = box.column().row().split(factor=0.15) 122 | split.column().label(text='Fingers') 123 | split_params = split.column().split(factor=0.3) 124 | split1 = split_params.column().split(factor=0.15) 125 | split1.column().prop( 126 | fmc_adapter_tool.apply_butterworth_filters_properties, 127 | 'apply_global_filter_fingers' 128 | ) 129 | split1.column().prop( 130 | fmc_adapter_tool.apply_butterworth_filters_properties, 131 | 'global_filter_fingers_frequency' 132 | ) 133 | if not scipy_available: 134 | split_params.column().label(text='Install scipy module') 135 | else: 136 | split2 = split_params.column().split(factor=0.07) 137 | split2.column().prop( 138 | fmc_adapter_tool.apply_butterworth_filters_properties, 139 | 'apply_local_filter_fingers' 140 | ) 141 | split3 = split2.column().split(factor=0.5) 142 | split3.column().prop( 143 | fmc_adapter_tool.apply_butterworth_filters_properties, 144 | 'local_filter_fingers_frequency' 145 | ) 146 | split3.column().prop( 147 | fmc_adapter_tool.apply_butterworth_filters_properties, 148 | 'local_filter_origin_fingers' 149 | ) 150 | 151 | split = box.column().row().split(factor=0.15) 152 | split.column().label(text='Legs') 153 | split_params = split.column().split(factor=0.3) 154 | split1 = split_params.column().split(factor=0.15) 155 | split1.column().prop( 156 | fmc_adapter_tool.apply_butterworth_filters_properties, 157 | 'apply_global_filter_legs' 158 | ) 159 | split1.column().prop( 160 | fmc_adapter_tool.apply_butterworth_filters_properties, 161 | 'global_filter_legs_frequency' 162 | ) 163 | if not scipy_available: 164 | split_params.column().label(text='Install scipy module') 165 | else: 166 | split2 = split_params.column().split(factor=0.07) 167 | split2.column().prop( 168 | fmc_adapter_tool.apply_butterworth_filters_properties, 169 | 'apply_local_filter_legs' 170 | ) 171 | split3 = split2.column().split(factor=0.5) 172 | split3.column().prop( 173 | fmc_adapter_tool.apply_butterworth_filters_properties, 174 | 'local_filter_legs_frequency' 175 | ) 176 | split3.column().prop( 177 | fmc_adapter_tool.apply_butterworth_filters_properties, 178 | 'local_filter_origin_legs' 179 | ) 180 | 181 | split = box.column().row().split(factor=0.15) 182 | split.column().label(text='Feet') 183 | split_params = split.column().split(factor=0.3) 184 | split1 = split_params.column().split(factor=0.15) 185 | split1.column().prop( 186 | fmc_adapter_tool.apply_butterworth_filters_properties, 187 | 'apply_global_filter_feet' 188 | ) 189 | split1.column().prop( 190 | fmc_adapter_tool.apply_butterworth_filters_properties, 191 | 'global_filter_feet_frequency' 192 | ) 193 | if not scipy_available: 194 | split_params.column().label(text='Install scipy module') 195 | else: 196 | split2 = split_params.column().split(factor=0.07) 197 | split2.column().prop( 198 | fmc_adapter_tool.apply_butterworth_filters_properties, 199 | 'apply_local_filter_feet' 200 | ) 201 | split3 = split2.column().split(factor=0.5) 202 | split3.column().prop( 203 | fmc_adapter_tool.apply_butterworth_filters_properties, 204 | 'local_filter_feet_frequency' 205 | ) 206 | split3.column().prop( 207 | fmc_adapter_tool.apply_butterworth_filters_properties, 208 | 'local_filter_origin_feet' 209 | ) 210 | 211 | box.operator( 212 | 'fmc_adapter.apply_butterworth_filters', 213 | text='3. Apply Butterworth Filters' 214 | ) 215 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/apply_foot_locking_panel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | 4 | def draw_apply_foot_locking_panel(context, layout): 5 | fmc_adapter_tool = context.scene.fmc_adapter_tool 6 | 7 | # Create a button to toggle Apply Foot Locking Options 8 | row = layout.row(align=True) 9 | row.prop( 10 | fmc_adapter_tool.apply_foot_locking_properties, 11 | "show_apply_foot_locking", 12 | text="", icon='TRIA_DOWN' if 13 | fmc_adapter_tool.apply_foot_locking_properties.show_apply_foot_locking 14 | else 'TRIA_RIGHT', 15 | emboss=False 16 | ) 17 | row.label(text="Apply Foot Locking") 18 | 19 | if fmc_adapter_tool.apply_foot_locking_properties.show_apply_foot_locking: 20 | 21 | # Apply Foot Locking Options 22 | box = layout.box() 23 | split = box.column().row().split(factor=0.6) 24 | split.column().label(text='Target Foot') 25 | split.split().column().prop( 26 | fmc_adapter_tool.apply_foot_locking_properties, 27 | 'target_foot' 28 | ) 29 | 30 | split = box.column().row().split(factor=0.6) 31 | split.column().label(text='Target foot base markers') 32 | split.split().column().prop( 33 | fmc_adapter_tool.apply_foot_locking_properties, 34 | 'target_base_markers' 35 | ) 36 | 37 | split = box.column().row().split(factor=0.6) 38 | split.column().label(text='Z Threshold (m)') 39 | split.split().column().prop( 40 | fmc_adapter_tool.apply_foot_locking_properties, 41 | 'z_threshold' 42 | ) 43 | 44 | split = box.column().row().split(factor=0.6) 45 | split.column().label(text='Ground Level (m)') 46 | split.split().column().prop( 47 | fmc_adapter_tool.apply_foot_locking_properties, 48 | 'ground_level' 49 | ) 50 | 51 | split = box.column().row().split(factor=0.6) 52 | split.column().label(text='Frame Window Minimum Size') 53 | split.split().column().prop( 54 | fmc_adapter_tool.apply_foot_locking_properties, 55 | 'frame_window_min_size' 56 | ) 57 | 58 | split = box.column().row().split(factor=0.6) 59 | split.column().label(text='Initial Attenuation Count') 60 | split.split().column().prop( 61 | fmc_adapter_tool.apply_foot_locking_properties, 62 | 'initial_attenuation_count' 63 | ) 64 | 65 | split = box.column().row().split(factor=0.6) 66 | split.column().label(text='Final Attenuation Count') 67 | split.split().column().prop( 68 | fmc_adapter_tool.apply_foot_locking_properties, 69 | 'final_attenuation_count' 70 | ) 71 | 72 | split = box.column().row().split(factor=0.6) 73 | split.column().label(text='Lock XY at Ground Level') 74 | split.split().column().prop( 75 | fmc_adapter_tool.apply_foot_locking_properties, 76 | 'lock_xy_at_ground_level' 77 | ) 78 | 79 | split = box.column().row().split(factor=0.6) 80 | split.column().label(text='Knee Hip Compensation Coefficient') 81 | split.split().column().prop( 82 | fmc_adapter_tool.apply_foot_locking_properties, 83 | 'knee_hip_compensation_coefficient' 84 | ) 85 | 86 | split = box.column().row().split(factor=0.6) 87 | split.column().label(text='Compensate Upper Body Markers') 88 | split.split().column().prop( 89 | fmc_adapter_tool.apply_foot_locking_properties, 90 | 'compensate_upper_body' 91 | ) 92 | 93 | box = layout.box() 94 | box.operator( 95 | 'fmc_adapter.apply_foot_locking', 96 | text='5. Apply Foot Locking' 97 | ) 98 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/export_fbx_panel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | 4 | def draw_export_fbx_panel(context, layout): 5 | fmc_adapter_tool = context.scene.fmc_adapter_tool 6 | 7 | # Create a button to toggle FBX Export Options 8 | row = layout.row(align=True) 9 | row.prop( 10 | fmc_adapter_tool.export_fbx_properties, 11 | "show_export_fbx", 12 | text="", 13 | icon='TRIA_DOWN' if 14 | fmc_adapter_tool.export_fbx_properties.show_export_fbx 15 | else 'TRIA_RIGHT', 16 | emboss=False 17 | ) 18 | row.label(text="FBX Export") 19 | 20 | if fmc_adapter_tool.export_fbx_properties.show_export_fbx: 21 | 22 | # FBX Export 23 | box = layout.box() 24 | split = box.column().row().split(factor=0.6) 25 | split.column().label(text='FBX Export Type') 26 | split.split().column().prop( 27 | fmc_adapter_tool.export_fbx_properties, 28 | 'fbx_type' 29 | ) 30 | 31 | box.operator( 32 | 'fmc_adapter.export_fbx', 33 | text='8. Export FBX' 34 | ) 35 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/reduce_bone_length_dispersion_panel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | 4 | def draw_reduce_bone_length_dispersion_panel(context, layout): 5 | fmc_adapter_tool = context.scene.fmc_adapter_tool 6 | 7 | # Create a button to toggle Reduce Bone Length Dispersion Options 8 | row = layout.row(align=True) 9 | row.prop( 10 | fmc_adapter_tool.reduce_bone_length_dispersion_properties, 11 | "show_reduce_bone_length_dispersion", 12 | text="", 13 | icon='TRIA_DOWN' if 14 | fmc_adapter_tool.reduce_bone_length_dispersion_properties.show_reduce_bone_length_dispersion 15 | else 'TRIA_RIGHT', 16 | emboss=False 17 | ) 18 | row.label(text="Reduce Bone Length Dispersion") 19 | 20 | if fmc_adapter_tool.reduce_bone_length_dispersion_properties.show_reduce_bone_length_dispersion: 21 | 22 | # Reduce Bone Length Dispersion Options 23 | box = layout.box() 24 | 25 | split = box.column().row().split(factor=0.6) 26 | split.column().label(text='Dispersion Interval Variable') 27 | split.split().column().prop( 28 | fmc_adapter_tool.reduce_bone_length_dispersion_properties, 29 | 'interval_variable' 30 | ) 31 | 32 | split = box.column().row().split(factor=0.6) 33 | split.column().label(text='Dispersion Interval Factor') 34 | split.split().column().prop( 35 | fmc_adapter_tool.reduce_bone_length_dispersion_properties, 36 | 'interval_factor' 37 | ) 38 | 39 | split = box.column().row().split(factor=0.6) 40 | split.column().label(text='Body (Rig) Height [m]') 41 | split.split().column().prop( 42 | fmc_adapter_tool.reduce_bone_length_dispersion_properties, 43 | 'body_height' 44 | ) 45 | 46 | box.operator( 47 | 'fmc_adapter.reduce_bone_length_dispersion', 48 | text='2. Reduce Bone Length Dispersion' 49 | ) 50 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/panels/retarget_animation_panel.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | 4 | def draw_retarget_animation_panel(context, layout): 5 | fmc_adapter_tool = context.scene.fmc_adapter_tool 6 | 7 | # Create a button to toggle Retarget Animation Options 8 | row = layout.row(align=True) 9 | row.prop( 10 | fmc_adapter_tool.retarget_animation_properties, 11 | "show_retarget_animation", 12 | text="", 13 | icon='TRIA_DOWN' if 14 | fmc_adapter_tool.retarget_animation_properties.show_retarget_animation 15 | else 'TRIA_RIGHT', 16 | emboss=False 17 | ) 18 | row.label(text="Retarget Animation") 19 | 20 | if fmc_adapter_tool.retarget_animation_properties.show_retarget_animation: 21 | 22 | # Retarget Animation Options 23 | box = layout.box() 24 | split = box.column().row().split(factor=0.6) 25 | split.column().label(text='Source FreeMoCap Armature') 26 | split.split().column().prop( 27 | fmc_adapter_tool.retarget_animation_properties, 28 | 'source_armature' 29 | ) 30 | 31 | split = box.column().row().split(factor=0.6) 32 | split.column().label(text='Target Armature') 33 | split.split().column().prop( 34 | fmc_adapter_tool.retarget_animation_properties, 35 | 'target_armature' 36 | ) 37 | 38 | # split = box.column().row().split(factor=0.6) 39 | # split.column().label(text='Target Armature Type') 40 | # split.split().column().prop( 41 | # fmc_adapter_tool.retarget_animation_properties, 42 | # 'target_armature_type' 43 | # ) 44 | 45 | split = box.column().row().split(factor=0.6) 46 | split.column().label(text='Bake Animation') 47 | split.split().column().prop( 48 | fmc_adapter_tool.retarget_animation_properties, 49 | 'bake_animation' 50 | ) 51 | 52 | split = box.column().row().split(factor=0.6) 53 | split.column().label(text='Clear Constraints') 54 | split.split().column().prop( 55 | fmc_adapter_tool.retarget_animation_properties, 56 | 'clear_constraints' 57 | ) 58 | 59 | box.operator( 60 | 'fmc_adapter.retarget_animation', 61 | text='9. Retarget Animation' 62 | ) 63 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/data_definitions/interface/properties/__init__.py -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/add_armature_properties.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | # from freemocap_adapter.addon_interface import get_pose_items, update_menu 3 | from .property_types import PropertyTypes 4 | 5 | def update_menu(self, context, menu_name): 6 | if menu_name == 'armature': 7 | self.pose = get_pose_items(self, context)[0][0] 8 | 9 | def get_pose_items(self, context): 10 | if self.armature == 'armature_freemocap': 11 | items = [('freemocap_tpose', 'FreeMoCap T-Pose', ''), 12 | ('freemocap_apose', 'FreeMoCap A-Pose', '')] 13 | elif self.armature == 'armature_ue_metahuman_simple': 14 | items = [('ue_metahuman_tpose', 'UE Metahuman T-Pose', ''), 15 | ('ue_metahuman_default', 'UE Metahuman Default', '')] 16 | return items 17 | 18 | class AddArmatureProperties(bpy.types.PropertyGroup): 19 | show_add_rig: PropertyTypes.Bool( 20 | description = 'Toggle Add Rig Options' 21 | ) # type: ignore 22 | add_rig_method: PropertyTypes.Enum( 23 | description = 'Method used to create the rig', 24 | items = [('bone_by_bone', 'Bone by Bone', ''), 25 | ('using_rigify', 'Using Rigify', '')] 26 | ) # type: ignore 27 | armature: PropertyTypes.Enum( 28 | description = 'Armature that will be used to create the rig', 29 | items = [('armature_freemocap', 'FreeMoCap', ''), 30 | ('armature_ue_metahuman_simple', 'UE Metahuman Simple', '')], 31 | update = lambda a,b: update_menu(a, 32 | b, 33 | 'armature') 34 | ) # type: ignore 35 | pose: PropertyTypes.Enum( 36 | description = 'Pose that will be used to create the rig', 37 | items = get_pose_items, 38 | ) # type: ignore 39 | bone_length_method: PropertyTypes.Enum( 40 | description = 'Method use to calculate length of major bones', 41 | items = [('median_length', 'Median Length', '')] 42 | ) # type: ignore 43 | keep_symmetry: PropertyTypes.Bool( 44 | description = 'Keep right/left side symmetry (use average right/left ' 45 | 'side bone length)' 46 | ) # type: ignore 47 | add_fingers_constraints: PropertyTypes.Bool( 48 | default = True, 49 | description = 'Add bone constraints for fingers' 50 | ) # type: ignore 51 | add_ik_constraints: PropertyTypes.Bool( 52 | description = 'Add IK constraints for arms and legs' 53 | ) # type: ignore 54 | ik_transition_threshold: PropertyTypes.Float( 55 | default = 0.9, 56 | min = 0, 57 | max = 1, 58 | precision = 2, 59 | description = 'Threshold of parallel degree (dot product) between ' 60 | 'base and target ik vectors. It is used to transition ' 61 | 'between vectors to determine the pole bone position' 62 | ) # type: ignore 63 | use_limit_rotation: PropertyTypes.Bool( 64 | description = 'Add rotation limits (human skeleton) to the bones ' 65 | 'constraints (experimental)' 66 | ) # type: ignore 67 | clear_constraints: PropertyTypes.Bool( 68 | description = 'Clear added constraints after baking animation' 69 | ) # type: ignore 70 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/add_body_mesh_properties.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from .property_types import PropertyTypes 3 | 4 | class AddBodyMeshProperties(bpy.types.PropertyGroup): 5 | show_add_body_mesh: PropertyTypes.Bool( 6 | description = 'Toggle Add Body Mesh Options' 7 | ) # type: ignore 8 | body_mesh_mode: PropertyTypes.Enum( 9 | default = 'skelly_parts', 10 | description = 'Mode (source) for adding the mesh to the rig', 11 | items = [('skelly_parts', 'Skelly Parts', ''), 12 | ('skelly', 'Skelly', ''), 13 | ('can_man', 'Custom', ''), 14 | ] 15 | ) # type: ignore 16 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/add_finger_rotation_limits_properties.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from .property_types import PropertyTypes 3 | 4 | class AddFingerRotationLimitsProperties(bpy.types.PropertyGroup): 5 | show_add_finger_rotation_limits: bpy.props.BoolProperty( 6 | description = 'Toggle Add Finger Rotation Limits options' 7 | ) # type: ignore 8 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/adjust_empties_properties.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from .property_types import PropertyTypes 3 | 4 | class AdjustEmptiesProperties(bpy.types.PropertyGroup): 5 | show_adjust_empties: PropertyTypes.Bool( 6 | # name='', 7 | # default=False, 8 | description='Toggle Adjust Empties Options' 9 | ) # type: ignore 10 | vertical_align_reference: PropertyTypes.Enum( 11 | # name='', 12 | description='Empty that serves as reference to align the z axis', 13 | items=[ 14 | ('left_knee', 'left_knee', ''), 15 | ('trunk_center', 'trunk_center', ''), 16 | ('right_knee', 'right_knee', '') 17 | ] 18 | ) # type: ignore 19 | vertical_align_angle_offset: PropertyTypes.Float( 20 | # name='', 21 | # default=0, 22 | description='Angle offset to adjust the vertical alignement of the z axis (in degrees)' 23 | ) # type: ignore 24 | ground_align_reference: PropertyTypes.Enum( 25 | # name='', 26 | description='Empty that serves as ground reference to the axes origin', 27 | items=[ 28 | ('left_foot_index', 'left_foot_index', ''), 29 | ('right_foot_index', 'right_foot_index', ''), 30 | ('left_heel', 'left_heel', ''), 31 | ('right_heel', 'right_heel', '') 32 | ] 33 | ) # type: ignore 34 | vertical_align_position_offset: PropertyTypes.Float( 35 | # name='', 36 | # default=0, 37 | # precision=3, 38 | description='Additional z offset to the axes origin relative to the imaginary ground level' 39 | ) # type: ignore 40 | # correct_fingers_empties: bpy.props.BoolProperty( 41 | # name='', 42 | # default=True, 43 | # description='Correct the fingers empties. Match hand_wrist (axis empty) position to wrist (sphere empty)' 44 | # ) # type: ignore 45 | correct_fingers_empties: PropertyTypes.Bool( 46 | # name='', 47 | # default=True, 48 | description='Correct the fingers empties. Match hand_wrist (axis empty) position to wrist (sphere empty)' 49 | ) # type: ignore 50 | add_hand_middle_empty: PropertyTypes.Bool( 51 | # name='', 52 | # default=False, 53 | description='Add an empty in the middle of the hand between index and pinky empties. This empty is used for a better orientation of the hand (experimental)' 54 | ) # type: ignore 55 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/apply_butterworth_filters_properties.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from .property_types import PropertyTypes 3 | 4 | class ApplyButterworthFiltersProperties(bpy.types.PropertyGroup): 5 | show_apply_butterworth_filters: PropertyTypes.Bool( 6 | description = 'Toggle Apply Butterworth Filters Options' 7 | ) # type: ignore 8 | position_correction_mode: PropertyTypes.Enum( 9 | description = 'Position correction mode', 10 | items = [('overall', 'Overall (Faster)', ''), 11 | ('each_children', 'Each Children (Slower)', '')], 12 | ) # type: ignore 13 | apply_global_filter_core: PropertyTypes.Bool( 14 | description = 'Apply global Butterworth filter to core empties ' 15 | '(hips_center, trunk_center and neck_center)' 16 | ) # type: ignore 17 | global_filter_core_frequency: PropertyTypes.Float( 18 | default = 7, 19 | min = 0, 20 | precision = 2, 21 | description = 'Core empties global Butterworth filter cutoff ' 22 | 'frequency (Hz)' 23 | ) # type: ignore 24 | apply_local_filter_core: PropertyTypes.Bool( 25 | description = 'Apply local Butterworth filter to core empties' 26 | ) # type: ignore 27 | local_filter_origin_core: PropertyTypes.Enum( 28 | description = 'Local filter origin', 29 | items = [('hips_center', 'Hips', ''), 30 | ], 31 | ) # type: ignore 32 | local_filter_core_frequency: PropertyTypes.Float( 33 | default = 7, 34 | min = 0, 35 | precision = 2, 36 | description = 'Core empties local Butterworth filter cutoff ' 37 | 'frequency (Hz)' 38 | ) # type: ignore 39 | apply_global_filter_arms: PropertyTypes.Bool( 40 | name = 'Arms', 41 | description = 'Apply global Butterworth filter to arms empties ' 42 | '(shoulde and elbow)' 43 | ) # type: ignore 44 | global_filter_arms_frequency: PropertyTypes.Float( 45 | default = 7, 46 | min = 0, 47 | precision = 2, 48 | description = 'Arms empties global Butterworth filter cutoff ' 49 | 'frequency (Hz)' 50 | ) # type: ignore 51 | apply_local_filter_arms: PropertyTypes.Bool( 52 | description = 'Apply local Butterworth filter to arms empties' 53 | ) # type: ignore 54 | local_filter_origin_arms: PropertyTypes.Enum( 55 | description = 'Local filter origin', 56 | items = [('neck_center', 'Neck', ''), 57 | ], 58 | ) # type: ignore 59 | local_filter_arms_frequency: PropertyTypes.Float( 60 | default = 7, 61 | min = 0, 62 | precision = 2, 63 | description = 'Arms empties local Butterworth filter cutoff ' 64 | 'frequency (Hz)' 65 | ) # type: ignore 66 | apply_global_filter_hands: PropertyTypes.Bool( 67 | name = 'Hands', 68 | description = 'Apply global Butterworth filter to hands empties ' 69 | '(wrist and hand)' 70 | ) # type: ignore 71 | global_filter_hands_frequency: PropertyTypes.Float( 72 | default = 7, 73 | min = 0, 74 | precision = 2, 75 | description = 'Hands empties global Butterworth filter cutoff ' 76 | 'frequency (Hz)' 77 | ) # type: ignore 78 | apply_local_filter_hands: PropertyTypes.Bool( 79 | description = 'Apply local Butterworth filter to hands empties' 80 | ) # type: ignore 81 | local_filter_origin_hands: PropertyTypes.Enum( 82 | description = 'Local filter origin', 83 | items = [('side_elbow', 'Elbow', ''), 84 | ], 85 | ) # type: ignore 86 | local_filter_hands_frequency: PropertyTypes.Float( 87 | default = 7, 88 | min = 0, 89 | precision = 2, 90 | description = 'Hands empties local Butterworth filter cutoff ' 91 | 'frequency (Hz)' 92 | ) # type: ignore 93 | apply_global_filter_fingers: PropertyTypes.Bool( 94 | name = 'Fingers', 95 | description = 'Apply global Butterworth filter to fingers empties ' 96 | '(_ip, _pip, _dip and _tip)' 97 | ) # type: ignore 98 | global_filter_fingers_frequency: PropertyTypes.Float( 99 | default = 7, 100 | min = 0, 101 | precision = 2, 102 | description = 'Fingers empties global Butterworth filter cutoff ' 103 | 'frequency (Hz)' 104 | ) # type: ignore 105 | apply_local_filter_fingers: PropertyTypes.Bool( 106 | description = 'Apply local Butterworth filter to fingers empties' 107 | ) # type: ignore 108 | local_filter_origin_fingers: PropertyTypes.Enum( 109 | description = 'Local filter origin', 110 | items = [('side_wrist', 'Wrist', ''), 111 | ], 112 | ) # type: ignore 113 | local_filter_fingers_frequency: PropertyTypes.Float( 114 | default = 7, 115 | min = 0, 116 | precision = 2, 117 | description = 'Fingers empties local Butterworth filter cutoff ' 118 | 'frequency (Hz)' 119 | ) # type: ignore 120 | apply_global_filter_legs: PropertyTypes.Bool( 121 | name = 'Legs', 122 | description = 'Apply global Butterworth filter to legs empties ' 123 | '(hips and knees)' 124 | ) # type: ignore 125 | global_filter_legs_frequency: PropertyTypes.Float( 126 | default = 7, 127 | min = 0, 128 | precision = 2, 129 | description = 'Legs empties global Butterworth filter cutoff ' 130 | 'frequency (Hz)' 131 | ) # type: ignore 132 | apply_local_filter_legs: PropertyTypes.Bool( 133 | description = 'Apply local Butterworth filter to legs empties' 134 | ) # type: ignore 135 | local_filter_origin_legs: PropertyTypes.Enum( 136 | description = 'Local filter origin', 137 | items = [('hips_center', 'Hips', ''), 138 | ], 139 | ) # type: ignore 140 | local_filter_legs_frequency: PropertyTypes.Float( 141 | default = 7, 142 | min = 0, 143 | precision = 2, 144 | description = 'Legs empties local Butterworth filter cutoff ' 145 | 'frequency (Hz)' 146 | ) # type: ignore 147 | apply_global_filter_feet: PropertyTypes.Bool( 148 | name = 'Feet', 149 | description = 'Apply global Butterworth filter to feet empties ' 150 | '(ankle, heel and foot_index)' 151 | ) # type: ignore 152 | global_filter_feet_frequency: PropertyTypes.Float( 153 | default = 7, 154 | min = 0, 155 | precision = 2, 156 | description = 'Feet empties global Butterworth filter cutoff ' 157 | 'frequency (Hz)' 158 | ) # type: ignore 159 | apply_local_filter_feet: PropertyTypes.Bool( 160 | description = 'Apply local Butterworth filter to feet empties' 161 | ) # type: ignore 162 | local_filter_origin_feet: PropertyTypes.Enum( 163 | description = 'Local filter origin', 164 | items = [('side_knee', 'Knee', ''), 165 | ], 166 | ) # type: ignore 167 | local_filter_feet_frequency: PropertyTypes.Float( 168 | default = 7, 169 | min = 0, 170 | precision = 2, 171 | description = 'Feet empties local Butterworth filter cutoff ' 172 | 'frequency (Hz)' 173 | ) # type: ignore 174 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/apply_foot_locking_properties.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from .property_types import PropertyTypes 3 | 4 | class ApplyFootLockingProperties(bpy.types.PropertyGroup): 5 | show_apply_foot_locking: PropertyTypes.Bool( 6 | description = 'Toggle Apply Foot Locking options' 7 | ) # type: ignore 8 | target_foot: PropertyTypes.Enum( 9 | description = 'Target foot for applying foot locking', 10 | items = [('both_feet', 'Both Feet', ''), 11 | ('left_foot', 'Left Foot', ''), 12 | ('right_foot', 'Right Foot', '') 13 | ] 14 | ) # type: ignore 15 | target_base_markers: PropertyTypes.Enum( 16 | description = 'Target foot base markers for applying foot locking', 17 | items = [('foot_index_and_heel', 'foot_index and heel', ''), 18 | ('foot_index', 'foot_index', ''), 19 | ('heel', 'heel', '') 20 | ] 21 | ) # type: ignore 22 | z_threshold: PropertyTypes.Float( 23 | default = 0.01, 24 | precision = 3, 25 | description = 'Vertical threshold under which foot markers are ' 26 | 'considered for applying foot locking' 27 | ) # type: ignore 28 | ground_level: PropertyTypes.Float( 29 | precision = 3, 30 | description = 'Ground level for applying foot locking. Markers with ' 31 | 'z global coordinate lower than this value will be ' 32 | 'fixed to this level. It must be lower than the ' 33 | 'z threshold' 34 | ) # type: ignore 35 | frame_window_min_size: PropertyTypes.Int( 36 | default = 10, 37 | min = 1, 38 | description = 'Minimum frame window size for applying foot locking. ' 39 | 'A markers z global coordinate has to be lower than the ' 40 | 'z threshold for a consecutive frames count equal or ' 41 | 'bigger than this value.' 42 | 'It must be equal or greater than ' 43 | 'initial_attenuation_count + final_attenuation_count' 44 | ) # type: ignore 45 | initial_attenuation_count: PropertyTypes.Int( 46 | default = 5, 47 | min = 0, 48 | description = 'This are the first frames of the window which have ' 49 | 'their z coordinate attenuated by the the initial ' 50 | 'quadratic attenuation function' 51 | ) # type: ignore 52 | final_attenuation_count: PropertyTypes.Int( 53 | default = 5, 54 | min = 0, 55 | description = 'This are the last frames of the window which have ' 56 | 'their z coordinate attenuated by the the final ' 57 | 'quadratic attenuation function' 58 | ) # type: ignore 59 | lock_xy_at_ground_level: PropertyTypes.Bool( 60 | description = 'When applying foot locking, lock also the x and y ' 61 | 'coordinates at the ground level. This is useful only ' 62 | 'when character is standing still as it might leed to ' 63 | '"sticky" or "lead" feet effect' 64 | ) # type: ignore 65 | knee_hip_compensation_coefficient: PropertyTypes.Float( 66 | default = 1.0, 67 | precision = 3, 68 | min = 0.0, 69 | max = 1.0, 70 | description = 'After calculating the ankle new z global coordinate, ' 71 | 'the knee and hip markers will be adjusted on the z ' 72 | 'axis by the same delta multiplied by this coefficient.' 73 | 'A value of 1.0 means knee and hip have the same ' 74 | 'adjustment as the ankle. A value of 0 means knee and ' 75 | 'hip have no adjustment at all. Values lower than 1.0 ' 76 | 'are useful when the rig has IK constraints on the legs.' 77 | 'This way the ankle adjustment is compensated by the ' 78 | 'knee IK bending' 79 | ) # type: ignore 80 | compensate_upper_body: PropertyTypes.Bool( 81 | description = 'Compensate the upper body markers by setting the new ' 82 | 'z coordinate of the hips_center marker as the average ' 83 | 'z coordinate of left and right hips markers.' 84 | 'Then propagate the new z delta to the upper body ' 85 | 'markers starting from the trunk_center.' 86 | ) # type: ignore 87 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/export_fbx_properties.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from .property_types import PropertyTypes 3 | 4 | class ExportFBXProperties(bpy.types.PropertyGroup): 5 | show_export_fbx: PropertyTypes.Bool( 6 | description = 'Toggle Export FBX Options' 7 | ) # type: ignore 8 | fbx_type: PropertyTypes.Enum( 9 | description = 'Type of the FBX file', 10 | items = [('standard', 'Standard', ''), 11 | ('unreal_engine', 'Unreal Engine', '') 12 | ] 13 | ) # type: ignore 14 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/property_types.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | 3 | class PropertyTypes: 4 | Bool = lambda **kwargs: bpy.props.BoolProperty( 5 | name=kwargs.get('name', ''), 6 | default=kwargs.get('default', False), 7 | description=kwargs.get('description', '') 8 | ) 9 | Enum = lambda **kwargs: bpy.props.EnumProperty( 10 | name=kwargs.get('name', ''), 11 | description=kwargs.get('description', ''), 12 | items=kwargs.get('items', []) 13 | ) 14 | Float = lambda **kwargs: bpy.props.FloatProperty( 15 | name=kwargs.get('name', ''), 16 | default=kwargs.get('default', 0.0), 17 | precision=kwargs.get('precision', 3), 18 | description=kwargs.get('description', '') 19 | ) 20 | Int = lambda **kwargs: bpy.props.IntProperty( 21 | name=kwargs.get('name', ''), 22 | default=kwargs.get('default', 0), 23 | description=kwargs.get('description', '') 24 | ) 25 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/reduce_bone_length_dispersion_properties.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from .property_types import PropertyTypes 3 | 4 | class ReduceBoneLengthDispersionProperties(bpy.types.PropertyGroup): 5 | show_reduce_bone_length_dispersion: PropertyTypes.Bool( 6 | description = 'Toggle Reduce Bone Length Dispersion Options' 7 | ) # type: ignore 8 | interval_variable: PropertyTypes.Enum( 9 | description = 'Variable used to define the new length dispersion ' 10 | 'interval', 11 | items = [ 12 | ('capture_median', 13 | 'Capture Median', 14 | 'Use the bones median length from the capture. Defines the ' 15 | 'new dispersion interval as ' 16 | '[median*(1-interval_factor),median*(1+interval_factor)]'), 17 | ('standard_length', 18 | 'Standard length', 19 | 'Use the standard lengths based on the total body (rig) ' 20 | 'height. Defines the new dispersion interval as ' 21 | '[length*(1-interval_factor),length*(1+interval_factor)]'), 22 | ('capture_stdev', 23 | 'Capture Std Dev', 24 | 'Use the bones length standard deviation from the capture. ' 25 | 'Defines the new dispersion interval as ' 26 | '[median-interval_factor*stdev,median+interval_factor*stdev]')] 27 | ) # type: ignore 28 | interval_factor: PropertyTypes.Float( 29 | min = 0, 30 | description = 'Factor to multiply the variable and form the limits of ' 31 | 'the dispersion interval like ' 32 | '[median-factor*variable,median+factor*variable]. ' 33 | 'If variable is median, the factor will be limited to ' 34 | 'values inside [0, 1]. ' 35 | 'If variable is stdev, the factor will be limited to ' 36 | 'values inside [0, median/stdev]' 37 | ) # type: ignore 38 | body_height: PropertyTypes.Float( 39 | default = 1.75, 40 | min = 0, 41 | description = 'Body height in meters. This value is used when the ' 42 | 'interval variable is set to standard length. If a rig ' 43 | 'is added after using Reduce Dispersion with standard ' 44 | 'length, it will have this value as height and the ' 45 | 'bones length will be proporions of this height' 46 | ) # type: ignore 47 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/interface/properties/retarget_animation_properties.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from .property_types import PropertyTypes 3 | 4 | def get_available_armatures(self, context): 5 | available_rigs = [] 6 | 7 | for scene_object in bpy.data.objects: 8 | if scene_object.type == 'ARMATURE': 9 | available_rigs.append((scene_object.name, scene_object.name, '')) 10 | 11 | return available_rigs 12 | 13 | class RetargetAnimationProperties(bpy.types.PropertyGroup): 14 | # Retarget Animation options 15 | show_retarget_animation: PropertyTypes.Bool( 16 | description = 'Toggle Retarget Animation Options' 17 | ) # type: ignore 18 | source_armature: PropertyTypes.Enum( 19 | description = 'Source armature which constraints will be copied from', 20 | items = get_available_armatures, 21 | ) # type: ignore 22 | target_armature: PropertyTypes.Enum( 23 | description = 'Target armature which constraints will be copied to', 24 | items = get_available_armatures, 25 | ) # type: ignore 26 | target_armature_type: PropertyTypes.Enum( 27 | description = 'Target armature type', 28 | items = [('mixamo', 'Mixamo', ''), 29 | ('daz', 'DAZ', ''), 30 | ('autodetect', 'Auto Detect', '')], 31 | ) # type: ignore 32 | bake_animation: PropertyTypes.Bool( 33 | default = True, 34 | description = 'Bake Animation' 35 | ) # type: ignore 36 | clear_constraints: PropertyTypes.Bool( 37 | default = True, 38 | description = 'Clear Constraints' 39 | ) # type: ignore 40 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/poses/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_adapter/data_definitions/poses/__init__.py -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/poses/freemocap_apose.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary with the rotations of the A-Pose of the FreeMoCap armature. 3 | """ 4 | import math as m 5 | 6 | freemocap_apose = { 7 | 'pelvis': { 8 | 'rotation': (m.radians(-90), 0, 0), 9 | 'roll': 0, 10 | }, 11 | 'pelvis.R': { 12 | 'rotation': (0, m.radians(-90), 0), 13 | 'roll': 0, 14 | }, 15 | 'pelvis.L': { 16 | 'rotation': (0, m.radians(90), 0), 17 | 'roll': 0, 18 | }, 19 | 'spine': { 20 | 'rotation': (0, 0, 0), 21 | 'roll': 0, 22 | }, 23 | 'spine.001': { 24 | 'rotation': (0, 0, 0), 25 | 'roll': 0, 26 | }, 27 | 'neck': { 28 | 'rotation': (0, 0, 0), 29 | 'roll': 0, 30 | }, 31 | 'face': { 32 | 'rotation': (m.radians(110), 0, 0), 33 | 'roll': 0, 34 | }, 35 | 'shoulder.R': { 36 | 'rotation': (0, m.radians(-90), 0), 37 | 'roll': 0, 38 | }, 39 | 'shoulder.L': { 40 | 'rotation': (0, m.radians(90), 0), 41 | 'roll': 0, 42 | }, 43 | 'upper_arm.R': { 44 | 'rotation': (0, m.radians(-135), 0), 45 | 'roll': m.radians(-135), 46 | }, 47 | 'upper_arm.L': { 48 | 'rotation': (0, m.radians(135), 0), 49 | 'roll': m.radians(135), 50 | }, 51 | 'forearm.R': { 52 | 'rotation': (0, m.radians(-135), m.radians(1)), 53 | 'roll': m.radians(-135), 54 | }, 55 | 'forearm.L': { 56 | 'rotation': (0, m.radians(135), m.radians(-1)), 57 | 'roll': m.radians(135), 58 | }, 59 | 'hand.R': { 60 | 'rotation': (0, m.radians(-135), 0), 61 | 'roll': 0, 62 | }, 63 | 'hand.L': { 64 | 'rotation': (0, m.radians(135), 0), 65 | 'roll': 0, 66 | }, 67 | 'thumb.carpal.R': { 68 | 'rotation': (0, m.radians(-135), m.radians(45)), 69 | 'roll': 0, 70 | }, 71 | 'thumb.carpal.L': { 72 | 'rotation': (0, m.radians(135), m.radians(-45)), 73 | 'roll': 0, 74 | }, 75 | 'thumb.01.R': { 76 | 'rotation': (0, m.radians(-135), m.radians(45)), 77 | 'roll': 0, 78 | }, 79 | 'thumb.01.L': { 80 | 'rotation': (0, m.radians(135), m.radians(-45)), 81 | 'roll': 0, 82 | }, 83 | 'thumb.02.R': { 84 | 'rotation': (0, m.radians(-135), m.radians(45)), 85 | 'roll': 0, 86 | }, 87 | 'thumb.02.L': { 88 | 'rotation': (0, m.radians(135), m.radians(-45)), 89 | 'roll': 0, 90 | }, 91 | 'thumb.03.R': { 92 | 'rotation': (0, m.radians(-135), m.radians(45)), 93 | 'roll': 0, 94 | }, 95 | 'thumb.03.L': { 96 | 'rotation': (0, m.radians(135), m.radians(-45)), 97 | 'roll': 0, 98 | }, 99 | 'palm.01.R': { 100 | 'rotation': (0, m.radians(-135), m.radians(17)), 101 | 'roll': 0, 102 | }, 103 | 'palm.01.L': { 104 | 'rotation': (0, m.radians(135), m.radians(-17)), 105 | 'roll': 0, 106 | }, 107 | 'f_index.01.R': { 108 | 'rotation': (0, m.radians(-135), 0), 109 | 'roll': 0, 110 | }, 111 | 'f_index.01.L': { 112 | 'rotation': (0, m.radians(135), 0), 113 | 'roll': 0, 114 | }, 115 | 'f_index.02.R': { 116 | 'rotation': (0, m.radians(-135), 0), 117 | 'roll': 0, 118 | }, 119 | 'f_index.02.L': { 120 | 'rotation': (0, m.radians(135), 0), 121 | 'roll': 0, 122 | }, 123 | 'f_index.03.R': { 124 | 'rotation': (0, m.radians(-135), 0), 125 | 'roll': 0, 126 | }, 127 | 'f_index.03.L': { 128 | 'rotation': (0, m.radians(135), 0), 129 | 'roll': 0, 130 | }, 131 | 'palm.02.R': { 132 | 'rotation': (0, m.radians(-135), m.radians(5.5)), 133 | 'roll': 0, 134 | }, 135 | 'palm.02.L': { 136 | 'rotation': (0, m.radians(135), m.radians(-5.5)), 137 | 'roll': 0, 138 | }, 139 | 'f_middle.01.R': { 140 | 'rotation': (0, m.radians(-135), 0), 141 | 'roll': 0, 142 | }, 143 | 'f_middle.01.L': { 144 | 'rotation': (0, m.radians(135), 0), 145 | 'roll': 0, 146 | }, 147 | 'f_middle.02.R': { 148 | 'rotation': (0, m.radians(-135), 0), 149 | 'roll': 0, 150 | }, 151 | 'f_middle.02.L': { 152 | 'rotation': (0, m.radians(135), 0), 153 | 'roll': 0, 154 | }, 155 | 'f_middle.03.R': { 156 | 'rotation': (0, m.radians(-135), 0), 157 | 'roll': 0, 158 | }, 159 | 'f_middle.03.L': { 160 | 'rotation': (0, m.radians(135), 0), 161 | 'roll': 0, 162 | }, 163 | 'palm.03.R': { 164 | 'rotation': (0, m.radians(-135), m.radians(-7.3)), 165 | 'roll': 0, 166 | }, 167 | 'palm.03.L': { 168 | 'rotation': (0, m.radians(135), m.radians(7.3)), 169 | 'roll': 0, 170 | }, 171 | 'f_ring.01.R': { 172 | 'rotation': (0, m.radians(-135), 0), 173 | 'roll': 0, 174 | }, 175 | 'f_ring.01.L': { 176 | 'rotation': (0, m.radians(135), 0), 177 | 'roll': 0, 178 | }, 179 | 'f_ring.02.R': { 180 | 'rotation': (0, m.radians(-135), 0), 181 | 'roll': 0, 182 | }, 183 | 'f_ring.02.L': { 184 | 'rotation': (0, m.radians(135), 0), 185 | 'roll': 0, 186 | }, 187 | 'f_ring.03.R': { 188 | 'rotation': (0, m.radians(-135), 0), 189 | 'roll': 0, 190 | }, 191 | 'f_ring.03.L': { 192 | 'rotation': (0, m.radians(135), 0), 193 | 'roll': 0, 194 | }, 195 | 'palm.04.R': { 196 | 'rotation': (0, m.radians(-135), m.radians(-19)), 197 | 'roll': 0, 198 | }, 199 | 'palm.04.L': { 200 | 'rotation': (0, m.radians(135), m.radians(19)), 201 | 'roll': 0, 202 | }, 203 | 'f_pinky.01.R': { 204 | 'rotation': (0, m.radians(-135), 0), 205 | 'roll': 0, 206 | }, 207 | 'f_pinky.01.L': { 208 | 'rotation': (0, m.radians(135), 0), 209 | 'roll': 0, 210 | }, 211 | 'f_pinky.02.R': { 212 | 'rotation': (0, m.radians(-135), 0), 213 | 'roll': 0, 214 | }, 215 | 'f_pinky.02.L': { 216 | 'rotation': (0, m.radians(135), 0), 217 | 'roll': 0, 218 | }, 219 | 'f_pinky.03.R': { 220 | 'rotation': (0, m.radians(-135), 0), 221 | 'roll': 0, 222 | }, 223 | 'f_pinky.03.L': { 224 | 'rotation': (0, m.radians(135), 0), 225 | 'roll': 0, 226 | }, 227 | 'thigh.R': { 228 | 'rotation': (m.radians(1), m.radians(180), 0), 229 | 'roll': 0, 230 | }, 231 | 'thigh.L': { 232 | 'rotation': (m.radians(1), m.radians(180), 0), 233 | 'roll': 0, 234 | }, 235 | 'shin.R': { 236 | 'rotation': (m.radians(-1), m.radians(180), 0), 237 | 'roll': 0, 238 | }, 239 | 'shin.L': { 240 | 'rotation': (m.radians(-1), m.radians(180), 0), 241 | 'roll': 0, 242 | }, 243 | 'foot.R': { 244 | 'rotation': (m.radians(113), 0, 0), 245 | 'roll': 0, 246 | }, 247 | 'foot.L': { 248 | 'rotation': (m.radians(113), 0, 0), 249 | 'roll': 0, 250 | }, 251 | 'heel.02.R': { 252 | 'rotation': (m.radians(195), 0, 0), 253 | 'roll': 0, 254 | }, 255 | 'heel.02.L': { 256 | 'rotation': (m.radians(195), 0, 0), 257 | 'roll': 0, 258 | }, 259 | } 260 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/poses/freemocap_tpose.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary with the rotations of the T-Pose of the FreeMoCap armature. 3 | """ 4 | import math as m 5 | 6 | freemocap_tpose = { 7 | 'pelvis': { 8 | 'rotation': (0, 0, 0), 9 | 'roll': 0, 10 | }, 11 | 'pelvis.R': { 12 | 'rotation': (0, m.radians(-90), 0), 13 | 'roll': 0, 14 | }, 15 | 'pelvis.L': { 16 | 'rotation': (0, m.radians(90), 0), 17 | 'roll': 0, 18 | }, 19 | 'spine': { 20 | 'rotation': (0, 0, 0), 21 | 'roll': 0, 22 | }, 23 | 'spine.001': { 24 | 'rotation': (0, 0, 0), 25 | 'roll': 0, 26 | }, 27 | 'neck': { 28 | 'rotation': (0, 0, 0), 29 | 'roll': 0, 30 | }, 31 | 'face': { 32 | 'rotation': (m.radians(110), 0, 0), 33 | 'roll': 0, 34 | }, 35 | 'shoulder.R': { 36 | 'rotation': (0, m.radians(-90), 0), 37 | 'roll': 0, 38 | }, 39 | 'shoulder.L': { 40 | 'rotation': (0, m.radians(90), 0), 41 | 'roll': 0, 42 | }, 43 | 'upper_arm.R': { 44 | 'rotation': (0, m.radians(-90), 0), 45 | 'roll': m.radians(-90), 46 | }, 47 | 'upper_arm.L': { 48 | 'rotation': (0, m.radians(90), 0), 49 | 'roll': m.radians(90), 50 | }, 51 | 'forearm.R': { 52 | 'rotation': (0, m.radians(-90), m.radians(1)), 53 | 'roll': m.radians(-90), 54 | }, 55 | 'forearm.L': { 56 | 'rotation': (0, m.radians(90), m.radians(-1)), 57 | 'roll': m.radians(90), 58 | }, 59 | 'hand.R': { 60 | 'rotation': (0, m.radians(-90), 0), 61 | 'roll': m.radians(-90), 62 | }, 63 | 'hand.L': { 64 | 'rotation': (0, m.radians(90), 0), 65 | 'roll': m.radians(90), 66 | }, 67 | 'thumb.carpal.R': { 68 | 'rotation': (0, m.radians(-90), m.radians(45)), 69 | 'roll': 0, 70 | }, 71 | 'thumb.carpal.L': { 72 | 'rotation': (0, m.radians(90), m.radians(-45)), 73 | 'roll': 0, 74 | }, 75 | 'thumb.01.R': { 76 | 'rotation': (0, m.radians(-90), m.radians(45)), 77 | 'roll': 0, 78 | }, 79 | 'thumb.01.L': { 80 | 'rotation': (0, m.radians(90), m.radians(-45)), 81 | 'roll': 0, 82 | }, 83 | 'thumb.02.R': { 84 | 'rotation': (0, m.radians(-90), m.radians(45)), 85 | 'roll': 0, 86 | }, 87 | 'thumb.02.L': { 88 | 'rotation': (0, m.radians(90), m.radians(-45)), 89 | 'roll': 0, 90 | }, 91 | 'thumb.03.R': { 92 | 'rotation': (0, m.radians(-90), m.radians(45)), 93 | 'roll': 0, 94 | }, 95 | 'thumb.03.L': { 96 | 'rotation': (0, m.radians(90), m.radians(-45)), 97 | 'roll': 0, 98 | }, 99 | 'palm.01.R': { 100 | 'rotation': (0, m.radians(-90), m.radians(17)), 101 | 'roll': 0, 102 | }, 103 | 'palm.01.L': { 104 | 'rotation': (0, m.radians(90), m.radians(-17)), 105 | 'roll': 0, 106 | }, 107 | 'f_index.01.R': { 108 | 'rotation': (0, m.radians(-90), 0), 109 | 'roll': 0, 110 | }, 111 | 'f_index.01.L': { 112 | 'rotation': (0, m.radians(90), 0), 113 | 'roll': 0, 114 | }, 115 | 'f_index.02.R': { 116 | 'rotation': (0, m.radians(-90), 0), 117 | 'roll': 0, 118 | }, 119 | 'f_index.02.L': { 120 | 'rotation': (0, m.radians(90), 0), 121 | 'roll': 0, 122 | }, 123 | 'f_index.03.R': { 124 | 'rotation': (0, m.radians(-90), 0), 125 | 'roll': 0, 126 | }, 127 | 'f_index.03.L': { 128 | 'rotation': (0, m.radians(90), 0), 129 | 'roll': 0, 130 | }, 131 | 'palm.02.R': { 132 | 'rotation': (0, m.radians(-90), m.radians(5.5)), 133 | 'roll': 0, 134 | }, 135 | 'palm.02.L': { 136 | 'rotation': (0, m.radians(90), m.radians(-5.5)), 137 | 'roll': 0, 138 | }, 139 | 'f_middle.01.R': { 140 | 'rotation': (0, m.radians(-90), 0), 141 | 'roll': 0, 142 | }, 143 | 'f_middle.01.L': { 144 | 'rotation': (0, m.radians(90), 0), 145 | 'roll': 0, 146 | }, 147 | 'f_middle.02.R': { 148 | 'rotation': (0, m.radians(-90), 0), 149 | 'roll': 0, 150 | }, 151 | 'f_middle.02.L': { 152 | 'rotation': (0, m.radians(90), 0), 153 | 'roll': 0, 154 | }, 155 | 'f_middle.03.R': { 156 | 'rotation': (0, m.radians(-90), 0), 157 | 'roll': 0, 158 | }, 159 | 'f_middle.03.L': { 160 | 'rotation': (0, m.radians(90), 0), 161 | 'roll': 0, 162 | }, 163 | 'palm.03.R': { 164 | 'rotation': (0, m.radians(-90), m.radians(-7.3)), 165 | 'roll': 0, 166 | }, 167 | 'palm.03.L': { 168 | 'rotation': (0, m.radians(90), m.radians(7.3)), 169 | 'roll': 0, 170 | }, 171 | 'f_ring.01.R': { 172 | 'rotation': (0, m.radians(-90), 0), 173 | 'roll': 0, 174 | }, 175 | 'f_ring.01.L': { 176 | 'rotation': (0, m.radians(90), 0), 177 | 'roll': 0, 178 | }, 179 | 'f_ring.02.R': { 180 | 'rotation': (0, m.radians(-90), 0), 181 | 'roll': 0, 182 | }, 183 | 'f_ring.02.L': { 184 | 'rotation': (0, m.radians(90), 0), 185 | 'roll': 0, 186 | }, 187 | 'f_ring.03.R': { 188 | 'rotation': (0, m.radians(-90), 0), 189 | 'roll': 0, 190 | }, 191 | 'f_ring.03.L': { 192 | 'rotation': (0, m.radians(90), 0), 193 | 'roll': 0, 194 | }, 195 | 'palm.04.R': { 196 | 'rotation': (0, m.radians(-90), m.radians(-19)), 197 | 'roll': 0, 198 | }, 199 | 'palm.04.L': { 200 | 'rotation': (0, m.radians(90), m.radians(19)), 201 | 'roll': 0, 202 | }, 203 | 'f_pinky.01.R': { 204 | 'rotation': (0, m.radians(-90), 0), 205 | 'roll': 0, 206 | }, 207 | 'f_pinky.01.L': { 208 | 'rotation': (0, m.radians(90), 0), 209 | 'roll': 0, 210 | }, 211 | 'f_pinky.02.R': { 212 | 'rotation': (0, m.radians(-90), 0), 213 | 'roll': 0, 214 | }, 215 | 'f_pinky.02.L': { 216 | 'rotation': (0, m.radians(90), 0), 217 | 'roll': 0, 218 | }, 219 | 'f_pinky.03.R': { 220 | 'rotation': (0, m.radians(-90), 0), 221 | 'roll': 0, 222 | }, 223 | 'f_pinky.03.L': { 224 | 'rotation': (0, m.radians(90), 0), 225 | 'roll': 0, 226 | }, 227 | 'thigh.R': { 228 | 'rotation': (m.radians(1), m.radians(180), 0), 229 | 'roll': 0, 230 | }, 231 | 'thigh.L': { 232 | 'rotation': (m.radians(1), m.radians(180), 0), 233 | 'roll': 0, 234 | }, 235 | 'shin.R': { 236 | 'rotation': (m.radians(-1), m.radians(180), 0), 237 | 'roll': 0, 238 | }, 239 | 'shin.L': { 240 | 'rotation': (m.radians(-1), m.radians(180), 0), 241 | 'roll': 0, 242 | }, 243 | 'foot.R': { 244 | 'rotation': (m.radians(113), 0, 0), 245 | 'roll': 0, 246 | }, 247 | 'foot.L': { 248 | 'rotation': (m.radians(113), 0, 0), 249 | 'roll': 0, 250 | }, 251 | 'heel.02.R': { 252 | 'rotation': (m.radians(195), 0, 0), 253 | 'roll': 0, 254 | }, 255 | 'heel.02.L': { 256 | 'rotation': (m.radians(195), 0, 0), 257 | 'roll': 0, 258 | }, 259 | } 260 | -------------------------------------------------------------------------------- /freemocap_adapter/data_definitions/poses/ue_metahuman_tpose.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dictionary with the rotations of the Metahuman pose of the freemocap armature. 3 | """ 4 | import math as m 5 | 6 | ue_metahuman_tpose = { 7 | 'pelvis': { 8 | 'rotation' : ( 9 | m.radians(-90), 10 | 0, 11 | 0, 12 | ), 13 | 'roll': 0, 14 | }, 15 | 'pelvis_r': { 16 | 'rotation' : ( 17 | 0, 18 | m.radians(-90), 19 | 0, 20 | ), 21 | 'roll': 0, 22 | }, 23 | 'pelvis_l': { 24 | 'rotation' : ( 25 | 0, 26 | m.radians(90), 27 | 0, 28 | ), 29 | 'roll': 0, 30 | }, 31 | 'spine_01': { 32 | 'rotation' : ( 33 | m.radians(6), 34 | 0, 35 | 0, 36 | ), 37 | 'roll': 0, 38 | }, 39 | 'spine_04': { 40 | 'rotation' : ( 41 | m.radians(-9.86320126530132), 42 | 0, 43 | 0, 44 | ), 45 | 'roll': 0, 46 | }, 47 | 'neck_01': { 48 | 'rotation' : ( 49 | m.radians(11.491515802111422), 50 | 0, 51 | 0, 52 | ), 53 | 'roll': 0, 54 | }, 55 | 'face': { 56 | 'rotation' : ( 57 | m.radians(110), 58 | 0, 59 | 0, 60 | ), 61 | 'roll': 0, 62 | }, 63 | 'clavicle_r': { 64 | 'rotation' : ( 65 | 0, 66 | m.radians(-90), 67 | 0, 68 | ), 69 | 'roll': 0, 70 | }, 71 | 'clavicle_l': { 72 | 'rotation' : ( 73 | 0, 74 | m.radians(90), 75 | 0, 76 | ), 77 | 'roll': 0, 78 | }, 79 | 'upperarm_r': { 80 | 'rotation' : ( 81 | 0, 82 | m.radians(-90), 83 | 0, 84 | ), 85 | 'roll': m.radians(-90), 86 | }, 87 | 'upperarm_l': { 88 | 'rotation' : ( 89 | 0, 90 | m.radians(90), 91 | 0, 92 | ), 93 | 'roll': m.radians(90), 94 | }, 95 | 'lowerarm_r': { 96 | 'rotation' : ( 97 | 0, 98 | m.radians(-90), 99 | m.radians(1), 100 | ), 101 | 'roll': m.radians(-90), 102 | }, 103 | 'lowerarm_l': { 104 | 'rotation' : ( 105 | 0, 106 | m.radians(90), 107 | m.radians(-1), 108 | ), 109 | 'roll': m.radians(90), 110 | }, 111 | 'hand_r': { 112 | 'rotation' : ( 113 | 0, 114 | m.radians(-90), 115 | 0, 116 | ), 117 | 'roll': m.radians(-90), 118 | }, 119 | 'hand_l': { 120 | 'rotation' : ( 121 | 0, 122 | m.radians(90), 123 | 0, 124 | ), 125 | 'roll': m.radians(90), 126 | }, 127 | 128 | 'thumb_metacarpal_r': { 129 | 'rotation' : ( 130 | 0, 131 | m.radians(-90), 132 | m.radians(45), 133 | ), 134 | 'roll' : m.radians(-69) 135 | }, 136 | 'thumb_01_r': { 137 | 'rotation' : ( 138 | 0, 139 | m.radians(-90), 140 | m.radians(45), 141 | ), 142 | 'roll' : m.radians(-69) 143 | }, 144 | 'thumb_02_r': { 145 | 'rotation' : ( 146 | 0, 147 | m.radians(-90), 148 | m.radians(45), 149 | ), 150 | 'roll' : m.radians(-69) 151 | }, 152 | 'thumb_03_r': { 153 | 'rotation' : ( 154 | 0, 155 | m.radians(-90), 156 | m.radians(45), 157 | ), 158 | 'roll' : m.radians(-69) 159 | }, 160 | 'thumb_metacarpal_l': { 161 | 'rotation' : ( 162 | 0, 163 | m.radians(90), 164 | m.radians(-45), 165 | ), 166 | 'roll' : m.radians(69) 167 | }, 168 | 'thumb_01_l': { 169 | 'rotation' : ( 170 | 0, 171 | m.radians(90), 172 | m.radians(-45), 173 | ), 174 | 'roll' : m.radians(69) 175 | }, 176 | 'thumb_02_l': { 177 | 'rotation' : ( 178 | 0, 179 | m.radians(90), 180 | m.radians(-45), 181 | ), 182 | 'roll' : m.radians(69) 183 | }, 184 | 'thumb_03_l': { 185 | 'rotation' : ( 186 | 0, 187 | m.radians(90), 188 | m.radians(-45), 189 | ), 190 | 'roll' : m.radians(69) 191 | }, 192 | 'index_metacarpal_r': { 193 | 'rotation' : ( 194 | 0, 195 | m.radians(-90), 196 | m.radians(17), 197 | ), 198 | 'roll' : m.radians(0) 199 | }, 200 | 'index_01_r': { 201 | 'rotation' : ( 202 | 0, 203 | m.radians(-90), 204 | 0, 205 | ), 206 | 'roll' : m.radians(0) 207 | }, 208 | 'index_02_r': { 209 | 'rotation' : ( 210 | 0, 211 | m.radians(-90), 212 | 0, 213 | ), 214 | 'roll' : m.radians(0) 215 | }, 216 | 'index_03_r': { 217 | 'rotation' : ( 218 | 0, 219 | m.radians(-90), 220 | 0, 221 | ), 222 | 'roll' : m.radians(0) 223 | }, 224 | 'index_metacarpal_l': { 225 | 'rotation' : ( 226 | 0, 227 | m.radians(90), 228 | m.radians(-17), 229 | ), 230 | 'roll' : m.radians(0) 231 | }, 232 | 'index_01_l': { 233 | 'rotation' : ( 234 | 0, 235 | m.radians(90), 236 | 0, 237 | ), 238 | 'roll' : m.radians(0) 239 | }, 240 | 'index_02_l': { 241 | 'rotation' : ( 242 | 0, 243 | m.radians(90), 244 | 0, 245 | ), 246 | 'roll' : m.radians(0) 247 | }, 248 | 'index_03_l': { 249 | 'rotation' : ( 250 | 0, 251 | m.radians(90), 252 | 0, 253 | ), 254 | 'roll' : m.radians(0) 255 | }, 256 | 'middle_metacarpal_r': { 257 | 'rotation' : ( 258 | 0, 259 | m.radians(-90), 260 | m.radians(5.5), 261 | ), 262 | 'roll' : m.radians(0) 263 | }, 264 | 'middle_01_r': { 265 | 'rotation' : ( 266 | 0, 267 | m.radians(-90), 268 | 0, 269 | ), 270 | 'roll' : m.radians(0) 271 | }, 272 | 'middle_02_r': { 273 | 'rotation' : ( 274 | 0, 275 | m.radians(-90), 276 | 0, 277 | ), 278 | 'roll' : m.radians(0) 279 | }, 280 | 'middle_03_r': { 281 | 'rotation' : ( 282 | 0, 283 | m.radians(-90), 284 | 0, 285 | ), 286 | 'roll' : m.radians(0) 287 | }, 288 | 'middle_metacarpal_l': { 289 | 'rotation' : ( 290 | 0, 291 | m.radians(90), 292 | m.radians(-5.5), 293 | ), 294 | 'roll' : m.radians(0) 295 | }, 296 | 'middle_01_l': { 297 | 'rotation' : ( 298 | 0, 299 | m.radians(90), 300 | 0, 301 | ), 302 | 'roll' : m.radians(0) 303 | }, 304 | 'middle_02_l': { 305 | 'rotation' : ( 306 | 0, 307 | m.radians(90), 308 | 0, 309 | ), 310 | 'roll' : m.radians(0) 311 | }, 312 | 'middle_03_l': { 313 | 'rotation' : ( 314 | 0, 315 | m.radians(90), 316 | 0, 317 | ), 318 | 'roll' : m.radians(0) 319 | }, 320 | 'ring_metacarpal_r': { 321 | 'rotation' : ( 322 | 0, 323 | m.radians(-90), 324 | m.radians(-7.3), 325 | ), 326 | 'roll' : m.radians(0) 327 | }, 328 | 'ring_01_r': { 329 | 'rotation' : ( 330 | 0, 331 | m.radians(-90), 332 | 0, 333 | ), 334 | 'roll' : m.radians(0) 335 | }, 336 | 'ring_02_r': { 337 | 'rotation' : ( 338 | 0, 339 | m.radians(-90), 340 | 0, 341 | ), 342 | 'roll' : m.radians(0) 343 | }, 344 | 'ring_03_r': { 345 | 'rotation' : ( 346 | 0, 347 | m.radians(-90), 348 | 0, 349 | ), 350 | 'roll' : m.radians(0) 351 | }, 352 | 'ring_metacarpal_l': { 353 | 'rotation' : ( 354 | 0, 355 | m.radians(90), 356 | m.radians(7.3), 357 | ), 358 | 'roll' : m.radians(0) 359 | }, 360 | 'ring_01_l': { 361 | 'rotation' : ( 362 | 0, 363 | m.radians(90), 364 | 0 365 | ), 366 | 'roll' : m.radians(0) 367 | }, 368 | 'ring_02_l': { 369 | 'rotation' : ( 370 | 0, 371 | m.radians(90), 372 | 0 373 | ), 374 | 'roll' : m.radians(0) 375 | }, 376 | 'ring_03_l': { 377 | 'rotation' : ( 378 | 0, 379 | m.radians(90), 380 | 0 381 | ), 382 | 'roll' : m.radians(0) 383 | }, 384 | 'pinky_metacarpal_r': { 385 | 'rotation' : ( 386 | 0, 387 | m.radians(-90), 388 | m.radians(-19), 389 | ), 390 | 'roll' : m.radians(0) 391 | }, 392 | 'pinky_01_r': { 393 | 'rotation' : ( 394 | 0, 395 | m.radians(-90), 396 | 0, 397 | ), 398 | 'roll' : m.radians(0) 399 | }, 400 | 'pinky_02_r': { 401 | 'rotation' : ( 402 | 0, 403 | m.radians(-90), 404 | 0, 405 | ), 406 | 'roll' : m.radians(0) 407 | }, 408 | 'pinky_03_r': { 409 | 'rotation' : ( 410 | 0, 411 | m.radians(-90), 412 | 0, 413 | ), 414 | 'roll' : m.radians(0) 415 | }, 416 | 'pinky_metacarpal_l': { 417 | 'rotation' : ( 418 | 0, 419 | m.radians(90), 420 | m.radians(19), 421 | ), 422 | 'roll' : m.radians(0) 423 | }, 424 | 'pinky_01_l': { 425 | 'rotation' : ( 426 | 0, 427 | m.radians(90), 428 | 0, 429 | ), 430 | 'roll' : m.radians(0) 431 | }, 432 | 'pinky_02_l': { 433 | 'rotation' : ( 434 | 0, 435 | m.radians(90), 436 | 0, 437 | ), 438 | 'roll' : m.radians(0) 439 | }, 440 | 'pinky_03_l': { 441 | 'rotation' : ( 442 | 0, 443 | m.radians(90), 444 | 0, 445 | ), 446 | 'roll' : m.radians(0) 447 | }, 448 | 'thigh_r': { 449 | 'rotation' : ( 450 | m.radians(1), 451 | m.radians(-176.63197042733134), 452 | m.radians(4.106872792731369), 453 | ), 454 | 'roll': m.radians(101), 455 | }, 456 | 'thigh_l': { 457 | 'rotation' : ( 458 | m.radians(1), 459 | m.radians(176.63197042733134), 460 | m.radians(-4.106635016770888), 461 | ), 462 | 'roll': m.radians(-101), 463 | }, 464 | 'calf_r': { 465 | 'rotation' : ( 466 | m.radians(-175.12260790378525), 467 | m.radians(-2.6481038282450826), 468 | m.radians(56.97761905625937), 469 | ), 470 | 'roll': m.radians(101), 471 | }, 472 | 'calf_l': { 473 | 'rotation' : ( 474 | m.radians(-175.12259424340692), 475 | m.radians(2.648141394285518), 476 | m.radians(-56.97820303743341), 477 | ), 478 | 'roll': m.radians(-101), 479 | }, 480 | 'foot_r': { 481 | 'rotation' : ( 482 | m.radians(106.8930615673465), 483 | m.radians(-8.188085418524645), 484 | m.radians(-11.028648396211644), 485 | ), 486 | 'roll': m.radians(90), 487 | }, 488 | 'foot_l': { 489 | 'rotation' : ( 490 | m.radians(107.86645231653254), 491 | m.radians(8.93590490150277), 492 | m.radians(12.247207078107985), 493 | ), 494 | 'roll': m.radians(-90), 495 | }, 496 | 'heel_r': { 497 | 'rotation' : ( 498 | m.radians(195), 499 | 0, 500 | 0 501 | ), 502 | 'roll': 0, 503 | }, 504 | 'heel_l': { 505 | 'rotation' : ( 506 | m.radians(195), 507 | 0, 508 | 0 509 | ), 510 | 'roll': 0, 511 | }, 512 | } 513 | -------------------------------------------------------------------------------- /freemocap_video_export/README.md: -------------------------------------------------------------------------------- 1 | # Freemocap Video Export Blender Addon 2 | Blender addon for exporting the output of Freemocap. Choose a profile and click the export button. The export range will be determined by the scene range. 3 | 4 | ## Installation 5 | Install the .zip file as a normal Blender addon. 6 | 7 | ## Considerations 8 | If the scene range is left as default the addon will fail as the last frame has no animation data. Adjust the range so the last frame is not considered. 9 | 10 | ## Requirements 11 | 1. Add the files freemocap_logo.png and charuco_board.png to the same folder where the .blend file is located. 12 | 13 | 14 | -------------------------------------------------------------------------------- /freemocap_video_export/__init__.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | 'name' : 'Freemocap Video Export', 3 | 'author' : 'ajc27', 4 | 'version' : (1, 0, 0), 5 | 'blender' : (3, 0, 0), 6 | 'location' : '3D Viewport > Sidebar > Freemocap Video Export', 7 | 'description' : 'Add-on to export the Freemocap Blender output as video', 8 | 'category' : 'Development', 9 | } 10 | 11 | import bpy 12 | 13 | def register(): 14 | # Import addon classes 15 | from freemocap_video_export.addon_interface import FMC_VIDEO_EXPORT_PROPERTIES, VIEW3D_PT_freemocap_video_export, FMC_ADAPTER_OT_export_video 16 | 17 | # Register addon classes 18 | bpy.utils.register_class(FMC_VIDEO_EXPORT_PROPERTIES) 19 | bpy.utils.register_class(VIEW3D_PT_freemocap_video_export) 20 | bpy.utils.register_class(FMC_ADAPTER_OT_export_video) 21 | 22 | bpy.types.Scene.fmc_video_export_tool = bpy.props.PointerProperty(type = FMC_VIDEO_EXPORT_PROPERTIES) 23 | 24 | def unregister(): 25 | # Import addon classes 26 | from .addon_interface import FMC_VIDEO_EXPORT_PROPERTIES, VIEW3D_PT_freemocap_video_export, FMC_ADAPTER_OT_export_video 27 | 28 | # Unregister addon classes 29 | bpy.utils.unregister_class(FMC_VIDEO_EXPORT_PROPERTIES) 30 | bpy.utils.unregister_class(VIEW3D_PT_freemocap_video_export) 31 | bpy.utils.unregister_class(FMC_ADAPTER_OT_export_video) 32 | 33 | del bpy.types.Scene.fmc_video_export_tool 34 | 35 | if __name__ == "__main__": 36 | register() -------------------------------------------------------------------------------- /freemocap_video_export/addon_interface.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Operator, Panel 3 | from bpy.props import EnumProperty 4 | from .functions import fmc_export_video 5 | from . import config_variables 6 | 7 | # Class with the different properties of the methods 8 | class FMC_VIDEO_EXPORT_PROPERTIES(bpy.types.PropertyGroup): 9 | 10 | export_profile: bpy.props.EnumProperty( 11 | name = '', 12 | description = 'Profile of the export video', 13 | items = [('debug', 'Debug', ''), 14 | ('showcase', 'Showcase', ''), 15 | ('scientific', 'Scientific', ''), 16 | ], 17 | ) 18 | 19 | scientific_ground_contact_threshold: bpy.props.FloatProperty( 20 | name = '', 21 | default = 0.05, 22 | description = 'Ground contact threshold (m)' 23 | ) 24 | 25 | # UI Panel Class 26 | class VIEW3D_PT_freemocap_video_export(Panel): 27 | bl_space_type = "VIEW_3D" 28 | bl_region_type = "UI" 29 | bl_category = "Freemocap Video Export" 30 | bl_label = "Freemocap Video Export" 31 | 32 | def draw(self, context): 33 | layout = self.layout 34 | scene = context.scene 35 | fmc_video_export_tool = scene.fmc_video_export_tool 36 | 37 | box = layout.box() 38 | 39 | split = box.column().row().split(factor=0.6) 40 | split.column().label(text='Video Profile') 41 | split.split().column().prop(fmc_video_export_tool, 'export_profile') 42 | 43 | box.label(text='Scientific Profile Options') 44 | split = box.column().row().split(factor=0.6) 45 | split.column().label(text='Ground Contact Threshold (m)') 46 | split.split().column().prop(fmc_video_export_tool, 'scientific_ground_contact_threshold') 47 | 48 | box.operator('fmc_export_video.export_video', text='Export Video') 49 | 50 | # Operator classes that executes the methods 51 | class FMC_ADAPTER_OT_export_video(Operator): 52 | bl_idname = 'fmc_export_video.export_video' 53 | bl_label = 'Freemocap Export Video' 54 | bl_description = "Export the Freemocap Blender output as a video file" 55 | bl_options = {'REGISTER', 'UNDO_GROUPED'} 56 | 57 | def execute(self, context): 58 | scene = context.scene 59 | fmc_video_export_tool = scene.fmc_video_export_tool 60 | 61 | print("Exporting video.......") 62 | 63 | config_variables.visual_components['vc_plot_com_bos']['ground_contact_threshold'] = fmc_video_export_tool.scientific_ground_contact_threshold 64 | 65 | fmc_export_video(scene=scene, export_profile=fmc_video_export_tool.export_profile) 66 | 67 | print("Video export completed.") 68 | 69 | return {'FINISHED'} 70 | -------------------------------------------------------------------------------- /freemocap_video_export/assets/charuco_board.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_video_export/assets/charuco_board.png -------------------------------------------------------------------------------- /freemocap_video_export/assets/freemocap_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_video_export/assets/freemocap_logo.png -------------------------------------------------------------------------------- /freemocap_video_export/config_variables.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | export_profiles = { 4 | 'debug': { 5 | 'resolution_x': 1920, 6 | 'resolution_y': 1080, 7 | 'bitrate': 2000000, 8 | 'visual_components': [ 9 | 'vc_frame_number', 10 | 'vc_logo', 11 | 'vc_recording_parameters', 12 | 'vc_mediapipe_skeleton_segment_lengths', 13 | ], 14 | }, 15 | 'showcase': { 16 | 'resolution_x': 1080, 17 | 'resolution_y': 1920, 18 | 'bitrate': 5000000, 19 | 'visual_components': [ 20 | 'vc_logo', 21 | ], 22 | 'background_path': '/assets/charuco_board.png', 23 | }, 24 | 'scientific': { 25 | 'resolution_x': 1920, 26 | 'resolution_y': 1080, 27 | 'bitrate': 3000000, 28 | 'visual_components': [ 29 | 'vc_frame_number', 30 | 'vc_logo', 31 | 'vc_mediapipe_skeleton_segment_lengths', 32 | 'vc_plot_com_bos', 33 | 'vc_plot_foot_deviation', 34 | ], 35 | }, 36 | } 37 | 38 | render_parameters = { 39 | 'scene.render.engine' : 'BLENDER_EEVEE', 40 | 'scene.eevee.taa_render_samples' : 1, 41 | 'scene.render.image_settings.file_format' : 'FFMPEG', 42 | 'scene.render.ffmpeg.format' : 'MPEG4', 43 | 'scene.render.ffmpeg.codec' : 'H264', 44 | 'scene.render.ffmpeg.constant_rate_factor' : 'LOWEST', 45 | 'scene.render.ffmpeg.ffmpeg_preset' : 'REALTIME', 46 | 'scene.render.fps' : 30, 47 | 'scene.render.resolution_percentage' : 100, 48 | 'scene.eevee.use_gtao' : False, 49 | 'scene.eevee.use_bloom' : False, 50 | 'scene.eevee.use_ssr' : False, 51 | 'scene.eevee.use_motion_blur' : False, 52 | 'scene.eevee.volumetric_samples' : 4, 53 | 'scene.eevee.use_volumetric_lights' : False, 54 | 'scene.eevee.use_soft_shadows' : True, 55 | } 56 | 57 | render_background = { 58 | 'height' : 10, 59 | 'y_axis_offset' : 0.1, 60 | } 61 | 62 | lens_FOVs = { 63 | '50mm': { 64 | 'horizontal_fov': 39.6, 65 | 'vertical_fov': 22.8965642148994, 66 | } 67 | } 68 | 69 | color_palette = { 70 | 'crystal': { 71 | 'rgb': (164, 214, 217), 72 | 'bgr': (217, 214, 164), 73 | 'hex': '#A4D6D9', 74 | }, 75 | 'dark_terra_cotta': { 76 | 'rgb': (217, 81, 87), 77 | 'bgr': (87, 81, 217), 78 | 'hex': '#D95157', 79 | }, 80 | 'police_blue': { 81 | 'rgb': (54, 93, 95), 82 | 'bgr': (95, 93, 54), 83 | 'hex': '#365D5F', 84 | }, 85 | 'japanese_indigo': { 86 | 'rgb': (37, 67, 66), 87 | 'bgr': (66, 67, 37), 88 | 'hex': '#254342', 89 | }, 90 | 'glossy_gold': { 91 | 'rgb': (250, 228, 129), 92 | 'bgr': (129, 228, 250), 93 | 'hex': '#FAE481', 94 | }, 95 | 96 | } 97 | 98 | visual_components = { 99 | 'frame_number': { 100 | 'position_x_pct': 0.02, 101 | 'position_y_pct': 0.05, 102 | 'font' : cv2.FONT_HERSHEY_SIMPLEX, 103 | 'fontScale' : 1, 104 | 'color' : color_palette['crystal']['bgr'], 105 | 'thickness' : 2, 106 | 'lineType' : cv2.LINE_AA, 107 | }, 108 | 'logo': { 109 | 'relative_path' : '/assets/freemocap_logo.png', 110 | 'resize_largest_side_pct' : 0.1, 111 | 'position_x_pct' : 0.9, 112 | 'position_y_pct' : 0.02, 113 | }, 114 | 'static_json_table': { 115 | 'float_decimal_digits' : 2, 116 | }, 117 | 'recording_parameters': { 118 | 'relative_path' : '/output_data/recording_parameters.json', 119 | 'position_x_pct' : 0.79, 120 | 'position_y_pct' : 0.6, 121 | 'text_parameters' : { 122 | 'level_1': { 123 | 'font' : cv2.FONT_HERSHEY_SIMPLEX, 124 | 'fontScale' : 0.6, 125 | 'color' : color_palette['dark_terra_cotta']['bgr'], 126 | 'thickness' : 1, 127 | 'lineType' : cv2.LINE_AA, 128 | }, 129 | 'level_2': { 130 | 'font' : cv2.FONT_HERSHEY_SIMPLEX, 131 | 'fontScale' : 0.55, 132 | 'color' : color_palette['crystal']['bgr'], 133 | 'thickness' : 1, 134 | 'lineType' : cv2.LINE_AA, 135 | }, 136 | 'level_3': { 137 | 'font' : cv2.FONT_HERSHEY_SIMPLEX, 138 | 'fontScale' : 0.5, 139 | 'color' : color_palette['glossy_gold']['bgr'], 140 | 'thickness' : 1, 141 | 'lineType' : cv2.LINE_AA, 142 | }, 143 | }, 144 | }, 145 | 'mediapipe_skeleton_segment_lengths': { 146 | 'relative_path' : '/output_data/mediapipe_skeleton_segment_lengths.json', 147 | 'position_x_pct' : 0.02, 148 | 'position_y_pct' : 0.07, 149 | 'text_parameters' : { 150 | 'level_1': { 151 | 'font' : cv2.FONT_HERSHEY_SIMPLEX, 152 | 'fontScale' : 0.4, 153 | 'color' : color_palette['dark_terra_cotta']['bgr'], 154 | 'thickness' : 1, 155 | 'lineType' : cv2.LINE_AA, 156 | }, 157 | 'level_2': { 158 | 'font' : cv2.FONT_HERSHEY_SIMPLEX, 159 | 'fontScale' : 0.35, 160 | 'color' : color_palette['crystal']['bgr'], 161 | 'thickness' : 1, 162 | 'lineType' : cv2.LINE_AA, 163 | }, 164 | 'level_3': { 165 | 'font' : cv2.FONT_HERSHEY_SIMPLEX, 166 | 'fontScale' : 0.3, 167 | 'color' : color_palette['glossy_gold']['bgr'], 168 | 'thickness' : 1, 169 | 'lineType' : cv2.LINE_AA, 170 | }, 171 | }, 172 | }, 173 | 'vc_plot_com_bos': { 174 | 'topleft_x_pct': 0.75, 175 | 'topleft_y_pct': 0.7, 176 | 'width_pct': 0.23, 177 | 'height_pct': 0.25, 178 | 'ground_contact_threshold': 0.05, 179 | }, 180 | 'vc_plot_foot_deviation': { 181 | 'topleft_x_pct': 0.75, 182 | 'topleft_y_pct': 0.4, 183 | 'width_pct': 0.23, 184 | 'height_pct': 0.25, 185 | } 186 | } -------------------------------------------------------------------------------- /freemocap_video_export/freemocap_video_export_addon.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajc27-git/freemocap_tools/eafbfdc03e5d6ba5af9d61646a2a8c5dbe971ed3/freemocap_video_export/freemocap_video_export_addon.zip -------------------------------------------------------------------------------- /freemocap_video_export/functions.py: -------------------------------------------------------------------------------- 1 | import time 2 | import bpy 3 | import math 4 | import mathutils 5 | import os 6 | import cv2 7 | import numpy as np 8 | from pathlib import Path 9 | from importlib.machinery import SourceFileLoader 10 | import addon_utils 11 | from .config_variables import * 12 | from .classes import * 13 | 14 | # Export the Freemocap Blender output as a video file 15 | def fmc_export_video(scene: bpy.types.Scene=None, 16 | export_profile: str='debug') -> None: 17 | 18 | print("Exporting fmc video...") 19 | 20 | # Get start time 21 | start = time.time() 22 | 23 | # Place the required cameras 24 | cameras_positions = place_cameras(scene, export_profile) 25 | 26 | # Place the required lights 27 | place_lights(scene, cameras_positions) 28 | 29 | # Rearrange the background videos 30 | rearrange_background_videos(scene, videos_x_separation=0.1) 31 | 32 | # Get the Blender file directory 33 | file_directory = Path(bpy.data.filepath).parent 34 | 35 | # Add the render background for the export profiles that have background 36 | if export_profile in ('showcase'): 37 | add_render_background(scene, 'showcase') 38 | 39 | # Set the output directory 40 | video_folder = file_directory / 'video' 41 | video_folder.mkdir(parents=True, exist_ok=True) 42 | 43 | # Set the output file name 44 | output_file = os.path.split(bpy.data.filepath)[1][:-6] + "_aux" + ".mp4" 45 | 46 | # Set the rendering properties 47 | for key, value in render_parameters.items(): 48 | 49 | # Split the key into context and property names 50 | key_parts = key.split(".") 51 | 52 | # Start with the bpy.context object 53 | context = bpy.context 54 | 55 | # Traverse through the key parts to access the correct context and property 56 | for part in key_parts[:-1]: 57 | context = getattr(context, part) 58 | 59 | # Assign the new value to the property 60 | setattr(context, key_parts[-1], value) 61 | 62 | # Set the render resolution based on the export profile 63 | bpy.context.scene.render.resolution_x = export_profiles[export_profile]['resolution_x'] 64 | bpy.context.scene.render.resolution_y = export_profiles[export_profile]['resolution_y'] 65 | 66 | # Set the output file 67 | render_path = os.path.join(video_folder, output_file) 68 | bpy.context.scene.render.filepath = render_path 69 | 70 | # Render the animation 71 | bpy.ops.render.render(animation=True) 72 | 73 | # Add the visual components 74 | add_visual_components(render_path=render_path, 75 | file_directory=file_directory, 76 | export_profile=export_profile, 77 | scene=scene) 78 | 79 | # Try to remove the auxiliary video file 80 | try: 81 | os.remove(render_path) 82 | except: 83 | print('Error while removing the auxiliary video file.') 84 | 85 | # Get end time and print execution time 86 | end = time.time() 87 | print('Finished Rendering. Execution time (s): ' + str(math.trunc((end - start)*1000)/1000)) 88 | 89 | 90 | def place_cameras( 91 | scene: bpy.types.Scene=None, 92 | export_profile: str='debug' 93 | ) -> list: 94 | 95 | # Set the horizontal and vertical FOV according to the aspect ratio 96 | if export_profiles[export_profile]['resolution_x'] / export_profiles[export_profile]['resolution_y'] >= 1: 97 | camera_horizontal_fov = lens_FOVs['50mm']['horizontal_fov'] # 39.6 # 2 * math.atan((0.5 * render_width) / (0.5 * render_height / math.tan(vFOV / 2))) 98 | camera_vertical_fov = lens_FOVs['50mm']['vertical_fov'] # 22.8965642148994 # 2 * math.atan((0.5 * render_height) / (0.5 * render_width / math.tan(hFOV / 2))) 99 | else: 100 | camera_horizontal_fov = lens_FOVs['50mm']['vertical_fov'] 101 | camera_vertical_fov = lens_FOVs['50mm']['horizontal_fov'] 102 | 103 | # Camera angle margin to show more area than the capture movement 104 | angle_margin = 0.9 105 | 106 | # List of cameras positions 107 | cameras_positions = [] 108 | 109 | # Create the camera 110 | camera_data = bpy.data.cameras.new(name="Front_Camera") 111 | camera = bpy.data.objects.new(name="Front_Camera", object_data=camera_data) 112 | scene.collection.objects.link(camera) 113 | 114 | # Assign the camera to the scene 115 | scene.camera = camera 116 | 117 | # Set the starting extreme points 118 | highest_point = mathutils.Vector([0, 0, 0]) 119 | lowest_point = mathutils.Vector([0, 0, 0]) 120 | leftmost_point = mathutils.Vector([0, 0, 0]) 121 | rightmost_point = mathutils.Vector([0, 0, 0]) 122 | 123 | # Find the extreme points as the highest, lowest, leftmost, rightmost considering all the frames 124 | for frame in range (scene.frame_start, scene.frame_end): 125 | 126 | scene.frame_set(frame) 127 | 128 | for object in scene.objects: 129 | if object.type == 'EMPTY' and object.name != 'freemocap_origin_axes' and object.name != 'world_origin' and object.name != 'center_of_mass_data_parent' and object.name != 'head': 130 | if object.matrix_world.translation[2] > highest_point[2]: 131 | highest_point = object.matrix_world.translation.copy() 132 | if object.matrix_world.translation[2] < lowest_point[2]: 133 | lowest_point = object.matrix_world.translation.copy() 134 | if object.matrix_world.translation[0] < leftmost_point[0]: 135 | leftmost_point = object.matrix_world.translation.copy() 136 | if object.matrix_world.translation[0] > rightmost_point[0]: 137 | rightmost_point = object.matrix_world.translation.copy() 138 | 139 | # Draw the extreme points as mesh spheres 140 | # bpy.ops.mesh.primitive_uv_sphere_add(radius=0.05, enter_editmode=False, align='WORLD', location=highest_point, scale=(1, 1, 1)) 141 | # bpy.data.objects['Sphere'].name = 'highest_point' 142 | # bpy.ops.mesh.primitive_uv_sphere_add(radius=0.05, enter_editmode=False, align='WORLD', location=lowest_point, scale=(1, 1, 1)) 143 | # bpy.data.objects['Sphere'].name = 'lowest_point' 144 | # bpy.ops.mesh.primitive_uv_sphere_add(radius=0.05, enter_editmode=False, align='WORLD', location=leftmost_point, scale=(1, 1, 1)) 145 | # bpy.data.objects['Sphere'].name = 'leftmost_point' 146 | # bpy.ops.mesh.primitive_uv_sphere_add(radius=0.05, enter_editmode=False, align='WORLD', location=rightmost_point, scale=(1, 1, 1)) 147 | # bpy.data.objects['Sphere'].name = 'rightmost_point' 148 | 149 | # Calculate the position of the camera assuming is centered at 0 on the x axis and pointing towards the y axis 150 | # and covers the extreme points including a margin 151 | 152 | # Camera distances to just cover the leftmost and rightmost points 153 | camera_y_axis_distance_leftmost = leftmost_point[1] - abs(leftmost_point[0]) / math.atan(math.radians(camera_horizontal_fov * angle_margin / 2)) 154 | camera_y_axis_distance_rightmost = rightmost_point[1] - abs(rightmost_point[0]) / math.atan(math.radians(camera_horizontal_fov * angle_margin / 2)) 155 | 156 | # Camera distances to just cover the highest and lowest points considering its centered between the two points on the z axis 157 | camera_y_axis_distance_highest = highest_point[1] - ((highest_point[2] - lowest_point[2]) / 2) / math.atan(math.radians(camera_vertical_fov * angle_margin / 2)) 158 | camera_y_axis_distance_lowest = lowest_point[1] - ((highest_point[2] - lowest_point[2]) / 2) / math.atan(math.radians(camera_vertical_fov * angle_margin / 2)) 159 | 160 | # Calculate the final y position of the camera as the minimum distance 161 | camera_y_axis_distance = min(camera_y_axis_distance_leftmost, camera_y_axis_distance_rightmost, camera_y_axis_distance_highest, camera_y_axis_distance_lowest) 162 | 163 | camera.location = (0, camera_y_axis_distance, highest_point[2] - (highest_point[2] - lowest_point[2]) / 2) 164 | camera.rotation_euler = (math.radians(90), 0, 0) 165 | 166 | # Add the camera position to the cameras position list 167 | cameras_positions.append(camera.location) 168 | 169 | return cameras_positions 170 | 171 | def place_lights( 172 | scene: bpy.types.Scene=None, 173 | cameras_positions: list=None 174 | ) -> None: 175 | 176 | # Lights vertical offset in Blender units 177 | lights_vertical_offset = 2 178 | 179 | # Create the light 180 | light_data = bpy.data.lights.new(name="Light", type='SPOT') 181 | light = bpy.data.objects.new(name="Light", object_data=light_data) 182 | scene.collection.objects.link(light) 183 | 184 | # Set the strength of the light 185 | light.data.energy = 200 * math.sqrt(lights_vertical_offset**2 + cameras_positions[0][1]**2) 186 | 187 | # Set the location of the light 188 | light.location = (cameras_positions[0][0], cameras_positions[0][1], cameras_positions[0][2] + lights_vertical_offset) 189 | 190 | # Set the rotation of the light so it points to the point (0, 0, cameras_positions[0][2]) 191 | light.rotation_euler = (math.atan(abs(cameras_positions[0][1]) / lights_vertical_offset), 0, 0) 192 | 193 | def rearrange_background_videos( 194 | scene: bpy.types.Scene=None, 195 | videos_x_separation: float=0.1 196 | ) -> None: 197 | 198 | # Create a list with the background videos 199 | background_videos = [] 200 | 201 | # Append the background videos to the list 202 | for object in scene.objects: 203 | if 'video_' in object.name: 204 | background_videos.append(object) 205 | 206 | # Get the videos x dimension 207 | videos_x_dimension = background_videos[0].dimensions.x 208 | 209 | # Calculate the first video x position (from the left to the right) 210 | first_video_x_position = -(len(background_videos) - 1) / 2 * (videos_x_dimension + videos_x_separation) 211 | 212 | # Iterate through the background videos 213 | for video_index in range(len(background_videos)): 214 | 215 | # Set the location of the video 216 | background_videos[video_index].location[0] = first_video_x_position + video_index * (videos_x_dimension + videos_x_separation) 217 | 218 | def add_visual_components( 219 | render_path: str, 220 | file_directory: Path, 221 | export_profile: str='debug', 222 | scene: bpy.types.Scene=None, 223 | ) -> None: 224 | 225 | # Get a reference to the render 226 | video = cv2.VideoCapture(render_path) 227 | 228 | # Create a VideoWriter object to write the output frames 229 | output_writer = cv2.VideoWriter( 230 | os.path.dirname(render_path) + '/' + os.path.basename(render_path)[:-7] + export_profile + '.mp4', 231 | cv2.VideoWriter_fourcc(*'mp4v'), 232 | render_parameters['scene.render.fps'], 233 | (export_profiles[export_profile]['resolution_x'], 234 | export_profiles[export_profile]['resolution_y']), 235 | export_profiles[export_profile]['bitrate'], 236 | ) 237 | 238 | # Create new frame_info object 239 | frame_info = frame_information( 240 | file_directory=str(file_directory), 241 | width=export_profiles[export_profile]['resolution_x'], 242 | height=export_profiles[export_profile]['resolution_y'], 243 | total_frames=int(video.get(cv2.CAP_PROP_FRAME_COUNT)), 244 | total_frames_digits=len(str(int(video.get(cv2.CAP_PROP_FRAME_COUNT)))), 245 | scene=scene, 246 | ) 247 | 248 | # Creat the visual component objects list 249 | visual_components_list = [] 250 | for visual_component in export_profiles[export_profile]['visual_components']: 251 | visual_component_class = globals()[visual_component] 252 | visual_components_list.append(visual_component_class(frame_info)) 253 | 254 | index_frame = 0 255 | # Add the logo to the video 256 | while video.isOpened(): 257 | ret, frame = video.read() 258 | if not ret: 259 | break 260 | 261 | # Update the frame number in frame_info 262 | frame_info.frame_number = index_frame 263 | 264 | # Add each visual component 265 | for visual_component in visual_components_list: 266 | frame = visual_component.add_component(frame, frame_info) 267 | 268 | # Write the frame 269 | output_writer.write(frame) 270 | 271 | index_frame += 1 272 | 273 | # Delete the "plot_aux.png" file if it exists 274 | try: 275 | os.remove(str(frame_info.file_directory) + '/video/' + 'plot_aux.png') 276 | except FileNotFoundError: 277 | pass 278 | 279 | video.release() 280 | output_writer.release() 281 | cv2.destroyAllWindows() 282 | 283 | def add_render_background(scene: bpy.types.Scene=None, 284 | export_profile: str=None,): 285 | 286 | # Set the path to the PNG image 287 | image_path = os.path.dirname(os.path.realpath(__file__)) + export_profiles[export_profile]['background_path'] 288 | print(image_path) 289 | 290 | # check if the addon is enabled 291 | loaded_default, loaded_state = addon_utils.check('io_import_images_as_planes') 292 | if not loaded_state: 293 | # enable the addon 294 | addon_utils.enable('io_import_images_as_planes') 295 | 296 | # Import the image as plane 297 | bpy.ops.import_image.to_plane(files=[{"name": str(image_path)}], 298 | size_mode='ABSOLUTE', 299 | height=render_background['height'], 300 | ) 301 | 302 | # Change the location of the plane ot be behind the video_0 element 303 | bpy.data.objects['charuco_board'].location = (bpy.data.objects['charuco_board'].location[0], 304 | bpy.data.objects['video_0'].location[1] + render_background['y_axis_offset'], 305 | bpy.data.objects['Front_Camera'].location[2]) 306 | -------------------------------------------------------------------------------- /freemocap_visualizer/README.md: -------------------------------------------------------------------------------- 1 | # Freemocap Visualizer 2 | Add-on to visualize the Freemocap Blender output. Some of its features: 3 | 1. One-click base elements visibility toggle. 4 | 2. Add motion paths to the joint markers and center of mass. 5 | 3. Add Center of Mass (COM) vertical projection with custom colors. 6 | 4. Add animated joint angles with mesh and text with angle value. Can set custom colors. 7 | 5. Add animated Base of Support (BOS) polygon based on points of contact and a z threshold. 8 | 9 | # Requirements 10 | Make sure that the scipy and shapely python modules are installed in your Blender's python folder. 11 | If they are not installed you will get a "ModuleNotFoundError: No module named scipy/shapely" when installing the addon. 12 | To install the scipy and shapely packages run this commands inside your Blender python folder: 13 | `python -m pip install scipy` 14 | `python -m pip install shapely` 15 | 16 | For example: 17 | 18 | `C:\Program Files\Blender Foundation\Blender 3.6\3.6\python\bin> .\python.exe -m pip install scipy`. 19 | 20 | `C:\Program Files\Blender Foundation\Blender 3.6\3.6\python\bin> .\python.exe -m pip install shapely`. 21 | 22 | # Installation 23 | Install as a regular *.zip add-on in Edit->Preferences-Add-ons. 24 | 25 | # Notes 26 | The addon doesn't consider all possible use combinations. So errors might happen when using the functions multiple times. 27 | Is better to undo the functions instead of deleting the meshes and create them again. 28 | 29 | Addon captures: 30 | 31 | ![image](https://github.com/ajc27-git/freemocap_tools/assets/36526931/cf05f630-dcbc-43d0-bc91-9fe5539b1f2b) 32 | 33 | ![image](https://github.com/ajc27-git/freemocap_tools/assets/36526931/5dc5a5c6-a0b4-4f18-8a27-03855343143a) 34 | 35 | -------------------------------------------------------------------------------- /freemocap_visualizer/__init__.py: -------------------------------------------------------------------------------- 1 | bl_info = { 2 | 'name' : 'Freemocap Visualizer', 3 | 'author' : 'ajc27', 4 | 'version' : (1, 1, 0), 5 | 'blender' : (3, 0, 0), 6 | 'location' : '3D Viewport > Sidebar > Freemocap Visualizer', 7 | 'description' : 'Add-on to help visualize the Freemocap Blender output', 8 | 'category' : 'Development', 9 | } 10 | 11 | import bpy 12 | from .addon_interface import (FMC_VISUALIZER_PROPERTIES, 13 | VIEW3D_PT_freemocap_visualizer, 14 | FMC_VISUALIZER_ADD_COM_VERTICAL_PROJECTION, 15 | FMC_VISUALIZER_ADD_JOINT_ANGLES, 16 | FMC_VISUALIZER_ADD_BASE_OF_SUPPORT) 17 | 18 | def register(): 19 | 20 | # Register addon classes 21 | bpy.utils.register_class(FMC_VISUALIZER_PROPERTIES) 22 | bpy.utils.register_class(VIEW3D_PT_freemocap_visualizer) 23 | bpy.utils.register_class(FMC_VISUALIZER_ADD_COM_VERTICAL_PROJECTION) 24 | bpy.utils.register_class(FMC_VISUALIZER_ADD_JOINT_ANGLES) 25 | bpy.utils.register_class(FMC_VISUALIZER_ADD_BASE_OF_SUPPORT) 26 | 27 | bpy.types.Scene.fmc_visualizer_tool = bpy.props.PointerProperty(type = FMC_VISUALIZER_PROPERTIES) 28 | 29 | def unregister(): 30 | 31 | # Unregister addon classes 32 | bpy.utils.unregister_class(FMC_VISUALIZER_PROPERTIES) 33 | bpy.utils.unregister_class(VIEW3D_PT_freemocap_visualizer) 34 | bpy.utils.unregister_class(FMC_VISUALIZER_ADD_COM_VERTICAL_PROJECTION) 35 | bpy.utils.unregister_class(FMC_VISUALIZER_ADD_JOINT_ANGLES) 36 | bpy.utils.unregister_class(FMC_VISUALIZER_ADD_BASE_OF_SUPPORT) 37 | 38 | del bpy.types.Scene.fmc_visualizer_tool 39 | 40 | if __name__ == "__main__": 41 | register() 42 | -------------------------------------------------------------------------------- /freemocap_visualizer/auxiliary_functions.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | import mathutils 3 | 4 | # Function to hide (or unhide) Blender objects 5 | def hide_objects(data_object: bpy.types.Object, 6 | hide: bool = True, 7 | hide_children_not_parent: bool = False,)->None: 8 | 9 | if hide_children_not_parent: 10 | for child_object in data_object.children: 11 | # Hide child object 12 | child_object.hide_set(hide) 13 | # Execute the function recursively 14 | hide_objects(child_object, hide, hide_children_not_parent) 15 | else: 16 | data_object.hide_set(hide) 17 | 18 | # Function to draw a vector for debbuging purposes 19 | def draw_vector(origin, angle, name): 20 | 21 | bpy.ops.object.empty_add(type='SINGLE_ARROW', align='WORLD', location=origin, rotation=mathutils.Vector([0,0,1]).rotation_difference(angle).to_euler(), scale=(0.002, 0.002, 0.002)) 22 | bpy.data.objects["Empty"].name = name 23 | 24 | bpy.ops.object.empty_add(type='SPHERE', align='WORLD', location=(origin+angle*0.5), scale=(0.001, 0.001, 0.001)) 25 | bpy.data.objects["Empty"].scale = (0.01, 0.01, 0.01) 26 | bpy.data.objects["Empty"].name = 'Sphere_' + name 27 | 28 | return 29 | 30 | # Function to check if a point is inside a polygon 31 | def is_point_inside_polygon(x, y, polygon): 32 | n = len(polygon) 33 | inside = False 34 | p1x, p1y = polygon[0] 35 | for i in range(n+1): 36 | p2x, p2y = polygon[i % n] 37 | if y > min(p1y, p2y): 38 | if y <= max(p1y, p2y): 39 | if x <= max(p1x, p2x): 40 | if p1y != p2y: 41 | xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x 42 | if p1x == p2x or x <= xinters: 43 | inside = not inside 44 | p1x, p1y = p2x, p2y 45 | return inside 46 | 47 | # Function to find the convex hull of a set of points 48 | def graham_scan(points): 49 | # Function to determine the orientation of 3 points (p, q, r) 50 | def orientation(p, q, r): 51 | val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]) 52 | if val == 0: 53 | return 0 # Collinear 54 | return 1 if val > 0 else -1 # Clockwise or Counterclockwise 55 | 56 | # Sort the points based on their x-coordinates 57 | sorted_points = sorted(points, key=lambda point: (point[0], point[1])) 58 | 59 | # Initialize the stack to store the convex hull points 60 | stack = [] 61 | 62 | # Iterate through the sorted points to find the convex hull 63 | for point in sorted_points: 64 | while len(stack) > 1 and orientation(stack[-2], stack[-1], point) != -1: 65 | stack.pop() 66 | stack.append(point) 67 | 68 | return stack 69 | 70 | -------------------------------------------------------------------------------- /freemocap_visualizer/data_definitions.py: -------------------------------------------------------------------------------- 1 | joints_angle_points = { 2 | 'right_shoulder': {'parent': 'neck_center', 'child': 'right_elbow'}, 3 | 'left_shoulder': {'parent': 'neck_center', 'child': 'left_elbow'}, 4 | 'right_elbow': {'parent': 'right_shoulder', 'child': 'right_wrist'}, 5 | 'left_elbow': {'parent': 'left_shoulder', 'child': 'left_wrist'}, 6 | 'right_wrist': {'parent': 'right_elbow', 'child': 'right_hand_middle'}, 7 | 'left_wrist': {'parent': 'left_elbow', 'child': 'left_hand_middle'}, 8 | 'right_hip': {'parent': 'hips_center', 'child': 'right_knee'}, 9 | 'left_hip': {'parent': 'hips_center', 'child': 'left_knee'}, 10 | 'right_knee': {'parent': 'right_hip', 'child': 'right_ankle'}, 11 | 'left_knee': {'parent': 'left_hip', 'child': 'left_ankle'}, 12 | 'right_ankle': {'parent': 'right_knee', 'child': 'right_foot_index'}, 13 | 'left_ankle': {'parent': 'left_knee', 'child': 'left_foot_index'}, 14 | } 15 | points_of_contact = [ 16 | 'right_heel', 17 | 'left_heel', 18 | 'right_foot_index', 19 | 'left_foot_index', 20 | ] 21 | -------------------------------------------------------------------------------- /video_sync_script/README.md: -------------------------------------------------------------------------------- 1 | Script to synchronize videos before processing in Freemocap. 2 | 3 | The method used to synchronize the videos is by detecting a high difference in brightness within consecutive frames of the video. 4 | For best results, the brightness difference should be produced by turning on a lamp in front all of the cameras at the same time at the beginning of the recording. 5 | 6 | The videos should be placed in a directory called "videos" inside the same folder as the script. 7 | 8 | It can handle different video formats and orientations. 9 | 10 | Some parameters can be adjusted in the main function. 11 | 12 | Module requirements: 13 | - OpenCV 14 | - MoviePy 15 | -------------------------------------------------------------------------------- /video_sync_script/video_sync.py: -------------------------------------------------------------------------------- 1 | import os 2 | import cv2 3 | from moviepy.editor import VideoFileClip 4 | from moviepy.video.fx.all import speedx 5 | 6 | # Define function to normalize the videos framerates 7 | def normalize_framerates( 8 | source_folder_path: str='./videos', 9 | destination_folder_path: str='./normalized_videos', 10 | new_frame_rate: float=30, 11 | new_bitrate: str='15000k', 12 | new_width: int=1080, 13 | new_height: int=1920, 14 | encoding_codec: str='libx264', 15 | encoding_preset: str='ultrafast', 16 | encoding_threads: int=2) -> None: 17 | 18 | print('Executing normalize_framerates()...') 19 | 20 | # Try to get a list of files in the folder 21 | try: 22 | video_files = os.listdir(source_folder_path) 23 | except: 24 | print('Could not get a list of files in the video source folder.') 25 | return 26 | 27 | # Loop through the video files 28 | for video_file in video_files: 29 | 30 | # Try to open the video file 31 | try: 32 | video = VideoFileClip(source_folder_path + '/' + video_file) 33 | except: 34 | continue 35 | 36 | # Set the output extension 37 | output_filename = 'normalized_' + video_file[:-4] + '.mp4' 38 | 39 | # Get the width and height of the video 40 | width, height = video.size 41 | # Get the video rotation 42 | rotation = video.rotation 43 | 44 | # If the new aspect ratio mode is different from the video aspect ratio and the video rotation is 0 then rotate the video 90 degrees 45 | if (new_width / new_height > 1) ^ (width / height > 1) and rotation == 0: 46 | video = video.rotate(90) 47 | 48 | # Resize the video to have the width and height values specified 49 | video = video.resize((new_width, new_height)) 50 | 51 | # Calculate the original duration of the video 52 | original_duration = video.duration 53 | 54 | # Create a new normalized video file 55 | normalized_video = speedx(video, factor=new_frame_rate/video.fps, final_duration=original_duration) 56 | 57 | # Check if the normalized folder exists and create it if it doesn't 58 | if not os.path.exists(destination_folder_path): 59 | os.mkdir(destination_folder_path) 60 | 61 | # Write the normalized video file to the destination folder 62 | normalized_video.write_videofile(destination_folder_path + '/' + output_filename, codec=encoding_codec, preset=encoding_preset, threads=encoding_threads, fps=new_frame_rate, bitrate=new_bitrate) 63 | 64 | # Close the video file 65 | video.close() 66 | 67 | # Define function to get the video files keyframes (frist_brightness_change, ending_frame) 68 | def get_video_files_keyframes( 69 | source_folder_path: str='./normalized_videos', 70 | brightness_difference_ratio_threshold: int=5, 71 | brightness_difference_threshold: int=10) -> dict: 72 | 73 | print('Executing get_video_files_keyframes()...') 74 | 75 | # Try to get a list of files in the folder 76 | try: 77 | video_files = os.listdir(source_folder_path) 78 | except: 79 | print('Could not get a list of files in the normalized video folder.') 80 | return 81 | 82 | # Create an empty dictionary to save the keyframes 83 | videos_keyframes = {} 84 | 85 | # Loop through the video files 86 | for video_file in video_files: 87 | 88 | # Try to open the video file 89 | try: 90 | video = cv2.VideoCapture(source_folder_path + '/' + video_file) 91 | except: 92 | continue 93 | 94 | print('Analyzing video: ' + video_file) 95 | 96 | # Read the first frame 97 | ret, previous_frame = video.read() 98 | 99 | # Start the frame count 100 | frame_number = 1 101 | 102 | # Set an initial previous difference value high to start 103 | previous_difference = 1000 104 | 105 | # Loop through the frames in the video 106 | while True: 107 | 108 | # Read the next frame 109 | ret, current_frame = video.read() 110 | 111 | # Check if a frame was successfully read 112 | if not ret: 113 | break 114 | 115 | # Increment the frame count 116 | frame_number += 1 117 | 118 | # Convert the previous frame to grayscale 119 | previous_frame_gray = cv2.cvtColor(previous_frame, cv2.COLOR_BGR2GRAY) 120 | 121 | # Convert the current frame to grayscale 122 | current_frame_gray = cv2.cvtColor(current_frame, cv2.COLOR_BGR2GRAY) 123 | 124 | # Calculate the difference between the previous and current frames 125 | difference = cv2.absdiff(previous_frame_gray, current_frame_gray) 126 | 127 | # Calculate the average of the difference 128 | current_difference = cv2.mean(difference)[0] 129 | 130 | # Get the difference ratio between the current and previous frame if previous difference is greater than 0 131 | if previous_difference > 0: 132 | brightness_difference_ratio = current_difference / previous_difference 133 | else: 134 | brightness_difference_ratio = 0 135 | 136 | # Check if the average difference is greater than a threshold 137 | if brightness_difference_ratio > brightness_difference_ratio_threshold and current_difference > brightness_difference_threshold: 138 | videos_keyframes[video_file] = { 139 | 'first_brightness_change': frame_number, 140 | 'ending_frame': video.get(cv2.CAP_PROP_FRAME_COUNT) 141 | } 142 | # Break the loop as the first_brightness_change has been found 143 | break 144 | 145 | # Update the previous frame 146 | previous_frame = current_frame 147 | 148 | # Update the previous difference 149 | previous_difference = current_difference 150 | 151 | # Release the video file 152 | video.release() 153 | 154 | # Print the keyframes 155 | print(videos_keyframes) 156 | 157 | # Return the keyframes 158 | return videos_keyframes 159 | 160 | # Define function to synchronize the video files to start at the first_brightness_change and have the same length 161 | def synchronize_normalized_videos( 162 | source_folder_path: str='./normalized_videos', 163 | destination_folder_path: str='./synchronized_videos', 164 | videos_keyframes: dict={}, 165 | source_frame_rate: float=30, 166 | start_offset_seconds: float=0) -> None: 167 | 168 | print('Executing synchronize_normalized_videos()...') 169 | 170 | # Check if the videos_keyframes dictionary is empty 171 | if not videos_keyframes: 172 | print('The videos_keyframes dictionary is empty.') 173 | return 174 | 175 | # Calculate the start frame offset based on the source_frame_rate and the start_offset_seconds variables 176 | start_frame_offset = int(source_frame_rate * start_offset_seconds) 177 | 178 | # Calculate the duration of the videos in frames based on the video with the longest duration from the first_brightness_change keyframe + start_frame_offset 179 | synchronized_duration = min(videos_keyframes[video_key]['ending_frame'] - (videos_keyframes[video_key]['first_brightness_change'] + start_frame_offset) for video_key in videos_keyframes.keys()) 180 | 181 | # Loop through the video files and rewrite them adjusted (synchronized) to the destination folder 182 | for video_file in videos_keyframes.keys(): 183 | 184 | # Try to open the video file 185 | try: 186 | video = cv2.VideoCapture(source_folder_path + '/' + video_file) 187 | except: 188 | print('Could not open video: ' + video_file) 189 | continue 190 | 191 | # Get the video properties 192 | video_fps = video.get(cv2.CAP_PROP_FPS) 193 | video_width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH)) 194 | video_height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)) 195 | 196 | # Set the starting frame 197 | video.set(cv2.CAP_PROP_POS_FRAMES, videos_keyframes[video_file]['first_brightness_change'] + start_frame_offset) 198 | 199 | # Check if the synchronized folder exists and create it if it doesn't 200 | if not os.path.exists(destination_folder_path): 201 | os.makedirs(destination_folder_path) 202 | 203 | # Try to create a VideoWriter object 204 | try: 205 | fourcc = cv2.VideoWriter_fourcc(*'mp4v') 206 | writer = cv2.VideoWriter(destination_folder_path + '/' + 'synchronized_' + video_file[11:], fourcc, video_fps, (video_width, video_height)) 207 | except: 208 | continue 209 | 210 | # Read and write the frames until the synched duration is reached 211 | frame_count = 0 212 | while video.isOpened() and frame_count < synchronized_duration: 213 | 214 | # Read the next frame 215 | ret, frame = video.read() 216 | 217 | # Check if a frame was successfully read 218 | if not ret: 219 | break 220 | 221 | # Write the frame 222 | writer.write(frame) 223 | frame_count += 1 224 | 225 | # Release the video file 226 | video.release() 227 | writer.release() 228 | 229 | def main() -> None: 230 | 231 | # Normalize the video files framerates 232 | normalize_framerates(source_folder_path='./videos', 233 | destination_folder_path='./normalized_videos', 234 | new_frame_rate=30, 235 | new_bitrate='15000k', 236 | new_width=1080, 237 | new_height=1920, 238 | encoding_codec='libx264', 239 | encoding_preset='ultrafast', 240 | encoding_threads=2) 241 | 242 | # Get the keyframes 243 | videos_keyframes = get_video_files_keyframes(source_folder_path='./normalized_videos', 244 | brightness_difference_ratio_threshold=5, 245 | brightness_difference_threshold=20) 246 | 247 | # Adjust the normalized video files to start at the first_brightness_change + start_frame_offset and have the same length 248 | synchronize_normalized_videos(source_folder_path='./normalized_videos', 249 | destination_folder_path='./synchronized_videos', 250 | videos_keyframes=videos_keyframes, 251 | source_frame_rate=30, 252 | start_offset_seconds=0) 253 | 254 | if __name__ == "__main__": 255 | main() 256 | --------------------------------------------------------------------------------