Save and load Motionbuilder FBModelMarker look properties to json.
The save
function dump a list of FBModelMarker
to a json file:
import mobulook
markers = [] # <- List of FBModelMarker to save
mobulook.save("C:/look.json", markers)
The load
function apply the content of a saved json file to markers in scene
with matching names.
mobulook.load("C:/look.json")
Only the FBModelMarker.Name
are saved in the json, namespaces are ommited.
When loading the file, an optional prefix namespace can be applied find the
correct markers in scene.
# Load "look.json" to matching markers under "Character_Ctrl" namespace
mobulook.load("C:/look.json", namespace="Character_Ctrl")
import pyfbsdk
import mobulook
def hierarchy(root): # (pyfbsdk.FBModel) -> Generator[pyfbsdk.FBModel, None, None]
"""Iter through models in hierarchy starting from 'root'."""
root = root or pyfbsdk.FBSystem().SceneRootModel
stack = [root]
while stack:
model = stack.pop()
yield model
stack.extend(model.Children)
# Save all FBModelMarkers in the hierarchy of "MyRootModel"
root = pyfbsdk.FBFindModelByName("MyRootModel")
mobulook.save("C:/output.json", hierarchy(root))
import pyfbsdk
import mobulook
character = pyfbsdk.FBApplication().CurrentCharacter
markers = []
# Body Nodes (FK)
for node_id in pyfbsdk.FBBodyNodeId.values.values():
model = character.GetCtrlRigModel(node_id)
if model:
markers.append(model)
# Effectors
for effector in pyfbsdk.FBEffectorId.values.values():
for effector_set in pyfbsdk.FBEffectorSetID.values.values():
model = character.GetEffectorModel(effector, effector_set)
if model:
markers.append(model)
# Extensions
for extension in character.CharacterExtensions
markers.extend(extension.Components)
mobulook.save("C:/output.json", markers)
Dev environment setup using pyenv and poetry.
Install python 2.7 with pyenv and set it as our local env. Then we tell poetry to use this version to create a venv with the necessary dependencies (mainly pytest).
pyenv install 2.7.18
pyenv local 2.7.18
for /f "tokens=*" %a in ('pyenv exec python -c "import sys; print(sys.executable)"') do poetry env use %a
poetry install
Now that we have a venv compatible with Motionbuilder 2020 (python 2.7.11), we
need to add the site-packages
directory of our poetry venv to PYTHONPATH (to
find pytest) and the mobulook/src
directory (to find our module).
set PYTHONPATH=<PATH_TO_VENV>\Lib\site-packages;%PYTHONPATH%
set PYTHONPATH=<PATH_TO_MOBULOOK>\src;%PYTHONPATH%
We can now run the tests using the mobupy
interpreter.
mobupy -m pytest
We can't use the mobupy interpreter of Motionbuilder 2020, it crashes as soon as you use pyfbsdk.
Instead we can use the main application to run our tests.
Create a python runner script. Note that the path to our test file has to be an
absolute path, the __file__
variable will be undefined in our case.
# runner.py
import pytest
pytest.main(["<PATH_TO_MOBULOOK>/test_mobulook.py", "--capture=sys"])
And execute this runner script from Motionbuilder CLI
motionbuilder.exe <PATH_TO_RUNNER_SCRIPT>
Check the Python Editor Window of Motionbuilder for the results.
This only work with Motionbuilder >= 2022.
Follow the first step of the section above to install a python venv. But instead
of adding to PYTHONPATH in a shell, we can create an .env
file at the root of
our package directory and reference it in the project settings:
mobulook/.env
:
PYTHONPATH=<PATH_TO_VENV>\Lib\site-packages;${PYTHONPATH}
PYTHONPATH=<PATH_TO_MOBULOOK>\src;${PYTHONPATH}
mobulook/.vscode/settings.json
:
{
"python.defaultInterpreterPath": "<PATH_TO_MOBUPY>",
"python.testing.unittestEnabled": false,
"python.testing.pytestEnabled": true,
"python.envFile": "${workspaceFolder}/.env",
}
Now you can run the tests in the Testing tab of VSCode.