Blender V4.3
usd_mesh_utils.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "usd_mesh_utils.hh"
7#include "usd_hash_types.hh"
8
9#include "BKE_attribute.hh"
10
11#include "DNA_mesh_types.h"
12
13#include "CLG_log.h"
14static CLG_LogRef LOG = {"io.usd"};
15
16namespace blender::io::usd {
17
18template<typename USDT>
19static void read_face_display_color(Mesh *mesh,
20 const pxr::UsdGeomPrimvar &primvar,
21 const pxr::TfToken &pv_name,
22 double motion_sample_time)
23{
24 const pxr::VtArray<USDT> usd_colors = get_primvar_array<USDT>(primvar, motion_sample_time);
25 if (usd_colors.empty()) {
26 return;
27 }
28
29 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
30 const bke::AttrDomain color_domain = bke::AttrDomain::Corner;
31
32 const StringRef attr_name(pv_name.GetString());
34 attributes.lookup_or_add_for_write_only_span<ColorGeometry4f>(attr_name, color_domain);
35 if (!color_data) {
36 CLOG_WARN(&LOG, "Primvar '%s' could not be added to Blender", primvar.GetBaseName().GetText());
37 return;
38 }
39
40 const OffsetIndices faces = mesh->faces();
41 for (const int i : faces.index_range()) {
42 if (i >= usd_colors.size()) {
43 break;
44 }
45
46 /* Take the per-face USD color and place it on each face-corner. */
47 const IndexRange face = faces[i];
48 for (const int j : face.index_range()) {
49 const int corner = face.start() + j;
50 color_data.span[corner] = detail::convert_value<USDT, ColorGeometry4f>(usd_colors[i]);
51 }
52 }
53
54 color_data.finish();
55}
56
57static std::optional<bke::AttrDomain> convert_usd_varying_to_blender(const pxr::TfToken usd_domain)
58{
59 static const blender::Map<pxr::TfToken, bke::AttrDomain> domain_map = []() {
61 map.add_new(pxr::UsdGeomTokens->faceVarying, bke::AttrDomain::Corner);
62 map.add_new(pxr::UsdGeomTokens->vertex, bke::AttrDomain::Point);
63 map.add_new(pxr::UsdGeomTokens->varying, bke::AttrDomain::Point);
64 map.add_new(pxr::UsdGeomTokens->face, bke::AttrDomain::Face);
65 /* As there's no "constant" type in Blender, for now we're
66 * translating into a point Attribute. */
67 map.add_new(pxr::UsdGeomTokens->constant, bke::AttrDomain::Point);
68 map.add_new(pxr::UsdGeomTokens->uniform, bke::AttrDomain::Face);
69 /* Notice: Edge types are not supported! */
70 return map;
71 }();
72
73 const bke::AttrDomain *value = domain_map.lookup_ptr(usd_domain);
74
75 if (value == nullptr) {
76 return std::nullopt;
77 }
78
79 return *value;
80}
81
83 const pxr::UsdGeomPrimvar &primvar,
84 const double motionSampleTime,
85 const bool is_left_handed)
86{
87 const pxr::SdfValueTypeName pv_type = primvar.GetTypeName();
88 const pxr::TfToken pv_interp = primvar.GetInterpolation();
89 const pxr::TfToken pv_name = pxr::UsdGeomPrimvar::StripPrimvarsName(primvar.GetPrimvarName());
90
91 const std::optional<bke::AttrDomain> domain = convert_usd_varying_to_blender(pv_interp);
92 const std::optional<eCustomDataType> type = convert_usd_type_to_blender(pv_type);
93
94 if (!domain.has_value() || !type.has_value()) {
96 "Primvar '%s' (interpolation %s, type %s) cannot be converted to Blender",
97 pv_name.GetText(),
98 pv_interp.GetText(),
99 pv_type.GetAsToken().GetText());
100 return;
101 }
102
103 /* Blender does not currently support displaying Face colors with the Viewport Shading
104 * "Attribute" color type. Make a special case for "displayColor" primvars and put them on
105 * the Corner domain instead. */
106 if (pv_name == usdtokens::displayColor && domain == bke::AttrDomain::Face) {
107 if (ELEM(pv_type,
108 pxr::SdfValueTypeNames->Color3fArray,
109 pxr::SdfValueTypeNames->Color3hArray,
110 pxr::SdfValueTypeNames->Color3dArray))
111 {
112 read_face_display_color<pxr::GfVec3f>(mesh, primvar, pv_name, motionSampleTime);
113 }
114 else {
115 read_face_display_color<pxr::GfVec4f>(mesh, primvar, pv_name, motionSampleTime);
116 }
117
118 return;
119 }
120
122 if (is_left_handed) {
123 faces = mesh->faces();
124 }
125
126 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
127 copy_primvar_to_blender_attribute(primvar, motionSampleTime, *type, *domain, faces, attributes);
128}
129
130} // namespace blender::io::usd
#define ELEM(...)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
constexpr int64_t start() const
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:484
void add_new(const Key &key, const Value &value)
Definition BLI_map.hh:241
#define LOG(severity)
Definition log.h:33
static char faces[256]
To convert_value(const From value)
pxr::VtArray< T > get_primvar_array(const pxr::UsdGeomPrimvar &primvar, const pxr::UsdTimeCode timecode)
static std::optional< bke::AttrDomain > convert_usd_varying_to_blender(const pxr::TfToken usd_domain)
static void read_face_display_color(Mesh *mesh, const pxr::UsdGeomPrimvar &primvar, const pxr::TfToken &pv_name, double motion_sample_time)
std::optional< eCustomDataType > convert_usd_type_to_blender(const pxr::SdfValueTypeName usd_type)
void read_generic_mesh_primvar(Mesh *mesh, const pxr::UsdGeomPrimvar &primvar, const double motionSampleTime, const bool is_left_handed)
void copy_primvar_to_blender_attribute(const pxr::UsdGeomPrimvar &primvar, const pxr::UsdTimeCode timecode, const eCustomDataType data_type, const bke::AttrDomain domain, const OffsetIndices< int > face_indices, bke::MutableAttributeAccessor attributes)
const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal)
static CLG_LogRef LOG