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>
43static const pxr::TfToken
Anim(
"Anim", pxr::TfToken::Immortal);
78 if ((md->
mode & mod_mode) != mod_mode) {
91 Object *object_eval = context.object;
92 bool needsfree =
false;
95 if (mesh ==
nullptr) {
100 const bool tag_only =
false;
118 mesh = triangulated_mesh;
127 write_mesh(context, mesh, subsurfData);
130 if (prim.IsValid() && object_eval) {
147void USDGenericMeshWriter::write_custom_data(
const Object *
obj,
149 const pxr::UsdGeomMesh &usd_mesh)
161 ELEM(iter.
name,
"position",
"material_index",
"velocity",
"crease_vert"))
190 this->write_uv_data(usd_mesh, iter, active_uvmap_name);
195 this->write_generic_data(mesh, usd_mesh, iter);
203 switch (blender_domain) {
205 return pxr::UsdGeomTokens->faceVarying;
207 return pxr::UsdGeomTokens->vertex;
209 return pxr::UsdGeomTokens->uniform;
217void USDGenericMeshWriter::write_generic_data(
const Mesh *mesh,
218 const pxr::UsdGeomMesh &usd_mesh,
221 const pxr::TfToken pv_name(
228 if (!pv_interp || !pv_type) {
231 "Mesh '%s', Attribute '%s' (domain %d, type %d) cannot be converted to USD",
245 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh);
247 pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type, *pv_interp);
253void USDGenericMeshWriter::write_uv_data(
const pxr::UsdGeomMesh &usd_mesh,
254 const bke::AttributeIter &attr,
255 const StringRef active_uvmap_name)
265 active_uvmap_name == attr.name ?
270 const pxr::TfToken pv_name(
272 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh);
274 pxr::UsdGeomPrimvar pv_uv = pv_api.CreatePrimvar(
275 pv_name, pxr::SdfValueTypeNames->TexCoord2fArray, pxr::UsdGeomTokens->faceVarying);
322 pxr::UsdGeomMesh usd_mesh = pxr::UsdGeomMesh::Define(stage,
usd_path);
328 get_geometry_data(mesh, usd_mesh_data);
340 assign_materials(context, usd_mesh, usd_mesh_data.
face_groups);
346 pxr::UsdAttribute attr_points = usd_mesh.CreatePointsAttr(pxr::VtValue(),
true);
347 pxr::UsdAttribute attr_face_vertex_counts = usd_mesh.CreateFaceVertexCountsAttr(pxr::VtValue(),
349 pxr::UsdAttribute attr_face_vertex_indices = usd_mesh.CreateFaceVertexIndicesAttr(pxr::VtValue(),
352 if (!attr_points.HasValue()) {
355 attr_points.Set(usd_mesh_data.
points, pxr::UsdTimeCode::Default());
356 attr_face_vertex_counts.Set(usd_mesh_data.
face_vertex_counts, pxr::UsdTimeCode::Default());
357 attr_face_vertex_indices.Set(usd_mesh_data.
face_indices, pxr::UsdTimeCode::Default());
364 attr_face_vertex_indices, pxr::VtValue(usd_mesh_data.
face_indices), timecode);
367 pxr::UsdAttribute attr_crease_lengths = usd_mesh.CreateCreaseLengthsAttr(pxr::VtValue(),
true);
368 pxr::UsdAttribute attr_crease_indices = usd_mesh.CreateCreaseIndicesAttr(pxr::VtValue(),
true);
369 pxr::UsdAttribute attr_crease_sharpness = usd_mesh.CreateCreaseSharpnessesAttr(pxr::VtValue(),
372 if (!attr_crease_lengths.HasValue()) {
373 attr_crease_lengths.Set(usd_mesh_data.
crease_lengths, pxr::UsdTimeCode::Default());
375 attr_crease_sharpness.Set(usd_mesh_data.
crease_sharpnesses, pxr::UsdTimeCode::Default());
379 attr_crease_lengths, pxr::VtValue(usd_mesh_data.
crease_lengths), timecode);
389 pxr::UsdAttribute attr_corner_indices = usd_mesh.CreateCornerIndicesAttr(pxr::VtValue(),
true);
390 pxr::UsdAttribute attr_corner_sharpnesses = usd_mesh.CreateCornerSharpnessesAttr(
391 pxr::VtValue(),
true);
393 if (!attr_corner_indices.HasValue()) {
394 attr_corner_indices.Set(usd_mesh_data.
corner_indices, pxr::UsdTimeCode::Default());
395 attr_corner_sharpnesses.Set(usd_mesh_data.
corner_sharpnesses, pxr::UsdTimeCode::Default());
399 attr_corner_indices, pxr::VtValue(usd_mesh_data.
corner_indices), timecode);
404 write_custom_data(
context.object, mesh, usd_mesh);
405 write_surface_velocity(mesh, usd_mesh);
407 const pxr::TfToken subdiv_scheme = get_subdiv_scheme(subsurfData);
413 subdiv_scheme == pxr::UsdGeomTokens->none)
415 write_normals(mesh, usd_mesh);
425 write_subdiv(subdiv_scheme, usd_mesh, subsurfData);
428 assign_materials(context, usd_mesh, usd_mesh_data.
face_groups);
432 if (
const std::optional<Bounds<float3>> bounds = mesh->bounds_min_max()) {
433 pxr::VtArray<pxr::GfVec3f> extent{
434 pxr::GfVec3f{bounds->min[0], bounds->min[1], bounds->min[2]},
435 pxr::GfVec3f{bounds->max[0], bounds->max[1], bounds->max[2]}};
436 usd_mesh.CreateExtentAttr().Set(extent);
440pxr::TfToken USDGenericMeshWriter::get_subdiv_scheme(
const SubsurfModifierData *subsurfData)
443 pxr::TfToken subdiv_scheme = pxr::UsdGeomTokens->none;
450 subdiv_scheme = pxr::UsdGeomTokens->catmullClark;
458 "USD export: Simple subdivision not supported, exporting subdivided mesh");
462 return subdiv_scheme;
465void USDGenericMeshWriter::write_subdiv(
const pxr::TfToken &subdiv_scheme,
466 const pxr::UsdGeomMesh &usd_mesh,
469 usd_mesh.CreateSubdivisionSchemeAttr().Set(subdiv_scheme);
470 if (subdiv_scheme == pxr::UsdGeomTokens->catmullClark) {
477 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->all);
480 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->cornersOnly);
483 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->cornersPlus1);
486 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->cornersPlus2);
489 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->boundaries);
492 usd_mesh.CreateFaceVaryingLinearInterpolationAttr().Set(pxr::UsdGeomTokens->none);
503 usd_mesh.CreateInterpolateBoundaryAttr().Set(pxr::UsdGeomTokens->edgeOnly);
506 usd_mesh.CreateInterpolateBoundaryAttr().Set(pxr::UsdGeomTokens->edgeAndCorner);
517 usd_mesh_data.
points = pxr::VtArray<pxr::GfVec3f>(positions.
begin(), positions.
end());
541 const Span<int> corner_verts = mesh->corner_verts();
556 const float crease = creases[i];
557 if (crease == 0.0f) {
561 const float sharpness = crease >= 1.0f ? pxr::UsdGeomMesh::SHARPNESS_INFINITE : crease;
580 const float crease = creases[i];
583 const float sharpness = crease >= 1.0f ? pxr::UsdGeomMesh::SHARPNESS_INFINITE : crease;
590void USDGenericMeshWriter::get_geometry_data(
const Mesh *mesh, USDMeshData &usd_mesh_data)
598void USDGenericMeshWriter::assign_materials(
const HierarchyContext &context,
599 const pxr::UsdGeomMesh &usd_mesh,
600 const MaterialFaceGroups &usd_face_groups)
602 if (context.object->totcol == 0) {
609 bool mesh_material_bound =
false;
610 auto mesh_prim = usd_mesh.GetPrim();
611 pxr::UsdShadeMaterialBindingAPI material_binding_api(mesh_prim);
612 for (
int mat_num = 0; mat_num < context.object->totcol; mat_num++) {
614 if (material ==
nullptr) {
619 material_binding_api.Bind(usd_material);
623 usd_mesh.CreateDoubleSidedAttr(
626 mesh_material_bound =
true;
630 if (mesh_material_bound) {
634 pxr::UsdShadeMaterialBindingAPI::Apply(mesh_prim);
638 usd_mesh.CreateDoubleSidedAttr(pxr::VtValue(
true));
641 if (!mesh_material_bound || usd_face_groups.size() < 2) {
650 short material_number = face_group.key;
651 const pxr::VtIntArray &face_indices = face_group.value;
654 if (material ==
nullptr) {
659 pxr::TfToken material_name = usd_material.GetPath().GetNameToken();
661 pxr::UsdGeomSubset usd_face_subset = material_binding_api.CreateMaterialBindSubset(
662 material_name, face_indices);
663 auto subset_prim = usd_face_subset.GetPrim();
664 auto subset_material_api = pxr::UsdShadeMaterialBindingAPI(subset_prim);
665 subset_material_api.Bind(usd_material);
667 subset_material_api.Apply(subset_prim);
671void USDGenericMeshWriter::write_normals(
const Mesh *mesh, pxr::UsdGeomMesh &usd_mesh)
675 pxr::VtVec3fArray loop_normals;
678 MutableSpan dst_normals(
reinterpret_cast<float3 *
>(loop_normals.data()), loop_normals.size());
680 switch (mesh->normals_domain()) {
686 const OffsetIndices
faces = mesh->faces();
687 const Span<float3> face_normals = mesh->face_normals();
688 for (
const int i :
faces.index_range()) {
689 dst_normals.slice(
faces[i]).fill(face_normals[i]);
699 pxr::UsdAttribute attr_normals = usd_mesh.CreateNormalsAttr(pxr::VtValue(),
true);
700 if (!attr_normals.HasValue()) {
701 attr_normals.Set(loop_normals, pxr::UsdTimeCode::Default());
703 usd_value_writer_.SetAttribute(attr_normals, pxr::VtValue(loop_normals), timecode);
704 usd_mesh.SetNormalsInterpolation(pxr::UsdGeomTokens->faceVarying);
707void USDGenericMeshWriter::write_surface_velocity(
const Mesh *mesh,
708 const pxr::UsdGeomMesh &usd_mesh)
714 if (velocity.is_empty()) {
719 Span<pxr::GfVec3f>
data = velocity.cast<pxr::GfVec3f>();
720 pxr::VtVec3fArray usd_velocities;
721 usd_velocities.assign(
data.begin(),
data.end());
724 pxr::UsdAttribute attr_vel = usd_mesh.CreateVelocitiesAttr(pxr::VtValue(),
true);
725 if (!attr_vel.HasValue()) {
726 attr_vel.Set(usd_velocities, pxr::UsdTimeCode::Default());
739 write_skinned_mesh_ =
false;
740 write_blend_shapes_ =
false;
746 write_skinned_mesh_ =
params.export_armatures &&
759 if (!mesh_prim.IsValid()) {
761 "%s: couldn't get valid mesh prim for mesh %s",
767 pxr::UsdSkelBindingAPI skel_api = pxr::UsdSkelBindingAPI::Apply(mesh_prim);
771 "Couldn't apply UsdSkelBindingAPI to mesh prim %s",
781 "Couldn't get armature modifier object for skinned mesh %s",
792 "No armature bones for skinned mesh %s",
797 bool needsfree =
false;
800 if (mesh ==
nullptr) {
825 if (!mesh_prim.IsValid()) {
827 "Couldn't get valid mesh prim for mesh %s",
828 mesh_prim.GetPath().GetAsString().c_str());
846 if (write_blend_shapes_) {
854 if (write_skinned_mesh_) {
858 if (write_blend_shapes_) {
866 if (write_blend_shapes_) {
873 if (write_skinned_mesh_) {
901 if (!mesh_prim.IsValid()) {
903 "Couldn't get valid mesh prim for mesh %s",
913 pxr::UsdAttribute temp_weights_attr = pxr::UsdGeomPrimvarsAPI(mesh_prim).CreatePrimvar(
916 if (!temp_weights_attr) {
918 "Couldn't create primvar %s on prim %s",
920 mesh_prim.GetPath().GetAsString().c_str());
924 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.
struct Material * BKE_object_material_get(struct 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.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
Mesh * BKE_object_get_pre_modified_mesh(const Object *object)
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
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
ATTR_WARN_UNUSED_RESULT BMesh * bm
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::VtIntArray > 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
virtual bool mark_as_instance(const HierarchyContext &context, const pxr::UsdPrim &prim)
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)
virtual void do_write(HierarchyContext &context) override
virtual 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)
virtual 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)
virtual Mesh * get_export_mesh(Object *object_eval, bool &r_needsfree) override
void set_skel_export_flags(const HierarchyContext &context)
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)
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)
static void get_positions(const Mesh *mesh, USDMeshData &usd_mesh_data)
std::string make_safe_name(const std::string &name, bool allow_unicode)
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)
void export_deform_verts(const Mesh *mesh, const pxr::UsdSkelBindingAPI &skel_api, const Span< std::string > bone_names)
const Key * get_mesh_shape_key(const Object *obj)
static void get_edge_creases(const Mesh *mesh, USDMeshData &usd_mesh_data)
pxr::TfToken TempBlendShapeWeightsPrimvarName
void get_armature_bone_names(const Object *ob_arm, const bool use_deform, Vector< std::string > &r_names)
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)
static const pxr::TfToken Anim("Anim", 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
Map< short, pxr::VtIntArray > face_groups
pxr::VtIntArray face_indices
pxr::VtIntArray crease_lengths
pxr::VtFloatArray corner_sharpnesses
pxr::VtFloatArray crease_sharpnesses
pxr::VtIntArray corner_indices
pxr::VtArray< pxr::GfVec3f > points