8#include <pxr/usd/usdGeom/basisCurves.h>
9#include <pxr/usd/usdGeom/curves.h>
10#include <pxr/usd/usdGeom/nurbsCurves.h>
11#include <pxr/usd/usdGeom/primvar.h>
12#include <pxr/usd/usdGeom/primvarsAPI.h>
13#include <pxr/usd/usdGeom/tokens.h>
14#include <pxr/usd/usdShade/material.h>
15#include <pxr/usd/usdShade/materialBindingAPI.h>
41pxr::UsdGeomBasisCurves USDCurvesWriter::DefineUsdGeomBasisCurves(pxr::VtValue curve_basis,
43 const bool is_cubic)
const
45 pxr::UsdGeomBasisCurves basis_curves = pxr::UsdGeomBasisCurves::Define(
50 basis_curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->cubic));
51 basis_curves.CreateBasisAttr(curve_basis);
54 basis_curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->linear));
58 basis_curves.CreateWrapAttr(pxr::VtValue(pxr::UsdGeomTokens->periodic));
60 else if (curve_basis == pxr::VtValue(pxr::UsdGeomTokens->catmullRom)) {
65 basis_curves.CreateWrapAttr(pxr::VtValue(pxr::UsdGeomTokens->pinned));
68 basis_curves.CreateWrapAttr(pxr::VtValue(pxr::UsdGeomTokens->nonperiodic));
80 widths.resize(radii.
varray.size());
82 for (
const int i : radii.
varray.index_range()) {
83 widths[i] = radii.
varray[i] * 2.0f;
88 const pxr::VtArray<int> &segments,
89 const pxr::VtIntArray &control_point_counts,
94 return pxr::TfToken();
97 const size_t accumulated_control_point_count = std::accumulate(
98 control_point_counts.begin(), control_point_counts.end(), 0);
103 if (widths.size() == accumulated_control_point_count) {
104 return pxr::UsdGeomTokens->vertex;
107 size_t expectedVaryingSize = std::accumulate(segments.begin(), segments.end(), 0);
109 expectedVaryingSize += control_point_counts.size();
112 if (widths.size() == expectedVaryingSize) {
113 return pxr::UsdGeomTokens->varying;
117 return pxr::TfToken();
122 pxr::VtArray<pxr::GfVec3f> &
verts,
123 pxr::VtIntArray &control_point_counts,
124 pxr::VtArray<int> &segments,
131 const IndexRange points = points_by_curve[i_curve];
132 for (
const int i_point : points) {
134 pxr::GfVec3f(positions[i_point][0], positions[i_point][1], positions[i_point][2]));
137 const int tot_points = points.
size();
138 control_point_counts[i_curve] = tot_points;
147 segments[i_curve] = tot_points;
150 segments[i_curve] = (tot_points - 4) + 1;
153 segments[i_curve] = tot_points - 1;
159 pxr::VtArray<pxr::GfVec3f> &
verts,
160 pxr::VtIntArray &control_point_counts,
161 pxr::VtArray<float> &widths,
162 pxr::TfToken &interpolation,
170 pxr::VtArray<int> segments(num_curves);
173 curves, positions,
verts, control_point_counts, segments,
is_cyclic, is_cubic);
177 widths, segments, control_point_counts,
is_cyclic, reports);
184 pxr::VtArray<pxr::GfVec3f> &
verts,
185 pxr::VtIntArray &control_point_counts,
186 pxr::VtArray<int> &segments,
189 const int bezier_vstep = 3;
194 const IndexRange points = points_by_curve[i_curve];
195 const int start_point_index = points[0];
196 const int last_point_index = points[points.
size() - 1];
198 const int start_verts_count =
verts.size();
200 for (
int i_point = start_point_index; i_point < last_point_index; i_point++) {
207 pxr::GfVec3f(positions[i_point][0], positions[i_point][1], positions[i_point][2]));
210 verts.push_back(pxr::GfVec3f(right_handle[0], right_handle[1], right_handle[2]));
213 verts.push_back(pxr::GfVec3f(left_handle[0], left_handle[1], left_handle[2]));
216 verts.push_back(pxr::GfVec3f(positions[last_point_index][0],
217 positions[last_point_index][1],
218 positions[last_point_index][2]));
225 verts.push_back(pxr::GfVec3f(right_handle[0], right_handle[1], right_handle[2]));
228 verts.push_back(pxr::GfVec3f(left_handle[0], left_handle[1], left_handle[2]));
231 const int tot_points =
verts.size() - start_verts_count;
232 control_point_counts[i_curve] = tot_points;
235 segments[i_curve] = tot_points / bezier_vstep;
238 segments[i_curve] = ((tot_points - 4) / bezier_vstep) + 1;
244 pxr::VtArray<pxr::GfVec3f> &
verts,
245 pxr::VtIntArray &control_point_counts,
246 pxr::VtArray<float> &widths,
247 pxr::TfToken &interpolation,
257 pxr::VtArray<int> segments(num_curves);
260 curves, positions, handles_l, handles_r,
verts, control_point_counts, segments,
is_cyclic);
264 widths, segments, control_point_counts,
is_cyclic, reports);
268 pxr::VtArray<pxr::GfVec3f> &
verts,
269 pxr::VtIntArray &control_point_counts,
270 pxr::VtArray<float> &widths,
271 pxr::VtArray<double> &knots,
272 pxr::VtArray<int> &orders,
273 pxr::TfToken &interpolation,
279 orders.resize(num_curves);
288 const IndexRange points = points_by_curve[i_curve];
289 for (
const int i_point : points) {
291 pxr::GfVec3f(positions[i_point][0], positions[i_point][1], positions[i_point][2]));
294 const int tot_points = points.
size();
295 control_point_counts[i_curve] = tot_points;
297 const int8_t order = geom_orders[i_curve];
298 orders[i_curve] =
int(geom_orders[i_curve]);
308 for (
int i_knot = 0; i_knot < knots_num; i_knot++) {
309 knots.push_back(
double(temp_knots[i_knot]));
314 int zeroth_knot_index = knots.size() - knots_num;
316 knots[zeroth_knot_index] = knots[zeroth_knot_index + 1] -
317 (knots[knots.size() - 2] - knots[knots.size() - 3]);
318 knots[knots.size() - 1] = knots[knots.size() - 2] +
319 (knots[zeroth_knot_index + 2] - knots[zeroth_knot_index + 1]);
322 knots[zeroth_knot_index] = knots[zeroth_knot_index + 1];
323 knots[knots.size() - 1] = knots[knots.size() - 2];
328 interpolation = pxr::UsdGeomTokens->vertex;
331void USDCurvesWriter::set_writer_attributes_for_nurbs(
332 const pxr::UsdGeomNurbsCurves &usd_nurbs_curves,
333 const pxr::VtArray<double> &knots,
334 const pxr::VtArray<int> &orders,
335 const pxr::UsdTimeCode timecode)
337 pxr::UsdAttribute attr_knots = usd_nurbs_curves.CreateKnotsAttr(pxr::VtValue(),
true);
339 pxr::UsdAttribute attr_order = usd_nurbs_curves.CreateOrderAttr(pxr::VtValue(),
true);
343void USDCurvesWriter::set_writer_attributes(pxr::UsdGeomCurves &usd_curves,
344 const pxr::VtArray<pxr::GfVec3f> &
verts,
345 const pxr::VtIntArray &control_point_counts,
346 const pxr::VtArray<float> &widths,
347 const pxr::UsdTimeCode timecode,
348 const pxr::TfToken interpolation)
350 pxr::UsdAttribute attr_points = usd_curves.CreatePointsAttr(pxr::VtValue(),
true);
353 pxr::UsdAttribute attr_vertex_counts = usd_curves.CreateCurveVertexCountsAttr(pxr::VtValue(),
355 usd_value_writer_.SetAttribute(attr_vertex_counts, pxr::VtValue(control_point_counts), timecode);
357 if (!widths.empty()) {
358 pxr::UsdAttribute attr_widths = usd_curves.CreateWidthsAttr(pxr::VtValue(),
true);
361 usd_curves.SetWidthsInterpolation(interpolation);
368 switch (blender_domain) {
370 return is_bezier ? pxr::UsdGeomTokens->varying : pxr::UsdGeomTokens->vertex;
372 return pxr::UsdGeomTokens->uniform;
381 const pxr::UsdGeomCurves &usd_curves)
390 if (!pv_interp || !pv_type) {
393 "Attribute '%s' (Blender domain %d, type %d) cannot be converted to USD",
406 const pxr::TfToken pv_name(
408 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_curves);
410 pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type, *pv_interp);
416void USDCurvesWriter::write_uv_data(
const bke::AttributeIter &attr,
417 const pxr::UsdGeomCurves &usd_curves)
425 const pxr::TfToken pv_name(
427 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_curves);
429 pxr::UsdGeomPrimvar pv_uv = pv_api.CreatePrimvar(
430 pv_name, pxr::SdfValueTypeNames->TexCoord2fArray, pxr::UsdGeomTokens->uniform);
435void USDCurvesWriter::write_custom_data(
const bke::CurvesGeometry &curves,
436 const pxr::UsdGeomCurves &usd_curves)
438 const bke::AttributeAccessor attributes = curves.attributes();
440 attributes.foreach_attribute([&](
const bke::AttributeIter &iter) {
452 "handle_type_right"))
460 this->write_uv_data(iter, usd_curves);
466 this->write_generic_data(curves, iter, usd_curves);
474 std::unique_ptr<
Curves, std::function<void(
Curves *)>> converted_curves;
476 switch (context.object->type) {
478 const Curve *legacy_curve =
static_cast<Curve *
>(context.object->data);
479 converted_curves = std::unique_ptr<
Curves, std::function<void(
Curves *)>>(
481 curves_id = converted_curves.get();
485 curves_id =
static_cast<Curves *
>(context.object->data);
497 const std::array<int, CURVE_TYPES_NUM> &curve_type_counts = curves.
curve_type_counts();
498 const int number_of_curve_types = std::count_if(curve_type_counts.begin(),
499 curve_type_counts.end(),
500 [](
const int count) { return count > 0; });
501 if (number_of_curve_types > 1) {
510 "Cannot export mixed cyclic and non-cyclic curves in the same Curves object");
517 if (first_frame_curve_type == -1) {
518 first_frame_curve_type = curve_type;
520 else if (first_frame_curve_type != curve_type) {
521 const char *first_frame_curve_type_name =
nullptr;
525 const char *current_curve_type_name =
nullptr;
531 "USD does not support animating curve types. The curve type changes from %s to "
533 IFACE_(first_frame_curve_type_name),
534 IFACE_(current_curve_type_name),
535 timecode.GetValue());
540 pxr::VtArray<pxr::GfVec3f>
verts;
541 pxr::VtIntArray control_point_counts;
542 pxr::VtArray<float> widths;
543 pxr::TfToken interpolation;
545 pxr::UsdGeomBasisCurves usd_basis_curves;
546 pxr::UsdGeomNurbsCurves usd_nurbs_curves;
547 pxr::UsdGeomCurves *usd_curves =
nullptr;
549 control_point_counts.resize(curves.
curves_num());
550 switch (curve_type) {
552 usd_basis_curves = DefineUsdGeomBasisCurves(pxr::VtValue(),
is_cyclic,
false);
553 usd_curves = &usd_basis_curves;
559 usd_basis_curves = DefineUsdGeomBasisCurves(
560 pxr::VtValue(pxr::UsdGeomTokens->catmullRom),
is_cyclic,
true);
561 usd_curves = &usd_basis_curves;
567 usd_basis_curves = DefineUsdGeomBasisCurves(
568 pxr::VtValue(pxr::UsdGeomTokens->bezier),
is_cyclic,
true);
569 usd_curves = &usd_basis_curves;
575 pxr::VtArray<double> knots;
576 pxr::VtArray<int> orders;
581 usd_curves = &usd_nurbs_curves;
584 curves,
verts, control_point_counts, widths, knots, orders, interpolation,
is_cyclic);
586 set_writer_attributes_for_nurbs(usd_nurbs_curves, knots, orders, timecode);
594 set_writer_attributes(*usd_curves,
verts, control_point_counts, widths, timecode, interpolation);
598 write_custom_data(curves, *usd_curves);
600 auto prim = usd_curves->GetPrim();
605 const pxr::UsdGeomCurves &usd_curves)
607 if (context.object->totcol == 0) {
611 bool curve_material_bound =
false;
612 for (
short mat_num = 0; mat_num < context.object->totcol; mat_num++) {
614 if (material ==
nullptr) {
618 pxr::UsdPrim curve_prim = usd_curves.GetPrim();
619 pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(curve_prim);
621 api.Bind(usd_material);
622 pxr::UsdShadeMaterialBindingAPI::Apply(curve_prim);
626 usd_curves.CreateDoubleSidedAttr(
629 curve_material_bound =
true;
633 if (!curve_material_bound) {
635 usd_curves.CreateDoubleSidedAttr(pxr::VtValue(
true));
Low-level operations for curves.
void BKE_id_free(Main *bmain, void *idv)
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_assert_unreachable()
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
constexpr int64_t size() const
constexpr const char * c_str() const
GAttributeReader lookup(const StringRef attribute_id) const
eCustomDataType data_type
GAttributeReader get() const
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
const std::array< int, CURVE_TYPES_NUM > & curve_type_counts() const
Span< float3 > handle_positions_left() const
VArray< int8_t > nurbs_knots_modes() const
Span< float3 > positions() const
Span< float3 > handle_positions_right() const
AttributeAccessor attributes() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
VArray< int8_t > nurbs_orders() const
pxr::UsdShadeMaterial ensure_usd_material(const HierarchyContext &context, Material *material) const
ReportList * reports() const
pxr::UsdTimeCode get_export_time_code() const
pxr::UsdUtilsSparseValueWriter usd_value_writer_
void write_id_properties(const pxr::UsdPrim &prim, const ID &id, pxr::UsdTimeCode=pxr::UsdTimeCode::Default()) const
const USDExporterContext usd_export_context_
virtual void do_write(HierarchyContext &context) override
void assign_materials(const HierarchyContext &context, const pxr::UsdGeomCurves &usd_curves)
static bool is_cyclic(const Nurb *nu)
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
BooleanMix booleans_mix_calc(const VArray< bool > &varray, IndexRange range_to_check)
void calculate_knots(int points_num, KnotsMode mode, int8_t order, bool cyclic, MutableSpan< float > knots)
int knots_num(int points_num, int8_t order, bool cyclic)
bool attribute_name_is_anonymous(const StringRef name)
Curves * curve_legacy_to_curves(const Curve &curve_legacy)
static pxr::TfToken get_curve_width_interpolation(const pxr::VtArray< float > &widths, const pxr::VtArray< int > &segments, const pxr::VtIntArray &control_point_counts, const bool is_cyclic, ReportList *reports)
static void populate_curve_props_for_nurbs(const bke::CurvesGeometry &curves, pxr::VtArray< pxr::GfVec3f > &verts, pxr::VtIntArray &control_point_counts, pxr::VtArray< float > &widths, pxr::VtArray< double > &knots, pxr::VtArray< int > &orders, pxr::TfToken &interpolation, const bool is_cyclic)
static void populate_curve_props_for_bezier(const bke::CurvesGeometry &curves, pxr::VtArray< pxr::GfVec3f > &verts, pxr::VtIntArray &control_point_counts, pxr::VtArray< float > &widths, pxr::TfToken &interpolation, const bool is_cyclic, ReportList *reports)
std::string make_safe_name(const std::string &name, bool allow_unicode)
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)
static void populate_curve_verts(const bke::CurvesGeometry &curves, const Span< float3 > positions, pxr::VtArray< pxr::GfVec3f > &verts, pxr::VtIntArray &control_point_counts, pxr::VtArray< int > &segments, const bool is_cyclic, const bool is_cubic)
static void populate_curve_props(const bke::CurvesGeometry &curves, pxr::VtArray< pxr::GfVec3f > &verts, pxr::VtIntArray &control_point_counts, pxr::VtArray< float > &widths, pxr::TfToken &interpolation, const bool is_cyclic, const bool is_cubic, ReportList *reports)
static void populate_curve_verts_for_bezier(const bke::CurvesGeometry &curves, const Span< float3 > positions, const Span< float3 > handles_l, const Span< float3 > handles_r, pxr::VtArray< pxr::GfVec3f > &verts, pxr::VtIntArray &control_point_counts, pxr::VtArray< int > &segments, const bool is_cyclic)
static void populate_curve_widths(const bke::CurvesGeometry &curves, pxr::VtArray< float > &widths)
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)
VecBase< float, 2 > float2
VecBase< float, 3 > float3
bool RNA_enum_name_from_value(const EnumPropertyItem *item, int value, const char **r_name)
const EnumPropertyItem rna_enum_curves_type_items[]
const USDExportParams & export_params