12#include <pxr/usd/usdGeom/mesh.h>
13#include <pxr/usd/usdGeom/primvarsAPI.h>
14#include <pxr/usd/usdShade/material.h>
15#include <pxr/usd/usdShade/materialBindingAPI.h>
16#include <pxr/usd/usdSkel/bindingAPI.h>
74 if ((md->
mode & mod_mode) != mod_mode) {
87 Object *object_eval = context.object;
88 bool needsfree =
false;
91 if (mesh ==
nullptr) {
96 const bool tag_only =
false;
114 mesh = triangulated_mesh;
123 write_mesh(context, mesh, subsurfData);
126 if (prim.IsValid() && object_eval) {
143void USDGenericMeshWriter::write_custom_data(
const Object *
obj,
145 const pxr::UsdGeomMesh &usd_mesh)
192 this->write_uv_data(usd_mesh, iter, active_uvmap_name);
197 this->write_generic_data(mesh, usd_mesh, iter);
205 switch (blender_domain) {
207 return pxr::UsdGeomTokens->faceVarying;
209 return pxr::UsdGeomTokens->vertex;
211 return pxr::UsdGeomTokens->uniform;
219void USDGenericMeshWriter::write_generic_data(
const Mesh *mesh,
220 const pxr::UsdGeomMesh &usd_mesh,
223 const pxr::TfToken pv_name(
230 if (!pv_interp || !pv_type) {
233 "Mesh '%s', Attribute '%s' (domain %d, type %d) cannot be converted to USD",
247 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh);
249 pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type, *pv_interp);
254void USDGenericMeshWriter::write_uv_data(
const pxr::UsdGeomMesh &usd_mesh,
255 const bke::AttributeIter &attr,
256 const StringRef active_uvmap_name)
266 active_uvmap_name == attr.name ?
271 const pxr::TfToken pv_name(
273 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh);
275 pxr::UsdGeomPrimvar pv_uv = pv_api.CreatePrimvar(
276 pv_name, pxr::SdfValueTypeNames->TexCoord2fArray, pxr::UsdGeomTokens->faceVarying);
323 pxr::UsdGeomMesh usd_mesh = pxr::UsdGeomMesh::Define(stage,
usd_path);
329 get_geometry_data(mesh, usd_mesh_data);
331 pxr::UsdAttribute attr_points = usd_mesh.CreatePointsAttr(pxr::VtValue(),
true);
332 pxr::UsdAttribute attr_face_vertex_counts = usd_mesh.CreateFaceVertexCountsAttr(pxr::VtValue(),
334 pxr::UsdAttribute attr_face_vertex_indices = usd_mesh.CreateFaceVertexIndicesAttr(pxr::VtValue(),
337 if (!attr_points.HasValue()) {
340 attr_points.Set(usd_mesh_data.
points, pxr::UsdTimeCode::Default());
341 attr_face_vertex_counts.Set(usd_mesh_data.
face_vertex_counts, pxr::UsdTimeCode::Default());
342 attr_face_vertex_indices.Set(usd_mesh_data.
face_indices, pxr::UsdTimeCode::Default());
349 attr_face_vertex_indices, pxr::VtValue(usd_mesh_data.
face_indices), time);
352 pxr::UsdAttribute attr_crease_lengths = usd_mesh.CreateCreaseLengthsAttr(pxr::VtValue(),
true);
353 pxr::UsdAttribute attr_crease_indices = usd_mesh.CreateCreaseIndicesAttr(pxr::VtValue(),
true);
354 pxr::UsdAttribute attr_crease_sharpness = usd_mesh.CreateCreaseSharpnessesAttr(pxr::VtValue(),
357 if (!attr_crease_lengths.HasValue()) {
358 attr_crease_lengths.Set(usd_mesh_data.
crease_lengths, pxr::UsdTimeCode::Default());
360 attr_crease_sharpness.Set(usd_mesh_data.
crease_sharpnesses, pxr::UsdTimeCode::Default());
364 attr_crease_lengths, pxr::VtValue(usd_mesh_data.
crease_lengths), time);
374 pxr::UsdAttribute attr_corner_indices = usd_mesh.CreateCornerIndicesAttr(pxr::VtValue(),
true);
375 pxr::UsdAttribute attr_corner_sharpnesses = usd_mesh.CreateCornerSharpnessesAttr(
376 pxr::VtValue(),
true);
378 if (!attr_corner_indices.HasValue()) {
379 attr_corner_indices.Set(usd_mesh_data.
corner_indices, pxr::UsdTimeCode::Default());
380 attr_corner_sharpnesses.Set(usd_mesh_data.
corner_sharpnesses, pxr::UsdTimeCode::Default());
384 attr_corner_indices, pxr::VtValue(usd_mesh_data.
corner_indices), time);
389 write_custom_data(
context.object, mesh, usd_mesh);
390 write_surface_velocity(mesh, usd_mesh);
392 const pxr::TfToken subdiv_scheme = get_subdiv_scheme(subsurfData);
398 subdiv_scheme == pxr::UsdGeomTokens->none)
400 write_normals(mesh, usd_mesh);
412 write_subdiv(subdiv_scheme, usd_mesh, subsurfData);
415 assign_materials(context, usd_mesh, usd_mesh_data.
face_groups);
419pxr::TfToken USDGenericMeshWriter::get_subdiv_scheme(
const SubsurfModifierData *subsurfData)
422 pxr::TfToken subdiv_scheme = pxr::UsdGeomTokens->none;
429 subdiv_scheme = pxr::UsdGeomTokens->catmullClark;
437 "USD export: Simple subdivision not supported, exporting subdivided mesh");
441 return subdiv_scheme;
444void USDGenericMeshWriter::write_subdiv(
const pxr::TfToken &subdiv_scheme,
445 const pxr::UsdGeomMesh &usd_mesh,
448 usd_mesh.CreateSubdivisionSchemeAttr().Set(subdiv_scheme);
449 if (subdiv_scheme == pxr::UsdGeomTokens->catmullClark) {
456 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->
all);
459 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->cornersOnly);
462 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->cornersPlus1);
465 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->cornersPlus2);
468 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->boundaries);
471 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->none);
482 usd_mesh.CreateInterpolateBoundaryAttr().Set(pxr::UsdGeomTokens->edgeOnly);
485 usd_mesh.CreateInterpolateBoundaryAttr().Set(pxr::UsdGeomTokens->edgeAndCorner);
496 usd_mesh_data.
points = pxr::VtArray<pxr::GfVec3f>(positions.
begin(), positions.
end());
520 const Span<int> corner_verts = mesh->corner_verts();
535 const float crease = std::clamp(creases[
i], 0.0f, 1.0f);
537 if (crease != 0.0f) {
556 const float crease = std::clamp(creases[
i], 0.0f, 1.0f);
558 if (crease != 0.0f) {
565void USDGenericMeshWriter::get_geometry_data(
const Mesh *mesh, USDMeshData &usd_mesh_data)
573void USDGenericMeshWriter::assign_materials(
const HierarchyContext &context,
574 const pxr::UsdGeomMesh &usd_mesh,
577 if (context.object->totcol == 0) {
584 bool mesh_material_bound =
false;
585 auto mesh_prim = usd_mesh.GetPrim();
586 pxr::UsdShadeMaterialBindingAPI material_binding_api(mesh_prim);
587 for (
int mat_num = 0; mat_num < context.object->totcol; mat_num++) {
589 if (material ==
nullptr) {
594 material_binding_api.Bind(usd_material);
598 usd_mesh.CreateDoubleSidedAttr(
601 mesh_material_bound =
true;
605 if (mesh_material_bound) {
609 pxr::UsdShadeMaterialBindingAPI::Apply(mesh_prim);
613 usd_mesh.CreateDoubleSidedAttr(pxr::VtValue(
true));
616 if (!mesh_material_bound || usd_face_groups.size() < 2) {
625 short material_number = face_group.key;
626 const pxr::VtIntArray &face_indices = face_group.value;
629 if (material ==
nullptr) {
634 pxr::TfToken material_name = usd_material.GetPath().GetNameToken();
636 pxr::UsdGeomSubset usd_face_subset = material_binding_api.CreateMaterialBindSubset(
637 material_name, face_indices);
638 auto subset_prim = usd_face_subset.GetPrim();
639 auto subset_material_api = pxr::UsdShadeMaterialBindingAPI(subset_prim);
640 subset_material_api.Bind(usd_material);
642 pxr::UsdShadeMaterialBindingAPI::Apply(subset_prim);
646void USDGenericMeshWriter::write_normals(
const Mesh *mesh, pxr::UsdGeomMesh &usd_mesh)
650 pxr::VtVec3fArray loop_normals;
653 MutableSpan dst_normals(
reinterpret_cast<float3 *
>(loop_normals.data()), loop_normals.size());
655 switch (mesh->normals_domain()) {
661 const OffsetIndices
faces = mesh->faces();
662 const Span<float3> face_normals = mesh->face_normals();
663 for (
const int i :
faces.index_range()) {
664 dst_normals.slice(
faces[
i]).fill(face_normals[
i]);
674 pxr::UsdAttribute attr_normals = usd_mesh.CreateNormalsAttr(pxr::VtValue(),
true);
675 if (!attr_normals.HasValue()) {
676 attr_normals.Set(loop_normals, pxr::UsdTimeCode::Default());
679 usd_mesh.SetNormalsInterpolation(pxr::UsdGeomTokens->faceVarying);
682void USDGenericMeshWriter::write_surface_velocity(
const Mesh *mesh,
683 const pxr::UsdGeomMesh &usd_mesh)
689 if (velocity.is_empty()) {
694 Span<pxr::GfVec3f>
data = velocity.cast<pxr::GfVec3f>();
695 pxr::VtVec3fArray usd_velocities;
696 usd_velocities.assign(
data.begin(),
data.end());
699 pxr::UsdAttribute attr_vel = usd_mesh.CreateVelocitiesAttr(pxr::VtValue(),
true);
700 if (!attr_vel.HasValue()) {
701 attr_vel.Set(usd_velocities, pxr::UsdTimeCode::Default());
714 write_skinned_mesh_ =
false;
715 write_blend_shapes_ =
false;
721 write_skinned_mesh_ =
params.export_armatures &&
734 if (!mesh_prim.IsValid()) {
736 "%s: couldn't get valid mesh prim for mesh %s",
742 pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(mesh_prim);
746 "Couldn't apply UsdSkelBindingAPI to mesh prim %s",
756 "Couldn't get armature modifier object for skinned mesh %s",
767 "No armature bones for skinned mesh %s",
772 bool needsfree =
false;
775 if (mesh ==
nullptr) {
800 if (!mesh_prim.IsValid()) {
802 "Couldn't get valid mesh prim for mesh %s",
803 mesh_prim.GetPath().GetAsString().c_str());
821 if (write_blend_shapes_) {
829 if (write_skinned_mesh_) {
833 if (write_blend_shapes_) {
841 if (write_blend_shapes_) {
848 if (write_skinned_mesh_) {
877 if (!mesh_prim.IsValid()) {
879 "Couldn't get valid mesh prim for mesh %s",
889 pxr::UsdAttribute temp_weights_attr = pxr::UsdGeomPrimvarsAPI(mesh_prim).CreatePrimvar(
892 if (!temp_weights_attr) {
894 "Couldn't create primvar %s on prim %s",
896 mesh_prim.GetPath().GetAsString().c_str());
900 temp_weights_attr.Set(weights, time);
CustomData interface, see also DNA_customdata_types.h.
const char * CustomData_get_render_layer_name(const CustomData *data, eCustomDataType type)
void BKE_id_free(Main *bmain, void *idv)
const char * BKE_id_name(const ID &id)
General operations, lookup, etc. for materials.
Material * BKE_object_material_get(Object *ob, short act)
Mesh * BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings)
BMesh * BKE_mesh_to_bmesh_ex(const Mesh *mesh, const BMeshCreateParams *create_params, const BMeshFromMeshParams *convert_params)
void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh)
General operations, lookup, etc. for blender objects.
const Mesh * BKE_object_get_pre_modified_mesh(const Object *object)
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert_msg(a, msg)
#define CLOG_WARN(clg_ref,...)
@ SUBSURF_TYPE_CATMULL_CLARK
@ SUBSURF_BOUNDARY_SMOOTH_ALL
@ SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS
struct SubsurfModifierData SubsurfModifierData
@ SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS
@ SUBSURF_UV_SMOOTH_PRESERVE_CORNERS
@ SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES
@ SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE
BMesh const char void * data
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
void BM_mesh_triangulate(BMesh *bm, const int quad_method, const int ngon_method, const int min_vertices, const bool tag_only, BMOperator *op, BMOpSlot *slot_facemap_out, BMOpSlot *slot_facemap_double_out)
MapItem< short, pxr::VtArray< int > > Item
Value & lookup_or_add_default(const Key &key)
constexpr const T * end() const
constexpr IndexRange index_range() const
constexpr const T * begin() const
constexpr int64_t rfind(char c, int64_t pos=INT64_MAX) const
constexpr const char * c_str() const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader get() const
pxr::UsdShadeMaterial ensure_usd_material(const HierarchyContext &context, Material *material) const
bool frame_has_been_written_
void author_extent(const pxr::UsdGeomBoundable &boundable, const pxr::UsdTimeCode time)
const pxr::SdfPath & usd_path() const
ReportList * reports() const
pxr::UsdTimeCode get_export_time_code() const
pxr::UsdUtilsSparseValueWriter usd_value_writer_
USDAbstractWriter(const USDExporterContext &usd_export_context)
void write_id_properties(const pxr::UsdPrim &prim, const ID &id, pxr::UsdTimeCode=pxr::UsdTimeCode::Default()) const
void write_visibility(const HierarchyContext &context, const pxr::UsdTimeCode time, const pxr::UsdGeomImageable &usd_geometry)
const USDExporterContext usd_export_context_
USDGenericMeshWriter(const USDExporterContext &ctx)
void do_write(HierarchyContext &context) override
bool is_supported(const HierarchyContext *context) const override
virtual Mesh * get_export_mesh(Object *object_eval, bool &r_needsfree)=0
virtual void free_export_mesh(Mesh *mesh)
void do_write(HierarchyContext &context) override
USDMeshWriter(const USDExporterContext &ctx)
void add_shape_key_weights_sample(const Object *obj)
void init_skinned_mesh(const HierarchyContext &context)
void init_blend_shapes(const HierarchyContext &context)
Mesh * get_export_mesh(Object *object_eval, bool &r_needsfree) override
void set_skel_export_flags(const HierarchyContext &context)
bool all(VecOp< bool, D >) RET
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
BLI_INLINE float crease_to_sharpness(float crease)
bool attribute_name_is_anonymous(const StringRef name)
int context(const bContext *C, const char *member, bContextDataResult *result)
static void get_loops_polys(const Mesh *mesh, USDMeshData &usd_mesh_data)
static const SubsurfModifierData * get_last_subdiv_modifier(eEvaluationMode eval_mode, Object *obj)
static void get_vert_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
Map< short, pxr::VtArray< int > > MaterialFaceGroups
void copy_blender_attribute_to_primvar(const GVArray &attribute, const bke::AttrType data_type, const pxr::UsdTimeCode time, const pxr::UsdGeomPrimvar &primvar, pxr::UsdUtilsSparseValueWriter &value_writer)
void get_armature_bone_names(const Object *ob_arm, const bool use_deform, Vector< StringRef > &r_names)
void export_deform_verts(const Mesh *mesh, const pxr::UsdSkelBindingAPI &skel_api, const Span< StringRef > bone_names)
std::optional< pxr::SdfValueTypeName > convert_blender_type_to_usd(const bke::AttrType blender_type, bool use_color3f_type)
void copy_blender_buffer_to_primvar(const VArray< BlenderT > &buffer, const pxr::UsdTimeCode time, const pxr::UsdGeomPrimvar &primvar, pxr::UsdUtilsSparseValueWriter &value_writer)
static void get_positions(const Mesh *mesh, USDMeshData &usd_mesh_data)
bool is_armature_modifier_bone_name(const Object &obj, const StringRefNull name, const Depsgraph *depsgraph)
static std::optional< pxr::TfToken > convert_blender_domain_to_usd(const bke::AttrDomain blender_domain, bool is_bezier)
void create_blend_shapes(pxr::UsdStageRefPtr stage, const Object *obj, const pxr::UsdPrim &mesh_prim, bool allow_unicode)
const Key * get_mesh_shape_key(const Object *obj)
std::string make_safe_name(const StringRef name, bool allow_unicode)
static void get_edge_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
pxr::TfToken TempBlendShapeWeightsPrimvarName
const Object * get_armature_modifier_obj(const Object &obj, const Depsgraph *depsgraph)
pxr::VtFloatArray get_blendshape_weights(const Key *key)
bool can_export_skinned_mesh(const Object &obj, const Depsgraph *depsgraph)
Mesh * get_shape_key_basis_mesh(Object *obj)
bool is_mesh_with_shape_keys(const Object *obj)
void copy_group_sizes(OffsetIndices< int > offsets, const IndexMask &mask, MutableSpan< int > sizes)
VecBase< float, 2 > float2
VecBase< float, 3 > float3
const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal)
char duplicator_visibility_flag
const USDExportParams & export_params
const pxr::SdfPath usd_path
const pxr::UsdStageRefPtr stage
pxr::VtIntArray face_vertex_counts
pxr::VtIntArray crease_vertex_indices
pxr::VtIntArray face_indices
MaterialFaceGroups face_groups
pxr::VtIntArray crease_lengths
pxr::VtFloatArray corner_sharpnesses
pxr::VtFloatArray crease_sharpnesses
pxr::VtIntArray corner_indices
pxr::VtArray< pxr::GfVec3f > points