I/O¶
io
¶
BVH file I/O — reading and writing .bvh motion capture files.
Public functions:
- :func:
read_bvh_file— parse a.bvhfile into a :class:~pybvh.bvh.Bvh - :func:
write_bvh_file— write a :class:~pybvh.bvh.Bvhto a.bvhfile
read_bvh_file(filepath: str | Path, world_up: str = 'auto', warn_on_world_up_disagreement: bool = True, lr_mapping: dict[str, str] | None = None) -> Bvh
¶
Parse a BVH motion capture file and return a Bvh object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filepath
|
str or Path
|
Path to the BVH file. |
required |
world_up
|
str
|
World vertical axis. |
'auto'
|
warn_on_world_up_disagreement
|
bool
|
If True (default) and |
True
|
lr_mapping
|
dict or None
|
Explicit left/right joint pair mapping
( |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
bvh |
Bvh
|
A Bvh object containing the skeleton hierarchy, root positions, joint angles, and frame time. |
Notes
BVH files store joint angles in degrees; pybvh holds them in radians
on :attr:Bvh.joint_angles. This function converts on read;
:func:write_bvh_file converts back on write.
Three things the reader normalizes rather than preserving verbatim, so a round-trip is lossless in motion but not byte-for-byte:
- Frame time is snapped to an exact
1 / Nwhen the file's value is within 0.01% of one — salvaging the ubiquitous0.033333truncation, at the cost ofbvh.frame_timenot being the literal file value. Non-integer rates (23.976 fps) are left alone, and no other parser does this snap. - Root channels are reordered to position-first. A file declaring rotations before positions parses correctly but writes back in pybvh's canonical order.
- Offsets and motion values are written at 6 decimal places (frame time at full precision), so re-reading a written file quantizes at ~1e-6 in the file's own units.
Values pybvh infers or you set — world_up, lr_mapping — have
nowhere to live in the BVH format and are lost on write; re-apply
them after reading.
write_bvh_file(bvh: Bvh, filepath: str | Path, verbose: bool = False, overwrite: bool = True) -> None
¶
Write a Bvh object to a .bvh file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
bvh
|
Bvh
|
The motion data to write. |
required |
filepath
|
str or Path
|
Destination file path. Must have a |
required |
verbose
|
bool
|
If True, print a one-line confirmation to stdout on success.
Default |
False
|
overwrite
|
bool
|
If True (default), replace an existing file at |
True
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the file extension is not |
FileNotFoundError
|
If the parent directory does not exist. |
FileExistsError
|
If |
Notes
pybvh stores joint angles in radians, but the BVH format requires degrees; this function converts on write.
Offsets and motion values are written with 6 decimal places, the de
facto BVH convention (and what most DCC tools emit) — motion data
re-read from a written file is therefore quantized at ~1e-6 in the
skeleton's length unit and in degrees. Frame Time is the
exception: it is written at full precision (%.10g), because a
truncated frame time compounds across every frame of a resample
while a truncated coordinate does not.
The BVH format carries no place for world_up, lr_mapping, or
source_path; those are lost on write and re-inferred on read.
Root channels are always written position-first, whatever order the
source file declared.