Skip to content

Commit

Permalink
add fbx (#94)
Browse files Browse the repository at this point in the history
* first version

* working setup

* working hacky setup

* builds both mac and amd

* add final steps for training

* lint

* fix linting
  • Loading branch information
budzianowski authored Oct 3, 2024
1 parent fc6e04d commit fe91ec5
Show file tree
Hide file tree
Showing 9 changed files with 298 additions and 0 deletions.
4 changes: 4 additions & 0 deletions third_party/expressive_humanoid/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
sip-4.19.3.tar.gz
fbx202032_fbxpythonbindings_linux.tar.gz
fbx202032_fbxsdk_linux.tar.gz
CMU_fbx.zip
146 changes: 146 additions & 0 deletions third_party/expressive_humanoid/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# docker build -t fbx_image .
# docker run -it fbx_image
ARG TARGETPLATFORM
FROM --platform=${TARGETPLATFORM:-linux/amd64} ubuntu:20.04 AS base

# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive \
HOME="/home/user" \
FBX_SDK_VERSION="2020.3.2" \
SIP_VERSION="4.19.3" \
PYTHON_VERSION="3.8" \
FBX_SDK_PATH="$HOME/fbx_setup/fbx_sdk" \
FBX_PYTHON_BINDING_PATH="$HOME/fbx_setup/fbx_python_bindings" \
SIP_ROOT="$HOME/fbx_setup/sip" \
FBXSDK_ROOT="$FBX_SDK_PATH" \
SIP_PATH="$SIP_ROOT/sip-$SIP_VERSION" \
PYTHON_EXECUTABLE="/home/user/miniconda/envs/humanoid/bin/python"

# Update and install dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
libxml2-dev \
zlib1g-dev \
wget \
python${PYTHON_VERSION} \
python${PYTHON_VERSION}-dev \
python3-pip \
libssl-dev \
vim \
libcurl4-openssl-dev && \
rm -rf /var/lib/apt/lists/*

# Create necessary directories
RUN mkdir -p $FBX_SDK_PATH $FBX_PYTHON_BINDING_PATH $SIP_ROOT

# Install Miniconda
RUN wget -qO- https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh && \
/bin/bash miniconda.sh -b -p $HOME/miniconda && \
rm miniconda.sh && \
$HOME/miniconda/bin/conda init bash

FROM base AS install_fbx

# Make sure the base environment is activated by default
SHELL ["/bin/bash", "-c"]

# Install packages inside the Conda environment
RUN /bin/bash -c "source ~/.bashrc && \
conda create -n humanoid python=3.8 -y && \
conda activate humanoid && \
conda install -y pytorch==1.10.0 torchvision==0.11.1 torchaudio==0.10.0 cudatoolkit=11.3 -c pytorch && \
conda install -y 'numpy<1.24' && \
conda install -c conda-forge gxx_linux-64=12.1.0 -y && \
pip install pydelatin wandb tqdm opencv-python ipdb pyfqmr flask dill gdown pandas matplotlib ruamel.yaml xlrd scipy"

FROM install_fbx AS base_conda

# Install FBX SDK
WORKDIR $FBX_SDK_PATH
COPY fbx202032_fbxsdk_linux.tar.gz $FBX_SDK_PATH/
RUN tar xzf fbx202032_fbxsdk_linux.tar.gz && \
chmod +x fbx202032_fbxsdk_linux
COPY install_fbx.sh .
RUN chmod +x install_fbx.sh && ./install_fbx.sh

FROM base_conda AS fbx_python_bindings

# Install FBX Python Bindings
WORKDIR $FBX_PYTHON_BINDING_PATH
COPY fbx202032_fbxpythonbindings_linux.tar.gz $FBX_PYTHON_BINDING_PATH/
RUN tar xzf fbx202032_fbxpythonbindings_linux.tar.gz && \
chmod +x fbx202032_fbxpythonbindings_linux
COPY install_fbx_bindings.sh .
RUN chmod +x install_fbx_bindings.sh && ./install_fbx_bindings.sh

FROM fbx_python_bindings AS sip

# Install SIP
WORKDIR $SIP_ROOT
RUN wget "https://sourceforge.net/projects/pyqt/files/sip/sip-${SIP_VERSION}/sip-${SIP_VERSION}.tar.gz/download" -O "sip-${SIP_VERSION}.tar.gz" && \
tar xzf "sip-${SIP_VERSION}.tar.gz" && \
cd sip-${SIP_VERSION} && \
$PYTHON_EXECUTABLE configure.py && \
make && \
make install

ENV SIP_ROOT="$SIP_ROOT/sip-$SIP_VERSION"

FROM sip AS build_fbx

# Build the SDK
WORKDIR $FBX_PYTHON_BINDING_PATH
RUN $PYTHON_EXECUTABLE PythonBindings.py "Python3_x64" buildsip

# Modify the Makefile to fix linking order
WORKDIR $FBX_PYTHON_BINDING_PATH/build/Python38_x64
RUN make clean && \
sed -i 's|\(LIBS = -L[^ ]*\) -lz -lxml2 \([^ ]*\)|\1 \2 -lz -lxml2|' Makefile

# Build and install
RUN make install

# Build the SDK
WORKDIR $FBX_PYTHON_BINDING_PATH
RUN $PYTHON_EXECUTABLE PythonBindings.py "Python3_x64" buildsip

FROM build_fbx AS rebuild_fbx

# Install git
WORKDIR $HOME
RUN apt-get update && apt-get install -y git unzip
RUN git clone https://github.com/Ke-Wang1017/expressive_humanoid.git expressive_humanoid

WORKDIR $HOME/expressive_humanoid/ASE/ase/poselib/data/
COPY CMU_fbx.zip .
RUN mkdir -p cmu_fbx_all && unzip CMU_fbx.zip -d cmu_fbx_all/

WORKDIR $HOME/expressive_humanoid/ASE/ase/poselib/
COPY test_fbx.py .
RUN $PYTHON_EXECUTABLE test_fbx.py && echo "FBX works"

# Set the default command to bash
COPY parse_cmu_mocap_all_2.py $HOME/expressive_humanoid/ASE/ase/poselib/
COPY fbx_importer_all_2.py $HOME/expressive_humanoid/ASE/ase/poselib/

FROM rebuild_fbx AS final

RUN $PYTHON_EXECUTABLE parse_cmu_mocap_all_2.py
RUN $PYTHON_EXECUTABLE fbx_importer_all_2.py
RUN mkdir -p pkl retarget_npy
RUN $PYTHON_EXECUTABLE retarget_motion_stompy_all.py

WORKDIR $HOME/expressive_humanoid/legged_gym/legged_gym/scripts
# Train for 1 iteration and kill the program to have a dummy model to load.
RUN $PYTHON_EXECUTABLE train.py debug --task stompy_view --motion_name motions_debug.yaml --debug

# Run the play script to visualize the motion
RUN $PYTHON_EXECUTABLE play.py debug --task stompy_view --motion_name motions_debug.yaml

RUN $PYTHON_EXECUTABLE train.py 060-40-some_descriptions_of_run --device cuda:0 --entity WANDB_ENTITY
RUN $PYTHON_EXECUTABLE play.py 060-40 --task stompy_mimic --record_video

FROM final AS amp

CMD ["/bin/bash"]
8 changes: 8 additions & 0 deletions third_party/expressive_humanoid/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# This file is kept for experimental purposes. All software contained within complies with their respective licenses.
# The following software is included:
# - Expressive Humanoid (https://github.com/chengxuxin/expressive-humanoid)
# - Expressive Humanoid (https://github.com/Ke-Wang1017/expressive_humanoid)
# - CMU Motion Capture Data
# - ASE
# - FBX SDK
# - SIP
11 changes: 11 additions & 0 deletions third_party/expressive_humanoid/download_assets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
echo "Starting download of CMU_fbx.zip"
aws s3 cp s3://kscale-public/expressive_humanoid/CMU_fbx.zip . &
echo "Starting download of fbx202032_fbxpythonbindings_linux.tar.gz"
aws s3 cp s3://kscale-public/expressive_humanoid/fbx202032_fbxpythonbindings_linux.tar.gz . &
echo "Starting download of fbx202032_fbxsdk_linux.tar.gz"
aws s3 cp s3://kscale-public/expressive_humanoid/fbx202032_fbxsdk_linux.tar.gz . &
echo "Starting download of sip-4.19.3.tar.gz"
aws s3 cp s3://kscale-public/expressive_humanoid/sip-4.19.3.tar.gz . &

wait
echo "All downloads completed"
43 changes: 43 additions & 0 deletions third_party/expressive_humanoid/fbx_importer_all_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""This script converts CMU Motion Capture data from FBX format to NPY format. """
import sys
import os
from tqdm import tqdm
from poselib.skeleton.skeleton3d import SkeletonMotion
import multiprocessing

sys.path.append("/home/user/fbx_setup/fbx_python_bindings/build/Distrib/site-packages/fbx/")

def process_file(i, fbx_file, all_fbx_path):
if fbx_file.endswith(".fbx"):
print(i, fbx_file)
motion = SkeletonMotion.from_fbx(
fbx_file_path=os.path.join(all_fbx_path, fbx_file),
root_joint="Hips",
fps=60
)
motion.to_file(f"data/npy/{fbx_file[:-4]}.npy")

def main():
all_fbx_path = "data/cmu_fbx_all/"
all_fbx_files = sorted(os.listdir(all_fbx_path))

all_fbx_filtered = []
for fbx in all_fbx_files:
npy = fbx.split(".")[0] + ".npy"
target_motion_file = os.path.join(all_fbx_path, "../npy/", npy)
if os.path.exists(target_motion_file):
print("Already exists, skip: ", fbx)
continue
all_fbx_filtered.append(fbx)

print(len(all_fbx_filtered))

for fbx_file in tqdm(all_fbx_filtered):
process_file(None, fbx_file, all_fbx_path)

n_workers = multiprocessing.cpu_count()
with multiprocessing.Pool(n_workers) as pool:
list(tqdm(pool.starmap(process_file, [(i, fbx_file, all_fbx_path) for i, fbx_file in enumerate(all_fbx_filtered)]), total=len(all_fbx_filtered)))

if __name__ == "__main__":
main()
6 changes: 6 additions & 0 deletions third_party/expressive_humanoid/install_fbx.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
./fbx202032_fbxsdk_linux <<EOF
y
yes
y
EOF
6 changes: 6 additions & 0 deletions third_party/expressive_humanoid/install_fbx_bindings.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash
./fbx202032_fbxpythonbindings_linux <<EOF
y
yes
y
EOF
67 changes: 67 additions & 0 deletions third_party/expressive_humanoid/parse_cmu_mocap_all_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import pandas as pd
from ruamel.yaml import YAML

path = "./data/configs/"

def find_entries(word, column):
subset = column[column.str.contains(word, na=False, case=False)]
num_entries = len(subset)
num_unique_entries = subset.nunique()
indices = subset.index.tolist()
unique_entries = subset.unique()
print(f"Found {num_entries} entries containing '{word}', {num_unique_entries} unique entries.")
return num_entries, num_unique_entries, indices, unique_entries

def save_yaml(motion_ids, motion_descriptions, name):
yaml = YAML()
yaml.preserve_quotes = True
motions_data = {"root": "../retarget_npy/"}
for i, motion_id in enumerate(motion_ids):
descrp = motion_descriptions[i].replace("/", ", ").replace("\\", ", ")
motions_data[motion_id] = {
"trim_beg": -1,
"trim_end": -1,
"weight": 1.0,
"description": f"{descrp}",
"difficulty": 4
}
final_structure = {"motions": motions_data}
with open(path + f'motions_autogen_debug_{name}.yaml', 'w') as file:
yaml.dump(final_structure, file)
print('YAML file created with the specified structure.')

file_path = path + "cmu-mocap-index-spreadsheet.xls"
data = pd.read_excel(file_path)
description_column = data.iloc[:, 1]
motion_id_column = data.iloc[:, 0]

forbidden_words = ["ladder", "suitcase", "uneven", "terrain", "stair", "stairway", "stairwell", "clean", "box", "climb", "backflip", "handstand", "sit", "hang"]
target_words = ["walk", "navigate", "basketball", "dance", "punch", "fight", "push", "pull", "throw", "catch", "crawl", "wave", "high five", "hug", "drink", "wash", "signal", "balance", "strech", "leg", "bend", "squat", "traffic", "high-five", "low-five"]

target_results = [find_entries(word, description_column) for word in target_words]

print("\n Searching for forbidden words:")
fbd_indices = []
for word in forbidden_words:
fbd_indices.extend(find_entries(word, description_column)[2])
fbd_indices = list(set(fbd_indices))
print(f"Found {len(fbd_indices)} unique forbidden entries.")

print("\n Filtering forbidden words:")
indices_all = []
for i, result in enumerate(target_results):
indices = result[2]
filtered_indices = [index for index in indices if index not in fbd_indices]
filtered_entries = description_column[filtered_indices]
filtered_unique_entries = list(set(filtered_entries))
print(f"Found {len(filtered_indices)} entries for '{target_words[i]}' after filtering, {len(filtered_unique_entries)} unique entries.")

motion_ids = motion_id_column[filtered_indices]
indices_all.extend(filtered_indices)

if target_words[i] in ["walk", "dance", "basketball", "punch"]:
save_yaml(motion_ids, filtered_entries.tolist(), target_words[i])

indices_all_unique = list(set(indices_all))
motion_ids_all_unique = motion_id_column[indices_all_unique]
save_yaml(motion_ids_all_unique, description_column[indices_all_unique].tolist(), "all_no_run_jump")
7 changes: 7 additions & 0 deletions third_party/expressive_humanoid/test_fbx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import sys
sys.path.append("/home/user/fbx_setup/fbx_python_bindings/build/Distrib/site-packages/fbx/")

import fbx
import FbxCommon

print("All modules imported successfully")

0 comments on commit fe91ec5

Please sign in to comment.