c6d61e8586
New functionality to export armatures and shape keys as USD skeletons and blend shapes. Added "Armature", "Only Deform Bones" and "Shape Key" USD export options. Added USDArmatureWriter class. Extended USDMeshWriter to write skinned meshes for binding with skeletons and 'neutral' meshes with blend shape targets. Specifically, when exporting an armature, a skinned mesh is written in its pre-modified rest position. When exporting to blend shapes, a mesh with shape keys is saved with its vertices in the shape key basis shape position. Added USDHierarchyIterator::process_usd_skel() function to finish processing skeleton and blend shape export after the writer instances completed writing. This is necessary because some of the export operations require processing multiple prims at once. Extended USDTransformWriter::do_write() to write transforms sparsely, to avoid saving redundant transform values when exporting armatures. Added a create_skel_roots() function, called on the stage at the end of the export. This function attempts to ensure that skinned prims and skeletons are encapsulated under SkelRoot primitives, which is required in USD for correct skinning behavior. When exporting blend shape animations for multiple meshes bound to a single skeleton, we need to merge the blend shape time samples of the different meshes into a single animation primitive at the end of the export. This requires some tricky book keeping, where the weight time samples for a given mesh are initially saved by the mesh writer to a temporary attribute on the mesh and are later copied to the animation primitive as one of the final steps. When writing blend shapes and skinned meshes, the pre-modified mesh is exported. This is to ensure that the number of blend shape offsets matches the number of points, and so that the skinned mesh is saved in its rest position. Because the pre-modified mesh must be exported, modifiers in addition to Armature modifiers will not be applied. This still allows the round trip UsdSkel -> Blender -> UsdSkel, but some additional setup might be required to export to UsdSkel when there are multiple modifiers (for example, applying mirroring modifiers that precede the armature modifier). Exporting bendy bones or absolute shape keys isn't currently supported. Co-authored-by: Charles Wardlaw <charleswardlaw@noreply.localhost> Pull Request: https://projects.blender.org/blender/blender/pulls/111931
97 lines
3.4 KiB
C++
97 lines
3.4 KiB
C++
/* SPDX-FileCopyrightText: 2019 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
#pragma once
|
|
|
|
#include "DNA_modifier_types.h"
|
|
#include "usd_writer_abstract.h"
|
|
|
|
#include "BLI_map.hh"
|
|
|
|
#include <pxr/usd/usdGeom/mesh.h>
|
|
|
|
struct Key;
|
|
|
|
namespace blender::bke {
|
|
class AttributeIDRef;
|
|
struct AttributeMetaData;
|
|
} // namespace blender::bke
|
|
|
|
namespace blender::io::usd {
|
|
|
|
struct USDMeshData;
|
|
|
|
/* Writer for USD geometry. Does not assume the object is a mesh object. */
|
|
class USDGenericMeshWriter : public USDAbstractWriter {
|
|
public:
|
|
USDGenericMeshWriter(const USDExporterContext &ctx);
|
|
|
|
protected:
|
|
virtual bool is_supported(const HierarchyContext *context) const override;
|
|
virtual void do_write(HierarchyContext &context) override;
|
|
|
|
virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) = 0;
|
|
virtual void free_export_mesh(Mesh *mesh);
|
|
|
|
private:
|
|
/* Mapping from material slot number to array of face indices with that material. */
|
|
using MaterialFaceGroups = Map<short, pxr::VtIntArray>;
|
|
|
|
void write_mesh(HierarchyContext &context, Mesh *mesh, const SubsurfModifierData *subsurfData);
|
|
pxr::TfToken get_subdiv_scheme(const SubsurfModifierData *subsurfData);
|
|
void write_subdiv(const pxr::TfToken &subdiv_scheme,
|
|
pxr::UsdGeomMesh &usd_mesh,
|
|
const SubsurfModifierData *subsurfData);
|
|
void get_geometry_data(const Mesh *mesh, struct USDMeshData &usd_mesh_data);
|
|
void assign_materials(const HierarchyContext &context,
|
|
pxr::UsdGeomMesh usd_mesh,
|
|
const MaterialFaceGroups &usd_face_groups);
|
|
void write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
|
|
void write_surface_velocity(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
|
|
|
|
void write_custom_data(const Object *obj, const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
|
|
void write_generic_data(const Mesh *mesh,
|
|
pxr::UsdGeomMesh usd_mesh,
|
|
const bke::AttributeIDRef &attribute_id,
|
|
const bke::AttributeMetaData &meta_data);
|
|
void write_uv_data(const Mesh *mesh,
|
|
pxr::UsdGeomMesh usd_mesh,
|
|
const bke::AttributeIDRef &attribute_id,
|
|
const char *active_set_name);
|
|
void write_color_data(const Mesh *mesh,
|
|
pxr::UsdGeomMesh usd_mesh,
|
|
const bke::AttributeIDRef &attribute_id,
|
|
const bke::AttributeMetaData &meta_data);
|
|
|
|
template<typename BlenderT, typename USDT>
|
|
void copy_blender_buffer_to_prim(const Span<BlenderT> buffer,
|
|
const pxr::UsdTimeCode timecode,
|
|
pxr::UsdGeomPrimvar attribute_pv);
|
|
};
|
|
|
|
class USDMeshWriter : public USDGenericMeshWriter {
|
|
bool write_skinned_mesh_;
|
|
bool write_blend_shapes_;
|
|
|
|
public:
|
|
USDMeshWriter(const USDExporterContext &ctx);
|
|
|
|
protected:
|
|
virtual void do_write(HierarchyContext &context) override;
|
|
|
|
virtual Mesh *get_export_mesh(Object *object_eval, bool &r_needsfree) override;
|
|
|
|
/**
|
|
* Determine whether we should write skinned mesh or blend shape data
|
|
* based on the export parameters and the modifiers enabled on the object.
|
|
*/
|
|
void set_skel_export_flags(const HierarchyContext &context);
|
|
|
|
void init_skinned_mesh(const HierarchyContext &context);
|
|
void init_blend_shapes(const HierarchyContext &context);
|
|
|
|
void add_shape_key_weights_sample(const Object *obj);
|
|
};
|
|
|
|
} // namespace blender::io::usd
|