Blender V4.3
usd_writer_curves.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <numeric>
6#include <string>
7
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>
16
19#include "usd_utils.hh"
20#include "usd_writer_curves.hh"
21
22#include "BLI_array_utils.hh"
24#include "BLI_span.hh"
25#include "BLI_virtual_array.hh"
26
27#include "BKE_attribute.hh"
29#include "BKE_curves.hh"
30#include "BKE_lib_id.hh"
31#include "BKE_material.h"
32#include "BKE_report.hh"
33
34#include "BLT_translation.hh"
35
36#include "RNA_access.hh"
37#include "RNA_enum_types.hh"
38
39namespace blender::io::usd {
40
41pxr::UsdGeomBasisCurves USDCurvesWriter::DefineUsdGeomBasisCurves(pxr::VtValue curve_basis,
42 const bool is_cyclic,
43 const bool is_cubic) const
44{
45 pxr::UsdGeomBasisCurves basis_curves = pxr::UsdGeomBasisCurves::Define(
47 /* Not required to set the basis attribute for linear curves
48 * https://graphics.pixar.com/usd/dev/api/class_usd_geom_basis_curves.html#details */
49 if (is_cubic) {
50 basis_curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->cubic));
51 basis_curves.CreateBasisAttr(curve_basis);
52 }
53 else {
54 basis_curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->linear));
55 }
56
57 if (is_cyclic) {
58 basis_curves.CreateWrapAttr(pxr::VtValue(pxr::UsdGeomTokens->periodic));
59 }
60 else if (curve_basis == pxr::VtValue(pxr::UsdGeomTokens->catmullRom)) {
61 /* In Blender the first and last points are treated as endpoints. The pinned attribute tells
62 * the client that to evaluate or render the curve, it must effectively add 'phantom
63 * points' at the beginning and end of every curve in a batch. These phantom points are
64 * injected to ensure that the interpolated curve begins at P[0] and ends at P[n-1]. */
65 basis_curves.CreateWrapAttr(pxr::VtValue(pxr::UsdGeomTokens->pinned));
66 }
67 else {
68 basis_curves.CreateWrapAttr(pxr::VtValue(pxr::UsdGeomTokens->nonperiodic));
69 }
70
71 return basis_curves;
72}
73
74static void populate_curve_widths(const bke::CurvesGeometry &curves, pxr::VtArray<float> &widths)
75{
76 const bke::AttributeAccessor curve_attributes = curves.attributes();
77 const bke::AttributeReader<float> radii = curve_attributes.lookup<float>("radius",
79
80 widths.resize(radii.varray.size());
81
82 for (const int i : radii.varray.index_range()) {
83 widths[i] = radii.varray[i] * 2.0f;
84 }
85}
86
87static pxr::TfToken get_curve_width_interpolation(const pxr::VtArray<float> &widths,
88 const pxr::VtArray<int> &segments,
89 const pxr::VtIntArray &control_point_counts,
90 const bool is_cyclic,
91 ReportList *reports)
92{
93 if (widths.empty()) {
94 return pxr::TfToken();
95 }
96
97 const size_t accumulated_control_point_count = std::accumulate(
98 control_point_counts.begin(), control_point_counts.end(), 0);
99
100 /* For Blender curves, radii are always stored per point. For linear curves, this should match
101 * with USD's vertex interpolation. For cubic curves, this should match with USD's varying
102 * interpolation. */
103 if (widths.size() == accumulated_control_point_count) {
104 return pxr::UsdGeomTokens->vertex;
105 }
106
107 size_t expectedVaryingSize = std::accumulate(segments.begin(), segments.end(), 0);
108 if (!is_cyclic) {
109 expectedVaryingSize += control_point_counts.size();
110 }
111
112 if (widths.size() == expectedVaryingSize) {
113 return pxr::UsdGeomTokens->varying;
114 }
115
116 BKE_report(reports, RPT_WARNING, "Curve width size not supported for USD interpolation");
117 return pxr::TfToken();
118}
119
121 const Span<float3> positions,
122 pxr::VtArray<pxr::GfVec3f> &verts,
123 pxr::VtIntArray &control_point_counts,
124 pxr::VtArray<int> &segments,
125 const bool is_cyclic,
126 const bool is_cubic)
127{
128 const OffsetIndices points_by_curve = curves.points_by_curve();
129 for (const int i_curve : curves.curves_range()) {
130
131 const IndexRange points = points_by_curve[i_curve];
132 for (const int i_point : points) {
133 verts.push_back(
134 pxr::GfVec3f(positions[i_point][0], positions[i_point][1], positions[i_point][2]));
135 }
136
137 const int tot_points = points.size();
138 control_point_counts[i_curve] = tot_points;
139
140 /* For periodic linear curve, segment count = curveVertexCount.
141 * For periodic cubic curve, segment count = curveVertexCount / vstep.
142 * For nonperiodic linear curve, segment count = curveVertexCount - 1.
143 * For nonperiodic cubic curve, segment count = ((curveVertexCount - 4) / vstep) + 1.
144 * This function handles linear and Catmull-Rom curves. For Catmull-Rom, vstep is 1.
145 * https://graphics.pixar.com/usd/dev/api/class_usd_geom_basis_curves.html */
146 if (is_cyclic) {
147 segments[i_curve] = tot_points;
148 }
149 else if (is_cubic) {
150 segments[i_curve] = (tot_points - 4) + 1;
151 }
152 else {
153 segments[i_curve] = tot_points - 1;
154 }
155 }
156}
157
159 pxr::VtArray<pxr::GfVec3f> &verts,
160 pxr::VtIntArray &control_point_counts,
161 pxr::VtArray<float> &widths,
162 pxr::TfToken &interpolation,
163 const bool is_cyclic,
164 const bool is_cubic,
165 ReportList *reports)
166{
167 const int num_curves = curves.curve_num;
168 const Span<float3> positions = curves.positions();
169
170 pxr::VtArray<int> segments(num_curves);
171
173 curves, positions, verts, control_point_counts, segments, is_cyclic, is_cubic);
174
175 populate_curve_widths(curves, widths);
176 interpolation = get_curve_width_interpolation(
177 widths, segments, control_point_counts, is_cyclic, reports);
178}
179
181 const Span<float3> positions,
182 const Span<float3> handles_l,
183 const Span<float3> handles_r,
184 pxr::VtArray<pxr::GfVec3f> &verts,
185 pxr::VtIntArray &control_point_counts,
186 pxr::VtArray<int> &segments,
187 const bool is_cyclic)
188{
189 const int bezier_vstep = 3;
190 const OffsetIndices points_by_curve = curves.points_by_curve();
191
192 for (const int i_curve : curves.curves_range()) {
193
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];
197
198 const int start_verts_count = verts.size();
199
200 for (int i_point = start_point_index; i_point < last_point_index; i_point++) {
201
202 /* The order verts in the USD bezier curve representation is [control point 0, right handle
203 * 0, left handle 1, control point 1, right handle 1, left handle 2, control point 2, ...].
204 * The last vert in the array doesn't need a right handle because the curve stops at that
205 * point. */
206 verts.push_back(
207 pxr::GfVec3f(positions[i_point][0], positions[i_point][1], positions[i_point][2]));
208
209 const blender::float3 right_handle = handles_r[i_point];
210 verts.push_back(pxr::GfVec3f(right_handle[0], right_handle[1], right_handle[2]));
211
212 const blender::float3 left_handle = handles_l[i_point + 1];
213 verts.push_back(pxr::GfVec3f(left_handle[0], left_handle[1], left_handle[2]));
214 }
215
216 verts.push_back(pxr::GfVec3f(positions[last_point_index][0],
217 positions[last_point_index][1],
218 positions[last_point_index][2]));
219
220 /* For USD periodic bezier curves, since the curve is closed, we need to include
221 * the right handle of the last point and the left handle of the first point.
222 */
223 if (is_cyclic) {
224 const blender::float3 right_handle = handles_r[last_point_index];
225 verts.push_back(pxr::GfVec3f(right_handle[0], right_handle[1], right_handle[2]));
226
227 const blender::float3 left_handle = handles_l[start_point_index];
228 verts.push_back(pxr::GfVec3f(left_handle[0], left_handle[1], left_handle[2]));
229 }
230
231 const int tot_points = verts.size() - start_verts_count;
232 control_point_counts[i_curve] = tot_points;
233
234 if (is_cyclic) {
235 segments[i_curve] = tot_points / bezier_vstep;
236 }
237 else {
238 segments[i_curve] = ((tot_points - 4) / bezier_vstep) + 1;
239 }
240 }
241}
242
244 pxr::VtArray<pxr::GfVec3f> &verts,
245 pxr::VtIntArray &control_point_counts,
246 pxr::VtArray<float> &widths,
247 pxr::TfToken &interpolation,
248 const bool is_cyclic,
249 ReportList *reports)
250{
251 const int num_curves = curves.curve_num;
252
253 const Span<float3> positions = curves.positions();
254 const Span<float3> handles_l = curves.handle_positions_left();
255 const Span<float3> handles_r = curves.handle_positions_right();
256
257 pxr::VtArray<int> segments(num_curves);
258
260 curves, positions, handles_l, handles_r, verts, control_point_counts, segments, is_cyclic);
261
262 populate_curve_widths(curves, widths);
263 interpolation = get_curve_width_interpolation(
264 widths, segments, control_point_counts, is_cyclic, reports);
265}
266
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,
274 const bool is_cyclic)
275{
276 /* Order and range, when representing a batched NurbsCurve should be authored one value per
277 * curve. */
278 const int num_curves = curves.curve_num;
279 orders.resize(num_curves);
280
281 const Span<float3> positions = curves.positions();
282
283 VArray<int8_t> geom_orders = curves.nurbs_orders();
284 VArray<int8_t> knots_modes = curves.nurbs_knots_modes();
285
286 const OffsetIndices points_by_curve = curves.points_by_curve();
287 for (const int i_curve : curves.curves_range()) {
288 const IndexRange points = points_by_curve[i_curve];
289 for (const int i_point : points) {
290 verts.push_back(
291 pxr::GfVec3f(positions[i_point][0], positions[i_point][1], positions[i_point][2]));
292 }
293
294 const int tot_points = points.size();
295 control_point_counts[i_curve] = tot_points;
296
297 const int8_t order = geom_orders[i_curve];
298 orders[i_curve] = int(geom_orders[i_curve]);
299
300 const KnotsMode mode = KnotsMode(knots_modes[i_curve]);
301
302 const int knots_num = bke::curves::nurbs::knots_num(tot_points, order, is_cyclic);
303 Array<float> temp_knots(knots_num);
304 bke::curves::nurbs::calculate_knots(tot_points, mode, order, is_cyclic, temp_knots);
305
306 /* Knots should be the concatenation of all batched curves.
307 * https://graphics.pixar.com/usd/dev/api/class_usd_geom_nurbs_curves.html#details */
308 for (int i_knot = 0; i_knot < knots_num; i_knot++) {
309 knots.push_back(double(temp_knots[i_knot]));
310 }
311
312 /* For USD it is required to set specific end knots for periodic/non-periodic curves
313 * https://graphics.pixar.com/usd/dev/api/class_usd_geom_nurbs_curves.html#details */
314 int zeroth_knot_index = knots.size() - knots_num;
315 if (is_cyclic) {
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]);
320 }
321 else {
322 knots[zeroth_knot_index] = knots[zeroth_knot_index + 1];
323 knots[knots.size() - 1] = knots[knots.size() - 2];
324 }
325 }
326
327 populate_curve_widths(curves, widths);
328 interpolation = pxr::UsdGeomTokens->vertex;
329}
330
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)
336{
337 pxr::UsdAttribute attr_knots = usd_nurbs_curves.CreateKnotsAttr(pxr::VtValue(), true);
338 usd_value_writer_.SetAttribute(attr_knots, pxr::VtValue(knots), timecode);
339 pxr::UsdAttribute attr_order = usd_nurbs_curves.CreateOrderAttr(pxr::VtValue(), true);
340 usd_value_writer_.SetAttribute(attr_order, pxr::VtValue(orders), timecode);
341}
342
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)
349{
350 pxr::UsdAttribute attr_points = usd_curves.CreatePointsAttr(pxr::VtValue(), true);
351 usd_value_writer_.SetAttribute(attr_points, pxr::VtValue(verts), timecode);
352
353 pxr::UsdAttribute attr_vertex_counts = usd_curves.CreateCurveVertexCountsAttr(pxr::VtValue(),
354 true);
355 usd_value_writer_.SetAttribute(attr_vertex_counts, pxr::VtValue(control_point_counts), timecode);
356
357 if (!widths.empty()) {
358 pxr::UsdAttribute attr_widths = usd_curves.CreateWidthsAttr(pxr::VtValue(), true);
359 usd_value_writer_.SetAttribute(attr_widths, pxr::VtValue(widths), timecode);
360
361 usd_curves.SetWidthsInterpolation(interpolation);
362 }
363}
364
365static std::optional<pxr::TfToken> convert_blender_domain_to_usd(
366 const bke::AttrDomain blender_domain, bool is_bezier)
367{
368 switch (blender_domain) {
370 return is_bezier ? pxr::UsdGeomTokens->varying : pxr::UsdGeomTokens->vertex;
372 return pxr::UsdGeomTokens->uniform;
373
374 default:
375 return std::nullopt;
376 }
377}
378
379void USDCurvesWriter::write_generic_data(const bke::CurvesGeometry &curves,
380 const bke::AttributeIter &attr,
381 const pxr::UsdGeomCurves &usd_curves)
382{
383 const CurveType curve_type = CurveType(curves.curve_types().first());
384 const bool is_bezier = curve_type == CURVE_TYPE_BEZIER;
385
386 const std::optional<pxr::TfToken> pv_interp = convert_blender_domain_to_usd(attr.domain,
387 is_bezier);
388 const std::optional<pxr::SdfValueTypeName> pv_type = convert_blender_type_to_usd(attr.data_type);
389
390 if (!pv_interp || !pv_type) {
391 BKE_reportf(this->reports(),
393 "Attribute '%s' (Blender domain %d, type %d) cannot be converted to USD",
394 attr.name.c_str(),
395 int8_t(attr.domain),
396 attr.data_type);
397 return;
398 }
399
400 const GVArray attribute = *attr.get();
401 if (attribute.is_empty()) {
402 return;
403 }
404
405 const pxr::UsdTimeCode timecode = get_export_time_code();
406 const pxr::TfToken pv_name(
408 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_curves);
409
410 pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type, *pv_interp);
411
413 attribute, attr.data_type, timecode, pv_attr, usd_value_writer_);
414}
415
416void USDCurvesWriter::write_uv_data(const bke::AttributeIter &attr,
417 const pxr::UsdGeomCurves &usd_curves)
418{
419 const VArray<float2> buffer = *attr.get<float2>(bke::AttrDomain::Curve);
420 if (buffer.is_empty()) {
421 return;
422 }
423
424 const pxr::UsdTimeCode timecode = get_export_time_code();
425 const pxr::TfToken pv_name(
426 make_safe_name(attr.name, usd_export_context_.export_params.allow_unicode));
427 const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_curves);
428
429 pxr::UsdGeomPrimvar pv_uv = pv_api.CreatePrimvar(
430 pv_name, pxr::SdfValueTypeNames->TexCoord2fArray, pxr::UsdGeomTokens->uniform);
431
433}
434
435void USDCurvesWriter::write_custom_data(const bke::CurvesGeometry &curves,
436 const pxr::UsdGeomCurves &usd_curves)
437{
438 const bke::AttributeAccessor attributes = curves.attributes();
439
440 attributes.foreach_attribute([&](const bke::AttributeIter &iter) {
441 /* Skip "internal" Blender properties and attributes dealt with elsewhere. */
442 if (iter.name[0] == '.' || bke::attribute_name_is_anonymous(iter.name) ||
443 ELEM(iter.name,
444 "position",
445 "radius",
446 "resolution",
447 "id",
448 "curve_type",
449 "handle_left",
450 "handle_right",
451 "handle_type_left",
452 "handle_type_right"))
453 {
454 return;
455 }
456
457 /* Spline UV data */
458 if (iter.domain == bke::AttrDomain::Curve && iter.data_type == CD_PROP_FLOAT2) {
459 if (usd_export_context_.export_params.export_uvmaps) {
460 this->write_uv_data(iter, usd_curves);
461 }
462 }
463
464 /* Everything else. */
465 else {
466 this->write_generic_data(curves, iter, usd_curves);
467 }
468 });
469}
470
472{
473 Curves *curves_id;
474 std::unique_ptr<Curves, std::function<void(Curves *)>> converted_curves;
475
476 switch (context.object->type) {
477 case OB_CURVES_LEGACY: {
478 const Curve *legacy_curve = static_cast<Curve *>(context.object->data);
479 converted_curves = std::unique_ptr<Curves, std::function<void(Curves *)>>(
480 bke::curve_legacy_to_curves(*legacy_curve), [](Curves *c) { BKE_id_free(nullptr, c); });
481 curves_id = converted_curves.get();
482 break;
483 }
484 case OB_CURVES:
485 curves_id = static_cast<Curves *>(context.object->data);
486 break;
487 default:
489 return;
490 }
491
492 const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
493 if (curves.points_num() == 0) {
494 return;
495 }
496
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) {
503 reports(), RPT_WARNING, "Cannot export mixed curve types in the same Curves object");
504 return;
505 }
506
510 "Cannot export mixed cyclic and non-cyclic curves in the same Curves object");
511 return;
512 }
513
514 const pxr::UsdTimeCode timecode = get_export_time_code();
515 const int8_t curve_type = curves.curve_types()[0];
516
517 if (first_frame_curve_type == -1) {
518 first_frame_curve_type = curve_type;
519 }
520 else if (first_frame_curve_type != curve_type) {
521 const char *first_frame_curve_type_name = nullptr;
523 rna_enum_curves_type_items, int(first_frame_curve_type), &first_frame_curve_type_name);
524
525 const char *current_curve_type_name = nullptr;
527 rna_enum_curves_type_items, int(curve_type), &current_curve_type_name);
528
531 "USD does not support animating curve types. The curve type changes from %s to "
532 "%s on frame %f",
533 IFACE_(first_frame_curve_type_name),
534 IFACE_(current_curve_type_name),
535 timecode.GetValue());
536 return;
537 }
538
539 const bool is_cyclic = curves.cyclic().first();
540 pxr::VtArray<pxr::GfVec3f> verts;
541 pxr::VtIntArray control_point_counts;
542 pxr::VtArray<float> widths;
543 pxr::TfToken interpolation;
544
545 pxr::UsdGeomBasisCurves usd_basis_curves;
546 pxr::UsdGeomNurbsCurves usd_nurbs_curves;
547 pxr::UsdGeomCurves *usd_curves = nullptr;
548
549 control_point_counts.resize(curves.curves_num());
550 switch (curve_type) {
551 case CURVE_TYPE_POLY:
552 usd_basis_curves = DefineUsdGeomBasisCurves(pxr::VtValue(), is_cyclic, false);
553 usd_curves = &usd_basis_curves;
554
556 curves, verts, control_point_counts, widths, interpolation, is_cyclic, false, reports());
557 break;
559 usd_basis_curves = DefineUsdGeomBasisCurves(
560 pxr::VtValue(pxr::UsdGeomTokens->catmullRom), is_cyclic, true);
561 usd_curves = &usd_basis_curves;
562
564 curves, verts, control_point_counts, widths, interpolation, is_cyclic, true, reports());
565 break;
567 usd_basis_curves = DefineUsdGeomBasisCurves(
568 pxr::VtValue(pxr::UsdGeomTokens->bezier), is_cyclic, true);
569 usd_curves = &usd_basis_curves;
570
572 curves, verts, control_point_counts, widths, interpolation, is_cyclic, reports());
573 break;
574 case CURVE_TYPE_NURBS: {
575 pxr::VtArray<double> knots;
576 pxr::VtArray<int> orders;
577 orders.resize(curves.curves_num());
578
579 usd_nurbs_curves = pxr::UsdGeomNurbsCurves::Define(usd_export_context_.stage,
580 usd_export_context_.usd_path);
581 usd_curves = &usd_nurbs_curves;
582
584 curves, verts, control_point_counts, widths, knots, orders, interpolation, is_cyclic);
585
586 set_writer_attributes_for_nurbs(usd_nurbs_curves, knots, orders, timecode);
587
588 break;
589 }
590 default:
592 }
593
594 set_writer_attributes(*usd_curves, verts, control_point_counts, widths, timecode, interpolation);
595
596 assign_materials(context, *usd_curves);
597
598 write_custom_data(curves, *usd_curves);
599
600 auto prim = usd_curves->GetPrim();
601 write_id_properties(prim, curves_id->id, timecode);
602}
603
605 const pxr::UsdGeomCurves &usd_curves)
606{
607 if (context.object->totcol == 0) {
608 return;
609 }
610
611 bool curve_material_bound = false;
612 for (short mat_num = 0; mat_num < context.object->totcol; mat_num++) {
613 Material *material = BKE_object_material_get(context.object, mat_num + 1);
614 if (material == nullptr) {
615 continue;
616 }
617
618 pxr::UsdPrim curve_prim = usd_curves.GetPrim();
619 pxr::UsdShadeMaterialBindingAPI api = pxr::UsdShadeMaterialBindingAPI(curve_prim);
620 pxr::UsdShadeMaterial usd_material = ensure_usd_material(context, material);
621 api.Bind(usd_material);
622 pxr::UsdShadeMaterialBindingAPI::Apply(curve_prim);
623
624 /* USD seems to support neither per-material nor per-face-group double-sidedness, so we just
625 * use the flag from the first non-empty material slot. */
626 usd_curves.CreateDoubleSidedAttr(
627 pxr::VtValue((material->blend_flag & MA_BL_CULL_BACKFACE) == 0));
628
629 curve_material_bound = true;
630 break;
631 }
632
633 if (!curve_material_bound) {
634 /* Blender defaults to double-sided, but USD to single-sided. */
635 usd_curves.CreateDoubleSidedAttr(pxr::VtValue(true));
636 }
637}
638
639} // namespace blender::io::usd
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)
Definition report.cc:125
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define ELEM(...)
#define IFACE_(msgid)
CurveType
@ CURVE_TYPE_BEZIER
@ CURVE_TYPE_NURBS
@ CURVE_TYPE_POLY
@ CURVE_TYPE_CATMULL_ROM
KnotsMode
@ CD_PROP_FLOAT2
@ MA_BL_CULL_BACKFACE
@ OB_CURVES_LEGACY
@ OB_CURVES
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
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
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
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
static float verts[][3]
int count
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)
Definition usd_utils.cc:16
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[]
Definition rna_curves.cc:22
signed char int8_t
Definition stdint.h:75
CurvesGeometry geometry