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>
77 if ((md->
mode & mod_mode) != mod_mode) {
90 Object *object_eval = context.object;
91 bool needsfree =
false;
94 if (mesh ==
nullptr) {
99 const bool tag_only =
false;
117 mesh = triangulated_mesh;
126 write_mesh(context, mesh, subsurfData);
129 if (prim.IsValid() && object_eval) {
146void USDGenericMeshWriter::write_custom_data(
const Object *
obj,
148 const pxr::UsdGeomMesh &usd_mesh)
195 this->write_uv_data(usd_mesh, iter, active_uvmap_name);
200 this->write_generic_data(mesh, usd_mesh, iter);
208 switch (blender_domain) {
210 return pxr::UsdGeomTokens->faceVarying;
212 return pxr::UsdGeomTokens->vertex;
214 return pxr::UsdGeomTokens->uniform;
222void USDGenericMeshWriter::write_generic_data(
const Mesh *mesh,
223 const pxr::UsdGeomMesh &usd_mesh,
226 const pxr::TfToken pv_name(
233 if (!pv_interp || !pv_type) {
236 "Mesh '%s', Attribute '%s' (domain %d, type %d) cannot be converted to USD",
250 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh);
252 pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type, *pv_interp);
258void USDGenericMeshWriter::write_uv_data(
const pxr::UsdGeomMesh &usd_mesh,
259 const bke::AttributeIter &attr,
260 const StringRef active_uvmap_name)
270 active_uvmap_name == attr.name ?
275 const pxr::TfToken pv_name(
277 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh);
279 pxr::UsdGeomPrimvar pv_uv = pv_api.CreatePrimvar(
280 pv_name, pxr::SdfValueTypeNames->TexCoord2fArray, pxr::UsdGeomTokens->faceVarying);
327 pxr::UsdGeomMesh usd_mesh = pxr::UsdGeomMesh::Define(stage,
usd_path);
333 get_geometry_data(mesh, usd_mesh_data);
335 pxr::UsdAttribute attr_points = usd_mesh.CreatePointsAttr(pxr::VtValue(),
true);
336 pxr::UsdAttribute attr_face_vertex_counts = usd_mesh.CreateFaceVertexCountsAttr(pxr::VtValue(),
338 pxr::UsdAttribute attr_face_vertex_indices = usd_mesh.CreateFaceVertexIndicesAttr(pxr::VtValue(),
341 if (!attr_points.HasValue()) {
344 attr_points.Set(usd_mesh_data.
points, pxr::UsdTimeCode::Default());
345 attr_face_vertex_counts.Set(usd_mesh_data.
face_vertex_counts, pxr::UsdTimeCode::Default());
346 attr_face_vertex_indices.Set(usd_mesh_data.
face_indices, pxr::UsdTimeCode::Default());
353 attr_face_vertex_indices, pxr::VtValue(usd_mesh_data.
face_indices), timecode);
356 pxr::UsdAttribute attr_crease_lengths = usd_mesh.CreateCreaseLengthsAttr(pxr::VtValue(),
true);
357 pxr::UsdAttribute attr_crease_indices = usd_mesh.CreateCreaseIndicesAttr(pxr::VtValue(),
true);
358 pxr::UsdAttribute attr_crease_sharpness = usd_mesh.CreateCreaseSharpnessesAttr(pxr::VtValue(),
361 if (!attr_crease_lengths.HasValue()) {
362 attr_crease_lengths.Set(usd_mesh_data.
crease_lengths, pxr::UsdTimeCode::Default());
364 attr_crease_sharpness.Set(usd_mesh_data.
crease_sharpnesses, pxr::UsdTimeCode::Default());
368 attr_crease_lengths, pxr::VtValue(usd_mesh_data.
crease_lengths), timecode);
378 pxr::UsdAttribute attr_corner_indices = usd_mesh.CreateCornerIndicesAttr(pxr::VtValue(),
true);
379 pxr::UsdAttribute attr_corner_sharpnesses = usd_mesh.CreateCornerSharpnessesAttr(
380 pxr::VtValue(),
true);
382 if (!attr_corner_indices.HasValue()) {
383 attr_corner_indices.Set(usd_mesh_data.
corner_indices, pxr::UsdTimeCode::Default());
384 attr_corner_sharpnesses.Set(usd_mesh_data.
corner_sharpnesses, pxr::UsdTimeCode::Default());
388 attr_corner_indices, pxr::VtValue(usd_mesh_data.
corner_indices), timecode);
393 write_custom_data(
context.object, mesh, usd_mesh);
394 write_surface_velocity(mesh, usd_mesh);
396 const pxr::TfToken subdiv_scheme = get_subdiv_scheme(subsurfData);
402 subdiv_scheme == pxr::UsdGeomTokens->none)
404 write_normals(mesh, usd_mesh);
407 this->
author_extent(usd_mesh, mesh->bounds_min_max(), timecode);
416 write_subdiv(subdiv_scheme, usd_mesh, subsurfData);
419 assign_materials(context, usd_mesh, usd_mesh_data.
face_groups);
423pxr::TfToken USDGenericMeshWriter::get_subdiv_scheme(
const SubsurfModifierData *subsurfData)
426 pxr::TfToken subdiv_scheme = pxr::UsdGeomTokens->none;
433 subdiv_scheme = pxr::UsdGeomTokens->catmullClark;
441 "USD export: Simple subdivision not supported, exporting subdivided mesh");
445 return subdiv_scheme;
448void USDGenericMeshWriter::write_subdiv(
const pxr::TfToken &subdiv_scheme,
449 const pxr::UsdGeomMesh &usd_mesh,
452 usd_mesh.CreateSubdivisionSchemeAttr().Set(subdiv_scheme);
453 if (subdiv_scheme == pxr::UsdGeomTokens->catmullClark) {
460 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->
all);
463 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->cornersOnly);
466 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->cornersPlus1);
469 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->cornersPlus2);
472 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->boundaries);
475 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->none);
486 usd_mesh.CreateInterpolateBoundaryAttr().Set(pxr::UsdGeomTokens->edgeOnly);
489 usd_mesh.CreateInterpolateBoundaryAttr().Set(pxr::UsdGeomTokens->edgeAndCorner);
500 usd_mesh_data.
points = pxr::VtArray<pxr::GfVec3f>(positions.
begin(), positions.
end());
524 const Span<int> corner_verts = mesh->corner_verts();
539 const float crease = std::clamp(creases[
i], 0.0f, 1.0f);
541 if (crease != 0.0f) {
560 const float crease = std::clamp(creases[
i], 0.0f, 1.0f);
562 if (crease != 0.0f) {
569void USDGenericMeshWriter::get_geometry_data(
const Mesh *mesh, USDMeshData &usd_mesh_data)
577void USDGenericMeshWriter::assign_materials(
const HierarchyContext &context,
578 const pxr::UsdGeomMesh &usd_mesh,
581 if (context.object->totcol == 0) {
588 bool mesh_material_bound =
false;
589 auto mesh_prim = usd_mesh.GetPrim();
590 pxr::UsdShadeMaterialBindingAPI material_binding_api(mesh_prim);
591 for (
int mat_num = 0; mat_num < context.object->totcol; mat_num++) {
593 if (material ==
nullptr) {
598 material_binding_api.Bind(usd_material);
602 usd_mesh.CreateDoubleSidedAttr(
605 mesh_material_bound =
true;
609 if (mesh_material_bound) {
613 pxr::UsdShadeMaterialBindingAPI::Apply(mesh_prim);
617 usd_mesh.CreateDoubleSidedAttr(pxr::VtValue(
true));
620 if (!mesh_material_bound || usd_face_groups.size() < 2) {
629 short material_number = face_group.key;
630 const pxr::VtIntArray &face_indices = face_group.value;
633 if (material ==
nullptr) {
638 pxr::TfToken material_name = usd_material.GetPath().GetNameToken();
640 pxr::UsdGeomSubset usd_face_subset = material_binding_api.CreateMaterialBindSubset(
641 material_name, face_indices);
642 auto subset_prim = usd_face_subset.GetPrim();
643 auto subset_material_api = pxr::UsdShadeMaterialBindingAPI(subset_prim);
644 subset_material_api.Bind(usd_material);
646 pxr::UsdShadeMaterialBindingAPI::Apply(subset_prim);
650void USDGenericMeshWriter::write_normals(
const Mesh *mesh, pxr::UsdGeomMesh &usd_mesh)
654 pxr::VtVec3fArray loop_normals;
657 MutableSpan dst_normals(
reinterpret_cast<float3 *
>(loop_normals.data()), loop_normals.size());
659 switch (mesh->normals_domain()) {
665 const OffsetIndices
faces = mesh->faces();
666 const Span<float3> face_normals = mesh->face_normals();
667 for (
const int i :
faces.index_range()) {
668 dst_normals.slice(
faces[
i]).fill(face_normals[
i]);
678 pxr::UsdAttribute attr_normals = usd_mesh.CreateNormalsAttr(pxr::VtValue(),
true);
679 if (!attr_normals.HasValue()) {
680 attr_normals.Set(loop_normals, pxr::UsdTimeCode::Default());
682 usd_value_writer_.SetAttribute(attr_normals, pxr::VtValue(loop_normals), timecode);
683 usd_mesh.SetNormalsInterpolation(pxr::UsdGeomTokens->faceVarying);
686void USDGenericMeshWriter::write_surface_velocity(
const Mesh *mesh,
687 const pxr::UsdGeomMesh &usd_mesh)
693 if (velocity.is_empty()) {
698 Span<pxr::GfVec3f>
data = velocity.cast<pxr::GfVec3f>();
699 pxr::VtVec3fArray usd_velocities;
700 usd_velocities.assign(
data.begin(),
data.end());
703 pxr::UsdAttribute attr_vel = usd_mesh.CreateVelocitiesAttr(pxr::VtValue(),
true);
704 if (!attr_vel.HasValue()) {
705 attr_vel.Set(usd_velocities, pxr::UsdTimeCode::Default());
718 write_skinned_mesh_ =
false;
719 write_blend_shapes_ =
false;
725 write_skinned_mesh_ =
params.export_armatures &&
738 if (!mesh_prim.IsValid()) {
740 "%s: couldn't get valid mesh prim for mesh %s",
746 pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(mesh_prim);
750 "Couldn't apply UsdSkelBindingAPI to mesh prim %s",
760 "Couldn't get armature modifier object for skinned mesh %s",
771 "No armature bones for skinned mesh %s",
776 bool needsfree =
false;
779 if (mesh ==
nullptr) {
804 if (!mesh_prim.IsValid()) {
806 "Couldn't get valid mesh prim for mesh %s",
807 mesh_prim.GetPath().GetAsString().c_str());
825 if (write_blend_shapes_) {
833 if (write_skinned_mesh_) {
837 if (write_blend_shapes_) {
845 if (write_blend_shapes_) {
852 if (write_skinned_mesh_) {
881 if (!mesh_prim.IsValid()) {
883 "Couldn't get valid mesh prim for mesh %s",
893 pxr::UsdAttribute temp_weights_attr = pxr::UsdGeomPrimvarsAPI(mesh_prim).CreatePrimvar(
896 if (!temp_weights_attr) {
898 "Couldn't create primvar %s on prim %s",
900 mesh_prim.GetPath().GetAsString().c_str());
904 temp_weights_attr.Set(weights, timecode);
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
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
eCustomDataType data_type
GAttributeReader get() const
pxr::UsdShadeMaterial ensure_usd_material(const HierarchyContext &context, Material *material) const
bool frame_has_been_written_
const pxr::SdfPath & usd_path() const
void write_visibility(const HierarchyContext &context, const pxr::UsdTimeCode timecode, const pxr::UsdGeomImageable &usd_geometry)
ReportList * reports() const
void author_extent(const pxr::UsdGeomBoundable &boundable, const pxr::UsdTimeCode timecode)
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
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 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)
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)
void copy_blender_attribute_to_primvar(const GVArray &attribute, const eCustomDataType data_type, const pxr::UsdTimeCode timecode, const pxr::UsdGeomPrimvar &primvar, pxr::UsdUtilsSparseValueWriter &value_writer)
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)
std::optional< pxr::SdfValueTypeName > convert_blender_type_to_usd(const eCustomDataType blender_type, bool use_color3f_type)
pxr::VtFloatArray get_blendshape_weights(const Key *key)
bool can_export_skinned_mesh(const Object &obj, const Depsgraph *depsgraph)
void copy_blender_buffer_to_primvar(const VArray< BlenderT > &buffer, const pxr::UsdTimeCode timecode, const pxr::UsdGeomPrimvar &primvar, pxr::UsdUtilsSparseValueWriter &value_writer)
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