- Table of Content
BeeVeeH is a BVH player written in Python. BeeVeeH uses OpenGL to render and controls including camera, playback and styling are available. Sculpture mode is for making some "motion sculptures" but with a limitation of 20 sculptures in total (you might want to increase it here if you have a powerful graphic card). BeeVeeH is available for all platforms and pre-built binaries could be found at the release page. For Ubuntu users, make sure you install appropriate OpenGL packages (for example, freeGLUT). BeeVeeH haven't been tested on Ubuntu outside VM, and seems to crash on Ubuntu 17.*.
- Python 3.x
- pip (>= 9.0.1, due to the bugs in early pip versions, please make sure the version of pip is 9.0.1 or above by
pip3 --version
)
If you are using macOS, you can skip this. If you are using Ubuntu, please do the following setups.
Install the following packages via apt
:
- libwebkitgtk-dev
- libjpeg-dev
- libtiff-dev
- libgtk2.0-dev
- libsdl1.2-dev
- libgstreamer-plugins-base0.10-dev
- freeglut3
- freeglut3-dev
- libnotify-dev
- libsm-dev
- libgtk-3-dev
- libwebkitgtk-3.0-dev
make init
This process will take a long time to finish on Ubuntu. If you want to speed up, you can try make init-accelerated
to download my prebuilt pip packages (I have not built them for all platforms).
pip install -r requirements.txt -t lib
make test
$env:PYTHONPATH=".\lib"
python -m lib.pytest --ignore=lib
This will run the tests including playing a short sample BVH file.
make run
python -m main
This is the launch the main entry of BeeVeeH.
or,
make dist
$env:PYTHONPATH=""
pip install PyInstaller==3.3
PyInstaller BeeVeeH.spec
This will generate the packed BeeVeeH inside the ./dist
directory.
You might find BeeVeeH's classes BVHNode
and BVHChannel
useful for parsing and world coordinate extraction.
import BeeVeeH.bvh_helper as BVH
file_path = 'tests/bvh_files/0007_Cartwheel001.bvh'
root, frames, frame_time = BVH.load(file_path)
print('number of frame = %d' % len(frames))
# "number of frame = 2111"
root.load_frame(frames[4])
root.apply_transformation()
print(root.str(show_coordinates=True))
# Node(Hips), offset(0.0, 0.0, 0.0)
# World coordinates: (18.94, 35.04, -9.44)
# Channels:
# Channel(Xposition) = 18.9393
# Channel(Yposition) = 35.0369
# Channel(Zposition) = -9.444
# Channel(Xrotation) = 34.5666
# Channel(Yrotation) = 71.8402
# Channel(Zrotation) = -35.4585
# Node(LeftUpLeg), offset(3.31716, 0.0, 0.0)
# World coordinates: (19.78, 34.91, -12.65)
# Channels:
# Channel(Xrotation) = -5.7958
# Channel(Yrotation) = 9.0163
# Channel(Zrotation) = -0.8796
# Node(LeftLeg), offset(0.0, -16.62131, 0.0)
# World coordinates: (18.36, 18.36, -12.10)
# Channels:
# Channel(Xrotation) = 9.3583
# ...
print(root.search_node('Head').str(show_coordinates=True))
# Node(Head), offset(0.0, 6.84636, 0.0)
# World coordinates: (23.03, 59.50, -10.77)
# Channels:
# Channel(Xrotation) = -5.4518
# Channel(Yrotation) = -2.1447
# Channel(Zrotation) = -0.3752
node = root.children[1]
print('The world coordinates of JOINT %s at frames[4] is (%.2f, %.2f, %.2f)' \
% (node.name, node.coordinates[0],
node.coordinates[1], node.coordinates[2]))
# The world coordinates of JOINT RightUpLeg at frames[4] is (18.10, 35.16, -6.24)
root.frame_distance(frames[0], frames[0])
# 0.0
root.frame_distance(frames[0], frames[1])
# 7.5706251988920146
root.search_node('Head').weight = 100.0
root.frame_distance(frames[0], frames[1])
# 34.952071657201969
BVH.loads()
will parse a string (in BVH format) and return the root node, frames and time between two frames. Each frame is one sample of motion data in the form of a float list. The float numbers appear in the order of the channels.
BVH.load()
will parse a BVH file and return the root node, frames and time between two frames. Refer toBVH.loads
for more details.
the name of the node.
the list of children nodes.
the list of channels. Accessing
channel.value
requires callingBVH.BVHNode.load_frame()
first.
the offsets, in the form of [x, y, z].
the world coordinates, with shape=(3, 1). Accessing it requires calling
BVH.BVHNode.load_frame()
andBVH.BVHNode.apply_transformation()
first.
the weight for frame distance calculation.
Constructor.
search_node
searches node recursively by name, returnsNone
if not found.
load_frame()
assigns a frame. It will map the motion data to each channel. You can get the list of "frame_data_array" fromBVH.load()
orBVH.loads()
.
apply_transformation()
starts the calculation of world coordinates. Call this method on the root BVHNode only (no parameter needed).
str()
returns a readable string containing information about the node and its childrens. Before settingshow_coordinates=True
, make sure callBVH.BVHNode.load_frame()
andBVH.BVHNode.apply_transformation()
first.
frame_distance
calculates the Euclidean distances of all joints between two frames, and returns the weighted sum.
the name of the channel.
the value of the channel, in degree when the channel represents a rotation. Accessing it requires calling
BVH.BVHNode.load_frame()
first.
Constructor.
set_value()
is the setter forvalue
.
matrix()
returns the transformation matrix of the channel.
str()
returns a readable string containing information about the channel.