Blender V4.3
usd_attribute_utils.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4#pragma once
5
6#include "BLI_color.hh"
10#include "BLI_span.hh"
11#include "BLI_virtual_array.hh"
12
13#include "BKE_attribute.hh"
14
16
17#include <pxr/base/gf/quatf.h>
18#include <pxr/base/gf/vec2f.h>
19#include <pxr/base/gf/vec3f.h>
20#include <pxr/base/vt/array.h>
21
22#include <pxr/usd/sdf/types.h>
23#include <pxr/usd/sdf/valueTypeName.h>
24#include <pxr/usd/usd/timeCode.h>
25#include <pxr/usd/usdGeom/primvar.h>
26#include <pxr/usd/usdUtils/sparseValueWriter.h>
27
28#include <cstdint>
29#include <optional>
30#include <type_traits>
31
32namespace usdtokens {
33inline const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal);
34}
35
36namespace blender::io::usd {
37
38namespace detail {
39
40/* Until we can use C++20, implement our own version of std::is_layout_compatible.
41 * Types with compatible layouts can be exchanged much more efficiently than otherwise.
42 */
43template<class T, class U> struct is_layout_compatible : std::false_type {};
44
45template<> struct is_layout_compatible<float2, pxr::GfVec2f> : std::true_type {};
46template<> struct is_layout_compatible<float3, pxr::GfVec3f> : std::true_type {};
47
48template<> struct is_layout_compatible<pxr::GfVec2f, float2> : std::true_type {};
49template<> struct is_layout_compatible<pxr::GfVec3f, float3> : std::true_type {};
50
51/* Conversion utilities to convert a Blender type to an USD type. */
52template<typename From, typename To> inline To convert_value(const From value)
53{
54 return value;
55}
56
57template<> inline pxr::GfVec2f convert_value(const float2 value)
58{
59 return pxr::GfVec2f(value[0], value[1]);
60}
61template<> inline pxr::GfVec3f convert_value(const float3 value)
62{
63 return pxr::GfVec3f(value[0], value[1], value[2]);
64}
65template<> inline pxr::GfVec3f convert_value(const ColorGeometry4f value)
66{
67 return pxr::GfVec3f(value.r, value.g, value.b);
68}
69template<> inline pxr::GfVec4f convert_value(const ColorGeometry4f value)
70{
71 return pxr::GfVec4f(value.r, value.g, value.b, value.a);
72}
73template<> inline pxr::GfVec3f convert_value(const ColorGeometry4b value)
74{
75 ColorGeometry4f color4f = value.decode();
76 return pxr::GfVec3f(color4f.r, color4f.g, color4f.b);
77}
78template<> inline pxr::GfVec4f convert_value(const ColorGeometry4b value)
79{
80 ColorGeometry4f color4f = value.decode();
81 return pxr::GfVec4f(color4f.r, color4f.g, color4f.b, color4f.a);
82}
83template<> inline pxr::GfQuatf convert_value(const math::Quaternion value)
84{
85 return pxr::GfQuatf(value.w, value.x, value.y, value.z);
86}
87
88template<> inline float2 convert_value(const pxr::GfVec2f value)
89{
90 return float2(value[0], value[1]);
91}
92template<> inline float3 convert_value(const pxr::GfVec3f value)
93{
94 return float3(value[0], value[1], value[2]);
95}
96template<> inline ColorGeometry4f convert_value(const pxr::GfVec3f value)
97{
98 return ColorGeometry4f(value[0], value[1], value[2], 1.0f);
99}
100template<> inline ColorGeometry4f convert_value(const pxr::GfVec4f value)
101{
102 return ColorGeometry4f(value[0], value[1], value[2], value[3]);
103}
104template<> inline math::Quaternion convert_value(const pxr::GfQuatf value)
105{
106 const pxr::GfVec3f &img = value.GetImaginary();
107 return math::Quaternion(value.GetReal(), img[0], img[1], img[2]);
108}
109
110} // namespace detail
111
112std::optional<pxr::SdfValueTypeName> convert_blender_type_to_usd(
113 const eCustomDataType blender_type, bool use_color3f_type = false);
114
115std::optional<eCustomDataType> convert_usd_type_to_blender(const pxr::SdfValueTypeName usd_type);
116
117/* Copy a typed Blender attribute array into a typed USD primvar attribute. */
118template<typename BlenderT, typename USDT>
120 const pxr::UsdTimeCode timecode,
121 const pxr::UsdGeomPrimvar &primvar,
122 pxr::UsdUtilsSparseValueWriter &value_writer)
123{
124 constexpr bool is_same = std::is_same_v<BlenderT, USDT>;
125 constexpr bool is_compatible = detail::is_layout_compatible<BlenderT, USDT>::value;
126
127 pxr::VtArray<USDT> usd_data;
128 if (const std::optional<BlenderT> value = buffer.get_if_single()) {
129 usd_data.assign(buffer.size(), detail::convert_value<BlenderT, USDT>(*value));
130 }
131 else {
132 const VArraySpan<BlenderT> data(buffer);
133 if constexpr (is_same || is_compatible) {
134 usd_data.assign(data.template cast<USDT>().begin(), data.template cast<USDT>().end());
135 }
136 else {
137 usd_data.resize(data.size());
138 for (const int i : data.index_range()) {
140 }
141 }
142 }
143
144 if (!primvar.HasValue()) {
145 primvar.Set(usd_data, pxr::UsdTimeCode::Default());
146 }
147
148 value_writer.SetAttribute(primvar.GetAttr(), usd_data, timecode);
149}
150
152 const eCustomDataType data_type,
153 const pxr::UsdTimeCode timecode,
154 const pxr::UsdGeomPrimvar &primvar,
155 pxr::UsdUtilsSparseValueWriter &value_writer);
156
157template<typename T>
158pxr::VtArray<T> get_primvar_array(const pxr::UsdGeomPrimvar &primvar,
159 const pxr::UsdTimeCode timecode)
160{
161 pxr::VtValue primvar_val;
162 if (!primvar.ComputeFlattened(&primvar_val, timecode)) {
163 return {};
164 }
165
166 if (!primvar_val.CanCast<pxr::VtArray<T>>()) {
167 return {};
168 }
169
170 return primvar_val.Cast<pxr::VtArray<T>>().template UncheckedGet<pxr::VtArray<T>>();
171}
172
173template<typename USDT, typename BlenderT>
174void copy_primvar_to_blender_buffer(const pxr::UsdGeomPrimvar &primvar,
175 const pxr::UsdTimeCode timecode,
178{
179 pxr::VtArray<USDT> usd_data = get_primvar_array<USDT>(primvar, timecode);
180 if (usd_data.empty()) {
181 return;
182 }
183
184 constexpr bool is_same = std::is_same_v<USDT, BlenderT>;
185 constexpr bool is_compatible = detail::is_layout_compatible<USDT, BlenderT>::value;
186
187 const pxr::TfToken pv_interp = primvar.GetInterpolation();
188 if (pv_interp == pxr::UsdGeomTokens->constant) {
189 /* For situations where there's only a single item, flood fill the object. */
191 }
192 else if (pv_interp == pxr::UsdGeomTokens->faceVarying) {
193 if (!faces.is_empty()) {
194 /* Reverse the index order. */
195 for (const int i : faces.index_range()) {
196 const IndexRange face = faces[i];
197 for (int j : face.index_range()) {
198 const int rev_index = face.last(j);
199 attribute[face.start() + j] = detail::convert_value<USDT, BlenderT>(usd_data[rev_index]);
200 }
201 }
202 }
203 else {
204 if constexpr (is_same || is_compatible) {
205 const Span<USDT> src(usd_data.data(), usd_data.size());
206 attribute.copy_from(src.template cast<BlenderT>());
207 }
208 else {
209 for (const int64_t i : attribute.index_range()) {
211 }
212 }
213 }
214 }
215 else {
216 /* Assume direct one-to-one mapping. */
217 if (usd_data.size() == attribute.size()) {
218 if constexpr (is_same || is_compatible) {
219 const Span<USDT> src(usd_data.data(), usd_data.size());
220 attribute.copy_from(src.template cast<BlenderT>());
221 }
222 else {
223 for (const int64_t i : attribute.index_range()) {
225 }
226 }
227 }
228 }
229}
230
231void copy_primvar_to_blender_attribute(const pxr::UsdGeomPrimvar &primvar,
232 const pxr::UsdTimeCode timecode,
233 const eCustomDataType data_type,
234 const bke::AttrDomain domain,
235 const OffsetIndices<int> face_indices,
237
238} // namespace blender::io::usd
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
ChannelStorageType r
Definition BLI_color.hh:88
ChannelStorageType g
Definition BLI_color.hh:88
ChannelStorageType b
Definition BLI_color.hh:88
ChannelStorageType a
Definition BLI_color.hh:88
ColorSceneLinear4f< Alpha > decode() const
Definition BLI_color.hh:224
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t start() const
constexpr IndexRange index_range() const
std::optional< T > get_if_single() const
ccl_device_inline int4 cast(const float4 a)
Definition math_float4.h:29
static char faces[256]
To convert_value(const From value)
pxr::VtArray< T > get_primvar_array(const pxr::UsdGeomPrimvar &primvar, const pxr::UsdTimeCode timecode)
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)
void copy_primvar_to_blender_buffer(const pxr::UsdGeomPrimvar &primvar, const pxr::UsdTimeCode timecode, const OffsetIndices< int > faces, MutableSpan< BlenderT > attribute)
std::optional< eCustomDataType > convert_usd_type_to_blender(const pxr::SdfValueTypeName usd_type)
std::optional< pxr::SdfValueTypeName > convert_blender_type_to_usd(const eCustomDataType blender_type, bool use_color3f_type)
void copy_blender_buffer_to_primvar(const VArray< BlenderT > &buffer, const pxr::UsdTimeCode timecode, const pxr::UsdGeomPrimvar &primvar, pxr::UsdUtilsSparseValueWriter &value_writer)
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)
QuaternionBase< float > Quaternion
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:337
VecBase< float, 3 > float3
ColorSceneLinearByteEncoded4b< eAlpha::Premultiplied > ColorGeometry4b
Definition BLI_color.hh:338
const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal)
__int64 int64_t
Definition stdint.h:89