30 #include <pxr/base/vt/array.h>
31 #include <pxr/base/vt/types.h>
32 #include <pxr/base/vt/value.h>
33 #include <pxr/usd/sdf/types.h>
34 #include <pxr/usd/usdGeom/mesh.h>
35 #include <pxr/usd/usdGeom/subset.h>
36 #include <pxr/usd/usdShade/materialBindingAPI.h>
42 static const pxr::TfToken
st(
"st", pxr::TfToken::Immortal);
43 static const pxr::TfToken
UVMap(
"UVMap", pxr::TfToken::Immortal);
44 static const pxr::TfToken
Cd(
"Cd", pxr::TfToken::Immortal);
45 static const pxr::TfToken
displayColor(
"displayColor", pxr::TfToken::Immortal);
53 if (r_mat_map ==
nullptr) {
67 return pxr::UsdShadeMaterialBindingAPI(prim).ComputeBoundMaterial();
74 const pxr::SdfPath &usd_mat_path,
76 const std::map<std::string, Material *> &mat_map,
77 const std::map<std::string, std::string> &usd_path_to_mat_name)
81 std::map<std::string, std::string>::const_iterator path_to_name_iter =
82 usd_path_to_mat_name.find(usd_mat_path.GetAsString());
84 if (path_to_name_iter != usd_path_to_mat_name.end()) {
85 std::string mat_name = path_to_name_iter->second;
86 std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
87 if (mat_iter != mat_map.end()) {
88 return mat_iter->second;
96 std::string mat_name = usd_mat_path.GetName();
97 std::map<std::string, Material *>::const_iterator mat_iter = mat_map.find(mat_name);
99 if (mat_iter != mat_map.end()) {
100 return mat_iter->second;
109 const std::map<pxr::SdfPath, int> &mat_index_map,
111 pxr::UsdStageRefPtr
stage,
112 std::map<std::string, Material *> &mat_name_to_mat,
113 std::map<std::string, std::string> &usd_path_to_mat_name)
115 if (!(
stage && bmain && ob)) {
119 if (mat_index_map.size() >
MAXMAT) {
125 for (std::map<pxr::SdfPath, int>::const_iterator it = mat_index_map.begin();
126 it != mat_index_map.end();
130 it->first,
params, mat_name_to_mat, usd_path_to_mat_name);
135 pxr::UsdPrim prim =
stage->GetPrimAtPath(it->first);
136 pxr::UsdShadeMaterial usd_mat(prim);
139 std::cout <<
"WARNING: Couldn't construct USD material from prim " << it->first
148 std::cout <<
"WARNING: Couldn't create Blender material from USD material " << it->first
153 const std::string mat_name = pxr::TfMakeValidIdentifier(assigned_mat->
id.
name + 2);
154 mat_name_to_mat[mat_name] = assigned_mat;
159 usd_path_to_mat_name[it->first.GetAsString()] = mat_name;
168 std::cout <<
"WARNING: Couldn't assign material " << it->first << std::endl;
192 if (cd_ptr !=
nullptr) {
210 is_left_handed_(false),
212 is_time_varying_(false),
213 is_initial_load_(false)
229 is_initial_load_ =
true;
233 is_initial_load_ =
false;
242 readFaceSetsSample(bmain,
mesh, motionSampleTime);
244 if (mesh_prim_.GetPointsAttr().ValueMightBeTimeVarying()) {
245 is_time_varying_ =
true;
248 if (is_time_varying_) {
253 pxr::TfToken subdivScheme;
254 mesh_prim_.GetSubdivisionSchemeAttr().Get(&subdivScheme, motionSampleTime);
256 if (subdivScheme == pxr::UsdGeomTokens->catmullClark) {
266 return static_cast<bool>(mesh_prim_);
274 mesh_prim_.GetFaceVertexIndicesAttr().Get(&face_indices_, motionSampleTime);
275 mesh_prim_.GetFaceVertexCountsAttr().Get(&face_counts_, motionSampleTime);
276 mesh_prim_.GetPointsAttr().Get(&positions_, motionSampleTime);
283 if (primvar.HasValue()) {
284 primvar.ComputeFlattened(&normals_, motionSampleTime);
285 normal_interpolation_ = primvar.GetInterpolation();
288 mesh_prim_.GetNormalsAttr().Get(&normals_, motionSampleTime);
289 normal_interpolation_ = mesh_prim_.GetNormalsInterpolation();
292 return positions_.size() != existing_mesh->
totvert ||
293 face_counts_.size() != existing_mesh->
totpoly ||
294 face_indices_.size() != existing_mesh->
totloop;
297 void USDMeshReader::read_mpolys(
Mesh *
mesh)
304 for (
int i = 0; i < face_counts_.size(); i++) {
305 const int face_size = face_counts_[i];
307 MPoly &poly = mpolys[i];
316 if (is_left_handed_) {
317 int loop_end_index = loop_index + (face_size - 1);
318 for (
int f = 0; f < face_size; ++f, ++loop_index) {
319 mloops[loop_index].
v = face_indices_[loop_end_index - f];
323 for (
int f = 0; f < face_size; ++f, ++loop_index) {
324 mloops[loop_index].
v = face_indices_[loop_index];
332 void USDMeshReader::read_uvs(
Mesh *
mesh,
const double motionSampleTime,
const bool load_uvs)
334 unsigned int loop_index = 0;
335 unsigned int rev_loop_index = 0;
336 unsigned int uv_index = 0;
341 pxr::VtVec2fArray uvs;
342 pxr::TfToken interpolation;
345 std::vector<UVSample> uv_primvars(ldata->
totlayer);
348 for (
int layer_idx = 0; layer_idx < ldata->
totlayer; layer_idx++) {
350 std::string layer_name = std::string(layer->
name);
355 pxr::TfToken uv_token;
358 if (uv_token_map_.find(layer_name) == uv_token_map_.end()) {
359 uv_token = pxr::TfToken(layer_name);
360 uv_token_map_.insert(std::make_pair(layer_name, uv_token));
363 uv_token = uv_token_map_.at(layer_name);
367 if (uv_token.IsEmpty()) {
371 if (!load_uvs && primvar_varying_map_.find(uv_token) != primvar_varying_map_.end() &&
372 !primvar_varying_map_.at(uv_token)) {
377 if (!mesh_prim_.HasPrimvar(uv_token)) {
381 if (pxr::UsdGeomPrimvar uv_primvar = mesh_prim_.GetPrimvar(uv_token)) {
382 uv_primvar.ComputeFlattened(&uv_primvars[layer_idx].uvs, motionSampleTime);
383 uv_primvars[layer_idx].interpolation = uv_primvar.GetInterpolation();
388 for (
int i = 0; i < face_counts_.size(); i++) {
389 const int face_size = face_counts_[i];
391 rev_loop_index = loop_index + (face_size - 1);
393 for (
int f = 0; f < face_size; f++, loop_index++, rev_loop_index--) {
395 for (
int layer_idx = 0; layer_idx < ldata->
totlayer; layer_idx++) {
402 if (layer_idx > uv_primvars.size()) {
407 if (uv_primvars[layer_idx].uvs.empty()) {
411 const UVSample &
sample = uv_primvars[layer_idx];
414 pxr::UsdGeomTokens->faceVarying,
415 pxr::UsdGeomTokens->vertex))) {
416 std::cerr <<
"WARNING: unexpected interpolation type " <<
sample.interpolation
417 <<
" for uv " << layer->
name << std::endl;
422 int usd_uv_index =
sample.interpolation == pxr::UsdGeomTokens->vertex ?
426 if (usd_uv_index >=
sample.uvs.size()) {
427 std::cerr <<
"WARNING: out of bounds uv index " << usd_uv_index <<
" for uv "
428 << layer->
name <<
" of size " <<
sample.uvs.size() << std::endl;
433 if (is_left_handed_) {
434 uv_index = rev_loop_index;
437 uv_index = loop_index;
439 mloopuv[uv_index].
uv[0] =
sample.uvs[usd_uv_index][0];
440 mloopuv[uv_index].
uv[1] =
sample.uvs[usd_uv_index][1];
446 void USDMeshReader::read_colors(
Mesh *
mesh,
const double motionSampleTime)
458 pxr::UsdGeomPrimvar color_primvar = mesh_prim_.GetDisplayColorPrimvar();
460 if (!color_primvar.HasValue()) {
464 pxr::TfToken
interp = color_primvar.GetInterpolation();
466 if (
interp == pxr::UsdGeomTokens->varying) {
467 std::cerr <<
"WARNING: Unsupported varying interpolation for display colors\n" << std::endl;
472 bool might_be_time_varying = color_primvar.ValueMightBeTimeVarying();
474 if (might_be_time_varying) {
475 is_time_varying_ =
true;
479 pxr::VtArray<pxr::GfVec3f> display_colors;
481 if (!color_primvar.ComputeFlattened(&display_colors, motionSampleTime)) {
482 std::cerr <<
"WARNING: Couldn't compute display colors\n" << std::endl;
486 if ((
interp == pxr::UsdGeomTokens->faceVarying && display_colors.size() !=
mesh->
totloop) ||
487 (
interp == pxr::UsdGeomTokens->vertex && display_colors.size() !=
mesh->
totvert) ||
488 (
interp == pxr::UsdGeomTokens->constant && display_colors.size() != 1) ||
489 (
interp == pxr::UsdGeomTokens->uniform && display_colors.size() !=
mesh->
totpoly)) {
490 std::cerr <<
"WARNING: display colors count mismatch\n" << std::endl;
497 std::cerr <<
"WARNING: Couldn't add displayColors custom data.\n";
508 for (
int j = 0; j < poly->
totloop; ++j) {
514 if (
interp == pxr::UsdGeomTokens->vertex) {
517 else if (
interp == pxr::UsdGeomTokens->faceVarying) {
519 if (is_left_handed_) {
520 usd_index += poly->
totloop - 1 - j;
526 else if (
interp == pxr::UsdGeomTokens->uniform) {
531 if (usd_index >= display_colors.size()) {
543 void USDMeshReader::read_vertex_creases(
Mesh *
mesh,
const double motionSampleTime)
545 pxr::VtIntArray corner_indices;
546 if (!mesh_prim_.GetCornerIndicesAttr().Get(&corner_indices, motionSampleTime)) {
550 pxr::VtIntArray corner_sharpnesses;
551 if (!mesh_prim_.GetCornerSharpnessesAttr().Get(&corner_sharpnesses, motionSampleTime)) {
557 std::cerr <<
"WARNING: too many vertex crease for mesh " <<
prim_path_ << std::endl;
561 if (corner_indices.size() != corner_sharpnesses.size()) {
562 std::cerr <<
"WARNING: vertex crease indices and sharpnesses count mismatch for mesh "
567 float *creases =
static_cast<float *
>(
570 for (
size_t i = 0; i < corner_indices.size(); i++) {
571 creases[corner_indices[i]] = corner_sharpnesses[i];
575 void USDMeshReader::process_normals_vertex_varying(
Mesh *
mesh)
581 if (normals_.empty()) {
586 std::cerr <<
"WARNING: vertex varying normals count mismatch for mesh " <<
prim_path_
593 vert_normals.copy_from({(
float3 *)normals_.data(),
static_cast<int64_t>(normals_.size())});
597 void USDMeshReader::process_normals_face_varying(
Mesh *
mesh)
599 if (normals_.empty()) {
606 std::cerr <<
"WARNING: loop normal count mismatch for mesh " <<
mesh->
id.
name << std::endl;
613 long int loop_count = normals_.size();
615 float(*lnors)[3] =
static_cast<float(*)[3]
>(
621 for (
int j = 0; j < mpoly->
totloop; j++) {
622 int blender_index = mpoly->
loopstart + j;
625 if (is_left_handed_) {
626 usd_index += mpoly->
totloop - 1 - j;
632 lnors[blender_index][0] = normals_[usd_index][0];
633 lnors[blender_index][1] = normals_[usd_index][1];
634 lnors[blender_index][2] = normals_[usd_index][2];
642 void USDMeshReader::process_normals_uniform(
Mesh *
mesh)
644 if (normals_.empty()) {
651 std::cerr <<
"WARNING: uniform normal count mismatch for mesh " <<
mesh->
id.
name << std::endl;
656 float(*lnors)[3] =
static_cast<float(*)[3]
>(
663 for (
int j = 0; j < mpoly->
totloop; j++) {
665 lnors[loop_index][0] = normals_[i][0];
666 lnors[loop_index][1] = normals_[i][1];
667 lnors[loop_index][2] = normals_[i][2];
679 const double motionSampleTime,
687 for (
int i = 0; i < positions_.size(); i++) {
689 mvert.
co[0] = positions_[i][0];
690 mvert.
co[1] = positions_[i][1];
691 mvert.
co[2] = positions_[i][2];
694 read_vertex_creases(
mesh, motionSampleTime);
699 if (normal_interpolation_ == pxr::UsdGeomTokens->faceVarying) {
700 process_normals_face_varying(
mesh);
702 else if (normal_interpolation_ == pxr::UsdGeomTokens->uniform) {
703 process_normals_uniform(
mesh);
713 normal_interpolation_ == pxr::UsdGeomTokens->vertex) {
714 process_normals_vertex_varying(
mesh);
718 read_uvs(
mesh, motionSampleTime, new_mesh);
722 read_colors(
mesh, motionSampleTime);
726 void USDMeshReader::assign_facesets_to_mpoly(
double motionSampleTime,
729 std::map<pxr::SdfPath, int> *r_mat_map)
731 if (r_mat_map ==
nullptr) {
741 const std::vector<pxr::UsdGeomSubset> subsets = pxr::UsdGeomSubset::GetAllGeomSubsets(
745 if (!subsets.empty()) {
746 for (
const pxr::UsdGeomSubset &subset : subsets) {
753 pxr::SdfPath subset_mtl_path = subset_mtl.GetPath();
755 if (subset_mtl_path.IsEmpty()) {
759 if (r_mat_map->find(subset_mtl_path) == r_mat_map->end()) {
760 (*r_mat_map)[subset_mtl_path] = 1 + current_mat++;
763 const int mat_idx = (*r_mat_map)[subset_mtl_path] - 1;
765 pxr::UsdAttribute indicesAttribute = subset.GetIndicesAttr();
767 indicesAttribute.Get(&
indices, motionSampleTime);
769 for (
int i = 0; i <
indices.size(); i++) {
776 if (r_mat_map->empty()) {
780 pxr::SdfPath mtl_path = mtl.GetPath();
782 if (!mtl_path.IsEmpty()) {
783 r_mat_map->insert(std::make_pair(mtl.GetPath(), 1));
789 void USDMeshReader::readFaceSetsSample(
Main *bmain,
Mesh *
mesh,
const double motionSampleTime)
795 std::map<pxr::SdfPath, int> mat_map;
805 this->
prim_.GetStage(),
806 this->settings_->mat_name_to_mat,
807 this->settings_->usd_path_to_mat_name);
811 const double motionSampleTime,
816 return existing_mesh;
819 mesh_prim_.GetOrientationAttr().Get(&orientation_);
820 if (orientation_ == pxr::UsdGeomTokens->leftHanded) {
821 is_left_handed_ =
true;
824 std::vector<pxr::TfToken> uv_tokens;
829 std::vector<pxr::UsdGeomPrimvar> primvars = mesh_prim_.GetPrimvars();
831 for (pxr::UsdGeomPrimvar p : primvars) {
833 pxr::TfToken
name = p.GetPrimvarName();
834 pxr::SdfValueTypeName
type = p.GetTypeName();
840 pxr::SdfValueTypeNames->TexCoord2hArray,
841 pxr::SdfValueTypeNames->TexCoord2fArray,
842 pxr::SdfValueTypeNames->TexCoord2dArray)) {
852 pxr::TfToken
interp = p.GetInterpolation();
854 if (!(
ELEM(
interp, pxr::UsdGeomTokens->faceVarying, pxr::UsdGeomTokens->vertex))) {
858 uv_tokens.push_back(p.GetBaseName());
862 if (primvar_varying_map_.find(
name) == primvar_varying_map_.end()) {
863 bool might_be_time_varying = p.ValueMightBeTimeVarying();
864 primvar_varying_map_.insert(std::make_pair(
name, might_be_time_varying));
865 if (might_be_time_varying) {
866 is_time_varying_ =
true;
873 Mesh *active_mesh = existing_mesh;
874 bool new_mesh =
false;
885 existing_mesh, positions_.size(), 0, 0, face_indices_.size(), face_counts_.size());
887 for (pxr::TfToken token : uv_tokens) {
893 read_mesh_sample(&settings, active_mesh, motionSampleTime, new_mesh || is_initial_load_);
899 size_t num_polys = active_mesh->
totpoly;
901 std::map<pxr::SdfPath, int> mat_map;
902 assign_facesets_to_mpoly(motionSampleTime, active_mesh->
mpoly, num_polys, &mat_map);
typedef float(TangentPoint)[2]
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_add_layer_named(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem, const char *name)
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
const CustomData_MeshMasks CD_MASK_MESH
General operations, lookup, etc. for materials.
void BKE_object_material_assign_single_obdata(struct Main *bmain, struct Object *ob, struct Material *ma, short act)
float(* BKE_mesh_vertex_normals_for_write(struct Mesh *mesh))[3]
struct Mesh * BKE_mesh_new_nomain_from_template(const struct Mesh *me_src, int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len)
void BKE_mesh_nomain_to_mesh(struct Mesh *mesh_src, struct Mesh *mesh_dst, struct Object *ob, const struct CustomData_MeshMasks *mask, bool take_ownership)
struct Mesh * BKE_mesh_add(struct Main *bmain, const char *name)
void BKE_mesh_vertex_normals_clear_dirty(struct Mesh *mesh)
void BKE_mesh_normals_tag_dirty(struct Mesh *mesh)
void BKE_mesh_set_custom_normals(struct Mesh *mesh, float(*r_custom_loopnors)[3])
void BKE_mesh_calc_edges(struct Mesh *mesh, bool keep_existing_edges, bool select_new_edges)
General operations, lookup, etc. for blender objects.
struct Object * BKE_object_add_only_object(struct Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
#define BLI_assert_unreachable()
#define BLI_STATIC_ASSERT(a, msg)
Object is a sort of wrapper for general info.
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
void add_cache_modifier()
void add_subdiv_modifier()
Material * add_material(const pxr::UsdShadeMaterial &usd_material) const
struct Mesh * read_mesh(struct Mesh *existing_mesh, double motionSampleTime, int read_flag, const char **err_str) override
void read_object_data(Main *bmain, double motionSampleTime) override
void create_object(Main *bmain, double motionSampleTime) override
bool valid() const override
USDMeshReader(const pxr::UsdPrim &prim, const USDImportParams &import_params, const ImportSettings &settings)
bool topology_changed(const Mesh *existing_mesh, double motionSampleTime) override
const ImportSettings * settings_
const USDImportParams & import_params_
const std::string & name() const
ccl_gpu_kernel_postfix int ccl_global int * indices
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
void(* MEM_freeN)(void *vmemh)
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t)
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
static const pxr::TfToken UVMap("UVMap", pxr::TfToken::Immortal)
static const pxr::TfToken normalsPrimvar("normals", pxr::TfToken::Immortal)
static const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal)
static const pxr::TfToken Cd("Cd", pxr::TfToken::Immortal)
static pxr::UsdShadeMaterial compute_bound_material(const pxr::UsdPrim &prim)
static void assign_materials(Main *bmain, Object *ob, const std::map< pxr::SdfPath, int > &mat_index_map, const USDImportParams ¶ms, pxr::UsdStageRefPtr stage, std::map< std::string, Material * > &mat_name_to_mat, std::map< std::string, std::string > &usd_path_to_mat_name)
static Material * find_existing_material(const pxr::SdfPath &usd_mat_path, const USDImportParams ¶ms, const std::map< std::string, Material * > &mat_map, const std::map< std::string, std::string > &usd_path_to_mat_name)
static void build_mat_map(const Main *bmain, std::map< std::string, Material * > *r_mat_map)
struct MLoopCol * mloopcol
std::map< std::string, Material * > mat_name_to_mat
@ USD_MTL_NAME_COLLISION_MAKE_UNIQUE
static void * add_customdata_cb(Mesh *mesh, const char *name, const int data_type)