Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 2 additions & 26 deletions momentum/io/character_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,23 +155,14 @@ void saveCharacter(
filename.string());

if (format == CharacterFormat::Gltf) {
// Convert FileSaveOptions to GltfOptions
GltfOptions gltfOptions;
gltfOptions.extensions = options.extensions;
gltfOptions.collisions = options.collisions;
gltfOptions.locators = options.locators;
gltfOptions.mesh = options.mesh;
gltfOptions.blendShapes = options.blendShapes;

saveGltfCharacter(
filename,
character,
fps,
{character.parameterTransform.name, motion},
{},
markerSequence,
options.gltfFileFormat,
gltfOptions);
options);
} else if (format == CharacterFormat::Fbx) {
// Save as FBX
saveFbx(
Expand Down Expand Up @@ -206,22 +197,7 @@ void saveCharacter(
filename.string());

if (format == CharacterFormat::Gltf) {
// Convert FileSaveOptions to GltfOptions
GltfOptions gltfOptions;
gltfOptions.extensions = options.extensions;
gltfOptions.collisions = options.collisions;
gltfOptions.locators = options.locators;
gltfOptions.mesh = options.mesh;
gltfOptions.blendShapes = options.blendShapes;

saveGltfCharacter(
filename,
character,
fps,
skeletonStates,
markerSequence,
options.gltfFileFormat,
gltfOptions);
saveGltfCharacter(filename, character, fps, skeletonStates, markerSequence, options);
} else if (format == CharacterFormat::Fbx) {
// Save as FBX
saveFbxWithSkeletonStates(
Expand Down
16 changes: 1 addition & 15 deletions momentum/io/file_save_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,9 @@ enum class GltfFileFormat {
Ascii = 2, // ASCII format (generally .gltf)
};

/// Options for GLTF file export
struct GltfOptions {
/// Include GLTF extensions in the output.
bool extensions = true;
/// Include collision geometry in the output.
bool collisions = true;
/// Include locators in the output.
bool locators = true;
/// Include mesh geometry in the output.
bool mesh = true;
/// Include blend shapes in the output.
bool blendShapes = true;
};

// ============================================================================
// FBX Coordinate System Options
// =====================================================================
// ============================================================================

/// Specifies which canonical axis represents up in the system (typically Y or Z).
/// Maps to fbxsdk::FbxAxisSystem::EUpVector
Expand Down
2 changes: 1 addition & 1 deletion momentum/io/gltf/gltf_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,7 @@ void GltfBuilder::addCharacter(
const Character& character,
const Vector3f& positionOffset /*= Vector3f::Zero()*/,
const Quaternionf& rotationOffset /*= Quaternionf::Identity()*/,
const GltfOptions& options) {
const FileSaveOptions& options) {
if (impl_->characterData.find(character.name) != impl_->characterData.end()) {
// Character already exist. Doesn't allow character with the same name to be saved.
// #TODO: proper warning
Expand Down
2 changes: 1 addition & 1 deletion momentum/io/gltf/gltf_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class GltfBuilder final {
const Character& character,
const Vector3f& positionOffset = Vector3f::Zero(),
const Quaternionf& rotationOffset = Quaternionf::Identity(),
const GltfOptions& options = GltfOptions());
const FileSaveOptions& options = FileSaveOptions());

/// Add a static mesh, such as an environment or a target scan
void addMesh(const Mesh& mesh, const std::string& name, bool addColor = false);
Expand Down
30 changes: 13 additions & 17 deletions momentum/io/gltf/gltf_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ addMesh(const fx::gltf::Document& model, const fx::gltf::Primitive& primitive, M
auto fidxDense = copyAccessorBuffer<uint32_t>(model, extension.at("texfaces"));
MT_CHECK(fidxDense.size() % 3 == 0, "{} % 3 = {}", fidxDense.size(), fidxDense.size() % 3);
texfaces.resize(fidxDense.size() / 3);
if (fidxDense.size() > 0) {
if (!fidxDense.empty()) {
std::copy_n(fidxDense.data(), fidxDense.size(), &texfaces[0][0]);
}
} else {
Expand Down Expand Up @@ -991,7 +991,7 @@ fx::gltf::Document makeCharacterDocument(
std::span<const SkeletonState> skeletonStates,
std::span<const std::vector<Marker>> markerSequence,
bool embedResource,
const GltfOptions& options) {
const FileSaveOptions& options) {
GltfBuilder fileBuilder;

const auto kCharacterIsEmpty = character.skeleton.joints.empty() && character.mesh == nullptr;
Expand Down Expand Up @@ -1226,7 +1226,7 @@ fx::gltf::Document makeCharacterDocument(
const IdentityParameters& offsets,
std::span<const std::vector<Marker>> markerSequence,
bool embedResource,
const GltfOptions& options) {
const FileSaveOptions& options) {
GltfBuilder fileBuilder;
const auto kCharacterIsEmpty = character.skeleton.joints.empty() && character.mesh == nullptr;
if (!kCharacterIsEmpty) {
Expand Down Expand Up @@ -1293,14 +1293,14 @@ MarkerSequence loadMarkerSequence(const filesystem::path& filename) {
positions.size());

// resize the output array if necessary
const size_t length = static_cast<size_t>(timestamps.back() * fps + 0.5f) + 1;
const size_t length = static_cast<size_t>(std::lround(timestamps.back() * fps)) + 1;
if (length > result.frames.size()) {
result.frames.resize(length);
}

// go over all data and enter into the output array
for (size_t i = 0; i < timestamps.size(); i++) {
const size_t index = static_cast<size_t>(timestamps[i] * fps + 0.5f);
const size_t index = static_cast<size_t>(std::lround(timestamps[i] * fps));
result.frames[index].emplace_back();
auto& marker = result.frames[index].back();

Expand All @@ -1321,14 +1321,12 @@ void saveGltfCharacter(
const MotionParameters& motion,
const IdentityParameters& offsets,
std::span<const std::vector<Marker>> markerSequence,
const GltfFileFormat fileFormat,
const GltfOptions& options) {
constexpr auto kEmbedResources = false; // Don't embed resource for saving glb
// create new model
const FileSaveOptions& options) {
constexpr auto kEmbedResources = false;
fx::gltf::Document model = makeCharacterDocument(
character, fps, motion, offsets, markerSequence, kEmbedResources, options);

GltfBuilder::save(model, filename, fileFormat, kEmbedResources);
GltfBuilder::save(model, filename, options.gltfFileFormat, kEmbedResources);
}

void saveGltfCharacter(
Expand All @@ -1337,14 +1335,12 @@ void saveGltfCharacter(
const float fps,
std::span<const SkeletonState> skeletonStates,
std::span<const std::vector<Marker>> markerSequence,
const GltfFileFormat fileFormat,
const GltfOptions& options) {
constexpr auto kEmbedResources = false; // Don't embed resource for saving glb
// create new model
const FileSaveOptions& options) {
constexpr auto kEmbedResources = false;
fx::gltf::Document model = ::makeCharacterDocument(
character, fps, skeletonStates, markerSequence, kEmbedResources, options);

GltfBuilder::save(model, filename, fileFormat, kEmbedResources);
GltfBuilder::save(model, filename, options.gltfFileFormat, kEmbedResources);
}

std::vector<std::byte> saveCharacterToBytes(
Expand All @@ -1353,8 +1349,8 @@ std::vector<std::byte> saveCharacterToBytes(
const MotionParameters& motion,
const IdentityParameters& offsets,
std::span<const std::vector<Marker>> markerSequence,
const GltfOptions& options) {
constexpr auto kEmbedResources = false; // Don't embed resource for saving glb
const FileSaveOptions& options) {
constexpr auto kEmbedResources = false;
fx::gltf::Document model = makeCharacterDocument(
character, fps, motion, offsets, markerSequence, kEmbedResources, options);

Expand Down
14 changes: 8 additions & 6 deletions momentum/io/gltf/gltf_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,43 +98,45 @@ fx::gltf::Document makeCharacterDocument(
const IdentityParameters& offsets = {},
std::span<const std::vector<Marker>> markerSequence = {},
bool embedResource = true,
const GltfOptions& options = GltfOptions());
const FileSaveOptions& options = FileSaveOptions());

/// Saves character motion to a glb file.
///
/// @param[in] motion The model parameters representing the motion of the character (numModelParams,
/// numFrames)
/// @param[in] offsets Offset values per joint capturing the skeleton bone lengths using translation
/// and scale offset (7*numJoints, 1)
/// @param[in] options Optional file save options for controlling output (default:
/// FileSaveOptions{}).
void saveGltfCharacter(
const filesystem::path& filename,
const Character& character,
float fps = 120.0f,
const MotionParameters& motion = {},
const IdentityParameters& offsets = {},
std::span<const std::vector<Marker>> markerSequence = {},
GltfFileFormat fileFormat = GltfFileFormat::Auto,
const GltfOptions& options = GltfOptions());
const FileSaveOptions& options = FileSaveOptions());

/// Saves character skeleton states to a glb file.
///
/// @param[in] skeletonStates The skeleton states for each frame of the motion sequence (numFrames,
/// numJoints, 8)
/// @param[in] options Optional file save options for controlling output (default:
/// FileSaveOptions{}).
void saveGltfCharacter(
const filesystem::path& filename,
const Character& character,
float fps,
std::span<const SkeletonState> skeletonStates,
std::span<const std::vector<Marker>> markerSequence = {},
GltfFileFormat fileFormat = GltfFileFormat::Auto,
const GltfOptions& options = GltfOptions());
const FileSaveOptions& options = FileSaveOptions());

std::vector<std::byte> saveCharacterToBytes(
const Character& character,
float fps = 120.0f,
const MotionParameters& motion = {},
const IdentityParameters& offsets = {},
std::span<const std::vector<Marker>> markerSequence = {},
const GltfOptions& options = GltfOptions());
const FileSaveOptions& options = FileSaveOptions());

} // namespace momentum
6 changes: 4 additions & 2 deletions pymomentum/geometry/character_pybind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,14 +714,15 @@ support the proprietary momentum motion format for storing model parameters in G
:param motion: Pose array in [n_frames x n_parameters]
:param offsets: Offset array in [n_joints x n_parameters_per_joint]
:param markers: Additional marker (3d positions) data in [n_frames][n_markers]
:param options: FileSaveOptions for controlling output (mesh, locators, collisions, etc.)
)",
py::arg("path"),
py::arg("character"),
py::arg("fps") = 120.f,
py::arg("motion") = std::optional<momentum::MotionParameters>{},
py::arg("offsets") = std::optional<const momentum::IdentityParameters>{},
py::arg("markers") = std::optional<const std::vector<std::vector<momentum::Marker>>>{},
py::arg("options") = momentum::GltfOptions{})
py::arg("options") = std::optional<momentum::FileSaveOptions>{})
.def_static(
"save_gltf_from_skel_states",
&saveGLTFCharacterToFileFromSkelStates,
Expand All @@ -733,13 +734,14 @@ support the proprietary momentum motion format for storing model parameters in G
:param fps: Frequency in frames per second
:param skel_states: Skeleton states [n_frames x n_joints x n_parameters_per_joint]
:param markers: Additional marker (3d positions) data in [n_frames][n_markers]
:param options: FileSaveOptions for controlling output (mesh, locators, collisions, etc.)
)",
py::arg("path"),
py::arg("character"),
py::arg("fps"),
py::arg("skel_states"),
py::arg("markers") = std::optional<const std::vector<std::vector<momentum::Marker>>>{},
py::arg("options") = momentum::GltfOptions{})
py::arg("options") = std::optional<momentum::FileSaveOptions>{})
.def_static(
"save_fbx",
&saveFBXCharacterToFile,
Expand Down
86 changes: 50 additions & 36 deletions pymomentum/geometry/geometry_pybind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,6 @@ PYBIND11_MODULE(geometry, m) {
"A constraint on model or joint parameters used to enforce realistic poses. "
"Supports various limit types including min/max bounds, linear relationships, "
"ellipsoid constraints, and half-plane constraints.");
auto gltfOptionsClass =
py::class_<mm::GltfOptions>(m, "GltfOptions", "Storage options for Gltf export.");
auto fileSaveOptionsClass = py::class_<mm::FileSaveOptions>(
m,
"FileSaveOptions",
Expand All @@ -197,31 +195,6 @@ PYBIND11_MODULE(geometry, m) {
"multiple function parameters. Format-specific options (e.g., FBX coordinate "
"system, GLTF extensions) are included but only used by their respective formats.");

gltfOptionsClass.def(py::init<>())
.def(
py::init<bool, bool, bool, bool, bool>(),
py::arg("extensions") = true,
py::arg("collisions") = true,
py::arg("locators") = true,
py::arg("mesh") = true,
py::arg("blendShapes") = true)
.def(
"__repr__",
[](const mm::GltfOptions& self) {
return fmt::format(
"GltfData(extensions={}, collisions={}, locators={}, mesh={}, blendShapes={})",
self.extensions,
self.collisions,
self.locators,
self.mesh,
self.blendShapes);
})
.def_readwrite("extensions", &mm::GltfOptions::extensions, "Save momentum extensions")
.def_readwrite("collisions", &mm::GltfOptions::collisions, "Save collision geometry")
.def_readwrite("locators", &mm::GltfOptions::locators, "Save locator data")
.def_readwrite("mesh", &mm::GltfOptions::mesh, "Save mesh data")
.def_readwrite("blend_shapes", &mm::GltfOptions::blendShapes, "Save blend shape data");

blendShapeClass
.def_property_readonly(
"base_shape",
Expand Down Expand Up @@ -493,19 +466,19 @@ The resulting tensors are as follows:
const momentum::FbxCoordSystem coordSystem) {
return momentum::FbxCoordSystemInfo{upVector, frontVector, coordSystem};
}),
py::arg("upVector"),
py::arg("frontVector"),
py::arg("coordSystem"))
py::arg("up_vector"),
py::arg("front_vector"),
py::arg("coord_system"))
.def_property_readonly(
"upVector",
"up_vector",
[](const mm::FbxCoordSystemInfo& coordSystemInfo) { return coordSystemInfo.upVector; },
"Returns the up vector.")
.def_property_readonly(
"frontVector",
"front_vector",
[](const mm::FbxCoordSystemInfo& coordSystemInfo) { return coordSystemInfo.frontVector; },
"Returns the front vector.")
.def_property_readonly(
"coordSystem",
"coord_system",
[](const mm::FbxCoordSystemInfo& coordSystemInfo) { return coordSystemInfo.coordSystem; },
"Returns the coordinate system.")
.def("__repr__", [](const mm::FbxCoordSystemInfo& info) {
Expand Down Expand Up @@ -565,7 +538,48 @@ The resulting tensors are as follows:
// - GLTF-specific: extensions, gltfFileFormat
// =====================================================

fileSaveOptionsClass.def(py::init<>())
fileSaveOptionsClass
.def(
py::init([](bool mesh,
bool locators,
bool collisions,
bool blendShapes,
bool permissive,
mm::FbxCoordSystemInfo coordSystemInfo,
std::string_view fbxNamespace,
bool extensions,
mm::GltfFileFormat gltfFileFormat) {
mm::FileSaveOptions options;
options.mesh = mesh;
options.locators = locators;
options.collisions = collisions;
options.blendShapes = blendShapes;
options.permissive = permissive;
options.coordSystemInfo = coordSystemInfo;
options.fbxNamespace = fbxNamespace;
options.extensions = extensions;
options.gltfFileFormat = gltfFileFormat;
return options;
}),
py::arg("mesh") = true,
py::arg("locators") = true,
py::arg("collisions") = true,
py::arg("blend_shapes") = true,
py::arg("permissive") = false,
py::arg("coord_system_info") = mm::FbxCoordSystemInfo{},
py::arg("fbx_namespace") = "",
py::arg("extensions") = true,
py::arg("gltf_file_format") = mm::GltfFileFormat::Auto,
"Create FileSaveOptions with custom settings.\n\n"
":param mesh: Include mesh geometry in the output (default: True)\n"
":param locators: Include locators in the output (default: True)\n"
":param collisions: Include collision geometry in the output (default: True)\n"
":param blend_shapes: Include blend shapes in the output (default: True)\n"
":param permissive: Permissive mode - allow saving mesh-only characters without skin weights (default: False)\n"
":param coord_system_info: FBX coordinate system configuration (default: Maya Y-up)\n"
":param fbx_namespace: Optional namespace prefix for FBX node names (default: empty)\n"
":param extensions: Enable GLTF extensions (default: True)\n"
":param gltf_file_format: GLTF file format selection (default: Auto)\n")
.def_readwrite(
"mesh", &mm::FileSaveOptions::mesh, "Include mesh geometry in the output (default: true)")
.def_readwrite(
Expand Down Expand Up @@ -667,8 +681,8 @@ The resulting tensors are as follows:
coordSystemStr);

return fmt::format(
"FileSaveOptions(mesh={}, locators={}, collisions={}, blendShapes={}, permissive={}, "
"coord_system_info={}, fbx_namespace='{}', extensions={}, gltfFileFormat={})",
"FileSaveOptions(mesh={}, locators={}, collisions={}, blend_shapes={}, permissive={}, "
"coord_system_info={}, fbx_namespace='{}', extensions={}, gltf_file_format={})",
opts.mesh,
opts.locators,
opts.collisions,
Expand Down
Loading
Loading