Blender V5.0
abc_reader_curves.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2016 Kévin Dietrich. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "abc_reader_curves.h"
10#include "abc_axis_conversion.h"
11#include "abc_util.h"
12
13#include <cstdio>
14
15#include "DNA_curves_types.h"
16#include "DNA_modifier_types.h"
17#include "DNA_object_types.h"
18
19#include "BKE_attribute.hh"
20#include "BKE_curves.hh"
21#include "BKE_geometry_set.hh"
22#include "BKE_object.hh"
23
24#include "BLI_vector.hh"
25
26#include "BLT_translation.hh"
27
28using Alembic::Abc::FloatArraySamplePtr;
29using Alembic::Abc::Int32ArraySamplePtr;
30using Alembic::Abc::P3fArraySamplePtr;
31using Alembic::Abc::PropertyHeader;
32using Alembic::Abc::UcharArraySamplePtr;
33
34using Alembic::AbcGeom::CurvePeriodicity;
35using Alembic::AbcGeom::ICompoundProperty;
36using Alembic::AbcGeom::ICurves;
37using Alembic::AbcGeom::ICurvesSchema;
38using Alembic::AbcGeom::IFloatGeomParam;
39using Alembic::AbcGeom::IInt16Property;
40using Alembic::AbcGeom::ISampleSelector;
41using Alembic::AbcGeom::kWrapExisting;
42
43namespace blender::io::alembic {
44static int16_t get_curve_resolution(const ICurvesSchema &schema,
45 const Alembic::Abc::ISampleSelector &sample_sel)
46{
47 ICompoundProperty user_props = schema.getUserProperties();
48 if (!user_props) {
49 return 0;
50 }
51
52 const PropertyHeader *header = user_props.getPropertyHeader(ABC_CURVE_RESOLUTION_U_PROPNAME);
53 if (!header || !header->isScalar() || !IInt16Property::matches(*header)) {
54 return 0;
55 }
56
57 IInt16Property resolu(user_props, header->getName());
58 return resolu.getValue(sample_sel);
59}
60
61static int16_t get_curve_order(const Alembic::AbcGeom::CurveType abc_curve_type,
62 const UcharArraySamplePtr orders,
63 const size_t curve_index)
64{
65 switch (abc_curve_type) {
66 case Alembic::AbcGeom::kCubic:
67 return 4;
68 case Alembic::AbcGeom::kVariableOrder:
69 if (orders && orders->size() > curve_index) {
70 return int16_t((*orders)[curve_index]);
71 }
73 case Alembic::AbcGeom::kLinear:
74 default:
75 return 2;
76 }
77}
78
79static int8_t get_knot_mode(const Alembic::AbcGeom::CurveType abc_curve_type)
80{
81 if (abc_curve_type == Alembic::AbcGeom::kCubic) {
83 }
84
86}
87
88static int get_curve_overlap(const P3fArraySamplePtr positions,
89 const int idx,
90 const int num_verts,
91 const int16_t order)
92{
93 /* Check the number of points which overlap, we don't have overlapping points in Blender, but
94 * other software do use them to indicate that a curve is actually cyclic. Usually the number of
95 * overlapping points is equal to the order/degree of the curve.
96 */
97
98 const int start = idx;
99 const int end = idx + num_verts;
100 int overlap = 0;
101
102 const int safe_order = order <= num_verts ? order : num_verts;
103 for (int j = start, k = end - safe_order; j < (start + safe_order); j++, k++) {
104 const Imath::V3f &p1 = (*positions)[j];
105 const Imath::V3f &p2 = (*positions)[k];
106
107 if (p1 != p2) {
108 break;
109 }
110
111 overlap++;
112 }
113
114 /* TODO: Special case, need to figure out how it coincides with knots. */
115 if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
116 overlap = 1;
117 }
118
119 return overlap;
120}
121
122static CurveType get_curve_type(const Alembic::AbcGeom::BasisType basis)
123{
124 switch (basis) {
125 case Alembic::AbcGeom::kNoBasis:
126 return CURVE_TYPE_POLY;
127 case Alembic::AbcGeom::kBezierBasis:
128 return CURVE_TYPE_BEZIER;
129 case Alembic::AbcGeom::kBsplineBasis:
130 return CURVE_TYPE_NURBS;
131 case Alembic::AbcGeom::kCatmullromBasis:
133 case Alembic::AbcGeom::kHermiteBasis:
134 case Alembic::AbcGeom::kPowerBasis:
135 /* Those types are unknown to Blender, use a default poly type. */
136 return CURVE_TYPE_POLY;
137 }
138 return CURVE_TYPE_POLY;
139}
140
141static inline int bezier_point_count(int alembic_count, bool is_cyclic)
142{
143 return is_cyclic ? (alembic_count / 3) : ((alembic_count / 3) + 1);
144}
145
146static inline float3 to_zup_float3(Imath::V3f v)
147{
148 float3 p;
149 copy_zup_from_yup(p, v.getValue());
150 return p;
151}
152
154 Span<int> preprocessed_offsets)
155{
156 if (curves.offsets() != preprocessed_offsets) {
157 return true;
158 }
159 return false;
160}
161
162template<typename SampleType>
163static bool samples_have_same_topology(const SampleType &sample, const SampleType &ceil_sample)
164{
165 const P3fArraySamplePtr positions = sample.getPositions();
166 const Int32ArraySamplePtr per_curve_vertices_count = sample.getCurvesNumVertices();
167
168 const P3fArraySamplePtr ceil_positions = ceil_sample.getPositions();
169 const Int32ArraySamplePtr ceil_per_curve_vertices_count = ceil_sample.getCurvesNumVertices();
170
171 /* It the counters are different, we can be sure the topology is different. */
172 const bool different_counters = positions->size() != ceil_positions->size() ||
173 per_curve_vertices_count->size() !=
174 ceil_per_curve_vertices_count->size();
175 if (different_counters) {
176 return false;
177 }
178
179 /* Otherwise check the curve vertex counts. */
180 if (memcmp(per_curve_vertices_count->get(),
181 ceil_per_curve_vertices_count->get(),
182 per_curve_vertices_count->size() * sizeof(int)))
183 {
184 return false;
185 }
186
187 return true;
188}
189
190/* Preprocessed data to help and simplify converting curve data from Alembic to Blender.
191 * As some operations may require to look up the Alembic sample multiple times, we just
192 * do it once and cache the results in this.
193 */
195 /* This holds one value for each spline. This will be used to lookup the data at the right
196 * indices, and will also be used to set #CurveGeometry.offsets. */
198 /* This holds one value for each spline, and tells where in the Alembic curve sample the spline
199 * actually starts, accounting for duplicate points indicating cyclicity. */
201 /* This holds one value for each spline to tell whether it is cyclic. */
203 /* This holds one value for each spline which define its order. */
205
206 /* True if any values of `curves_overlaps` is true. If so, we will need to copy the
207 * `curves_overlaps` to an attribute on the Blender curves. */
208 bool do_cyclic = false;
209
210 /* Only one curve type for the whole objects. */
212 int8_t knot_mode = 0;
213
214 /* Optional settings for reading interpolated vertices. If present, `ceil_positions` has to be
215 * valid. */
216 std::optional<SampleInterpolationSettings> interpolation_settings;
217
218 /* Store the pointers during preprocess so we do not have to look up the sample twice. */
219 P3fArraySamplePtr positions = nullptr;
220 P3fArraySamplePtr ceil_positions = nullptr;
221 FloatArraySamplePtr weights = nullptr;
222 FloatArraySamplePtr radii = nullptr;
223};
224
225/* Compute topological information about the curves. We do this step mainly to properly account
226 * for curves overlaps which imply different offsets between Blender and Alembic, but also to
227 * validate the data and cache some values. */
228static std::optional<PreprocessedSampleData> preprocess_sample(StringRefNull iobject_name,
229 bool use_interpolation,
230 const ICurvesSchema &schema,
231 const ISampleSelector sample_sel)
232{
233
234 ICurvesSchema::Sample smp;
235 try {
236 smp = schema.getValue(sample_sel);
237 }
238 catch (Alembic::Util::Exception &ex) {
239 printf("Alembic: error reading curve sample for '%s/%s' at time %f: %s\n",
240 iobject_name.c_str(),
241 schema.getName().c_str(),
242 sample_sel.getRequestedTime(),
243 ex.what());
244 return {};
245 }
246
247 /* NOTE: although Alembic can store knots, we do not read them as the functionality is not
248 * exposed by the Blender's Curves API yet. */
249 const Int32ArraySamplePtr per_curve_vertices_count = smp.getCurvesNumVertices();
250 const P3fArraySamplePtr positions = smp.getPositions();
251 const FloatArraySamplePtr weights = smp.getPositionWeights();
252 const CurvePeriodicity periodicity = smp.getWrap();
253 const UcharArraySamplePtr orders = smp.getOrders();
254
255 if (positions->size() == 0) {
256 return {};
257 }
258
259 const IFloatGeomParam widths_param = schema.getWidthsParam();
260 FloatArraySamplePtr radii;
261 if (widths_param.valid()) {
262 IFloatGeomParam::Sample wsample = widths_param.getExpandedValue(sample_sel);
263 radii = wsample.getVals();
264 }
265
266 const int curve_count = per_curve_vertices_count->size();
267
269 /* Add 1 as these store offsets with the actual value being `offset[i + 1] - offset[i]`. */
270 data.offset_in_blender.resize(curve_count + 1);
271 data.offset_in_alembic.resize(curve_count + 1);
272 data.curves_cyclic.resize(curve_count);
273 data.curve_type = get_curve_type(smp.getBasis());
274 data.knot_mode = get_knot_mode(smp.getType());
275 data.do_cyclic = periodicity == Alembic::AbcGeom::kPeriodic;
276
277 /* If #kVariableOrder is set then we must have order data. If not, this sample is suspect.
278 * Interpret the data as linear as a fallback. See #126324 for one such example.
279 * See also: Alembic source code in `ICurves.h`, #ICurvesSchema::Sample::valid() */
280 if (smp.getType() == Alembic::AbcGeom::kVariableOrder && !orders) {
281 data.curve_type = CURVE_TYPE_POLY;
282 data.knot_mode = NURBS_KNOT_MODE_NORMAL;
283 data.do_cyclic = false;
284 }
285
286 if (data.curve_type == CURVE_TYPE_NURBS) {
287 data.curves_orders.resize(curve_count);
288 }
289
290 /* Compute topological information. */
291
292 int blender_offset = 0;
293 int alembic_offset = 0;
294 for (size_t i = 0; i < curve_count; i++) {
295 const int vertices_count = (*per_curve_vertices_count)[i];
296
297 const int curve_order = get_curve_order(smp.getType(), orders, i);
298
299 data.offset_in_blender[i] = blender_offset;
300 data.offset_in_alembic[i] = alembic_offset;
301 data.curves_cyclic[i] = data.do_cyclic;
302
303 if (data.curve_type == CURVE_TYPE_NURBS) {
304 data.curves_orders[i] = curve_order;
305 }
306
307 /* Some software writes repeated vertices to indicate periodicity but Blender
308 * should skip these if present. */
309 const int overlap = data.do_cyclic ?
311 positions, alembic_offset, vertices_count, curve_order) :
312 0;
313
314 if (data.curve_type == CURVE_TYPE_BEZIER) {
315 blender_offset += bezier_point_count(vertices_count, data.do_cyclic);
316 }
317 else {
318 blender_offset += (overlap >= vertices_count) ? vertices_count : (vertices_count - overlap);
319 }
320
321 alembic_offset += vertices_count;
322 }
323 data.offset_in_blender[curve_count] = blender_offset;
324 data.offset_in_alembic[curve_count] = alembic_offset;
325
326 /* Store relevant pointers. */
327
328 data.positions = positions;
329
330 if (weights && weights->size() > 1) {
331 data.weights = weights;
332 }
333
334 if (radii && radii->size() > 1) {
335 data.radii = radii;
336 }
337
338 const std::optional<SampleInterpolationSettings> interpolation_settings =
340 sample_sel, schema.getTimeSampling(), schema.getNumSamples());
341
342 if (use_interpolation && interpolation_settings.has_value()) {
343 Alembic::AbcGeom::ICurvesSchema::Sample ceil_smp;
344 schema.get(ceil_smp, Alembic::Abc::ISampleSelector(interpolation_settings->ceil_index));
345 if (samples_have_same_topology(smp, ceil_smp)) {
346 data.ceil_positions = ceil_smp.getPositions();
347 data.interpolation_settings = interpolation_settings;
348 }
349 }
350
351 return data;
352}
353
354AbcCurveReader::AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
355 : AbcObjectReader(object, settings)
356{
357 ICurves abc_curves(object, kWrapExisting);
358 m_curves_schema = abc_curves.getSchema();
359
361}
362
364{
365 return m_curves_schema.valid();
366}
367
369 const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
370 const Object *const ob,
371 const char **r_err_str) const
372{
373 if (!Alembic::AbcGeom::ICurves::matches(alembic_header)) {
374 *r_err_str = RPT_(
375 "Object type mismatch, Alembic object path pointed to Curves when importing, but not "
376 "anymore.");
377 return false;
378 }
379
380 if (ob->type != OB_CURVES) {
381 *r_err_str = RPT_("Object type mismatch, Alembic object path points to Curves.");
382 return false;
383 }
384
385 return true;
386}
387
388void AbcCurveReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel)
389{
390 Curves *curves = BKE_curves_add(bmain, m_data_name.c_str());
391
393 m_object->data = curves;
394
395 read_curves_sample(curves, false, m_curves_schema, sample_sel);
396
397 if (m_settings->always_add_cache_reader || has_animations(m_curves_schema, m_settings)) {
399 }
400}
401
403 const Span<Imath::V3f> &ceil_positions,
404 int i,
405 float weight)
406{
407 float3 p;
408 const Imath::V3f &floor_pos = floor_positions[i];
409 const Imath::V3f &ceil_pos = ceil_positions[i];
410
411 interp_v3_v3v3(p, floor_pos.getValue(), ceil_pos.getValue(), weight);
412 copy_zup_from_yup(p, p);
413 return p;
414}
415
416static void add_bezier_control_point(int cp,
417 int offset,
418 const Span<Imath::V3f> floor_positions,
419 const Span<Imath::V3f> ceil_positions,
420 MutableSpan<float3> positions,
421 MutableSpan<float3> handles_left,
422 MutableSpan<float3> handles_right,
423 float weight)
424{
425 positions[cp] = interpolate_to_zup(floor_positions, ceil_positions, offset, weight);
426 if (offset == 0) {
427 handles_right[cp] = interpolate_to_zup(floor_positions, ceil_positions, offset + 1, weight);
428 handles_left[cp] = 2.0f * positions[cp] - handles_right[cp];
429 }
430 else if (offset == floor_positions.size() - 1) {
431 handles_left[cp] = interpolate_to_zup(floor_positions, ceil_positions, offset - 1, weight);
432 handles_right[cp] = 2.0f * positions[cp] - handles_left[cp];
433 }
434 else {
435 handles_left[cp] = interpolate_to_zup(floor_positions, ceil_positions, offset - 1, weight);
436 handles_right[cp] = interpolate_to_zup(floor_positions, ceil_positions, offset + 1, weight);
437 }
438}
439
441 bool use_interpolation,
442 const ICurvesSchema &schema,
443 const ISampleSelector &sample_sel)
444{
445 std::optional<PreprocessedSampleData> opt_preprocess = preprocess_sample(
446 m_iobject.getFullName(), use_interpolation, schema, sample_sel);
447 if (!opt_preprocess) {
448 return;
449 }
450
451 const PreprocessedSampleData &data = opt_preprocess.value();
452
453 const int point_count = data.offset_in_blender.last();
454 const int curve_count = data.offset_in_blender.size() - 1;
455
456 bke::CurvesGeometry &curves = curves_id->geometry.wrap();
457
458 if (curves_topology_changed(curves, data.offset_in_blender)) {
459 curves.resize(point_count, curve_count);
460 curves.offsets_for_write().copy_from(data.offset_in_blender);
461 }
462
463 curves.fill_curve_types(data.curve_type);
464
465 if (data.curve_type != CURVE_TYPE_POLY) {
466 int16_t curve_resolution = get_curve_resolution(schema, sample_sel);
467 if (curve_resolution > 0) {
468 curves.resolution_for_write().fill(curve_resolution);
469 }
470 }
471
472 MutableSpan<float3> curves_positions = curves.positions_for_write();
473
474 Span<Imath::V3f> alembic_points{&(*data.positions)[0], int64_t((*data.positions).size())};
475 Span<Imath::V3f> alembic_points_ceil;
476 float interp_weight = 0.0f;
477 if (data.interpolation_settings.has_value()) {
478 alembic_points_ceil = {&(*data.ceil_positions)[0], int64_t((*data.ceil_positions).size())};
479 interp_weight = data.interpolation_settings->weight;
480 }
481 else {
482 alembic_points_ceil = alembic_points;
483 }
484
485 if (data.curve_type == CURVE_TYPE_BEZIER) {
488
491
492 int point_offset = 0;
493 for (const int i_curve : curves.curves_range()) {
494 const int alembic_point_offset = data.offset_in_alembic[i_curve];
495 const int alembic_point_count = data.offset_in_alembic[i_curve + 1] - alembic_point_offset;
496 const int cp_count = data.offset_in_blender[i_curve + 1] - data.offset_in_blender[i_curve];
497
498 int cp_offset = 0;
499 for (const int cp : IndexRange(cp_count)) {
501 cp,
502 cp_offset,
503 alembic_points.slice(alembic_point_offset, alembic_point_count),
504 alembic_points_ceil.slice(alembic_point_offset, alembic_point_count),
505 curves_positions.slice(point_offset, point_count),
506 handles_left.slice(point_offset, point_count),
507 handles_right.slice(point_offset, point_count),
508 interp_weight);
509 cp_offset += 3;
510 }
511
512 point_offset += cp_count;
513 }
514 }
515 else {
516 for (const int i_curve : curves.curves_range()) {
517 int position_offset = data.offset_in_alembic[i_curve];
518 for (const int i_point : curves.points_by_curve()[i_curve]) {
519 if (data.interpolation_settings.has_value()) {
520 curves_positions[i_point] = interpolate_to_zup(
521 alembic_points, alembic_points_ceil, position_offset++, interp_weight);
522 }
523 else {
524 curves_positions[i_point] = to_zup_float3(alembic_points[position_offset++]);
525 }
526 }
527 }
528 }
529
530 if (data.do_cyclic) {
531 curves.cyclic_for_write().copy_from(data.curves_cyclic);
532 }
533
534 if (data.radii) {
535 MutableSpan<float> radii = curves.radius_for_write();
536
537 Alembic::Abc::FloatArraySample alembic_widths = *data.radii;
538 for (const int i_point : curves.points_range()) {
539 radii[i_point] = alembic_widths[i_point] / 2.0f;
540 }
541 }
542
543 if (data.curve_type == CURVE_TYPE_NURBS) {
544 curves.nurbs_orders_for_write().copy_from(data.curves_orders);
545 curves.nurbs_knots_modes_for_write().fill(data.knot_mode);
546
547 if (data.weights) {
548 MutableSpan<float> curves_weights = curves.nurbs_weights_for_write();
549 Span<float> data_weights_span = {data.weights->get(), int64_t(data.weights->size())};
550 for (const int i_curve : curves.curves_range()) {
551 const int alembic_offset = data.offset_in_alembic[i_curve];
552 const IndexRange points = curves.points_by_curve()[i_curve];
553 curves_weights.slice(points).copy_from(
554 data_weights_span.slice(alembic_offset, points.size()));
555 }
556 }
557 }
558}
559
561 const Alembic::Abc::ISampleSelector &sample_sel,
562 int read_flag,
563 const char * /*velocity_name*/,
564 const float /*velocity_scale*/,
565 const char ** /*r_err_str*/)
566{
567 Curves *curves = geometry_set.get_curves_for_write();
568
569 bool use_interpolation = read_flag & MOD_MESHSEQ_INTERPOLATE_VERTICES;
570 read_curves_sample(curves, use_interpolation, m_curves_schema, sample_sel);
571}
572
573} // namespace blender::io::alembic
struct Curves * BKE_curves_add(struct Main *bmain, const char *name)
Low-level operations for curves.
General operations, lookup, etc. for blender objects.
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
#define ATTR_FALLTHROUGH
#define BLI_INLINE
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
#define RPT_(msgid)
@ BEZIER_HANDLE_ALIGN
@ NURBS_KNOT_MODE_ENDPOINT
@ NURBS_KNOT_MODE_NORMAL
@ MOD_MESHSEQ_INTERPOLATE_VERTICES
Object is a sort of wrapper for general info.
@ OB_CURVES
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
long long int int64_t
constexpr void fill(const T &value) const
Definition BLI_span.hh:517
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr const char * c_str() const
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
MutableSpan< int8_t > handle_types_right_for_write()
IndexRange curves_range() const
MutableSpan< int > resolution_for_write()
MutableSpan< float3 > handle_positions_left_for_write()
MutableSpan< float3 > handle_positions_right_for_write()
MutableSpan< int8_t > nurbs_knots_modes_for_write()
MutableSpan< int8_t > nurbs_orders_for_write()
IndexRange points_range() const
MutableSpan< float > radius_for_write()
MutableSpan< float > nurbs_weights_for_write()
void resize(int points_num, int curves_num)
void fill_curve_types(CurveType type)
MutableSpan< int > offsets_for_write()
MutableSpan< bool > cyclic_for_write()
MutableSpan< int8_t > handle_types_left_for_write()
void readObjectData(Main *bmain, const Alembic::Abc::ISampleSelector &sample_sel) override
void read_geometry(bke::GeometrySet &geometry_set, const Alembic::Abc::ISampleSelector &sample_sel, int read_flag, const char *velocity_name, float velocity_scale, const char **r_err_str) override
void read_curves_sample(Curves *curves_id, bool use_interpolation, const Alembic::AbcGeom::ICurvesSchema &schema, const Alembic::Abc::ISampleSelector &sample_selector)
bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header, const Object *const ob, const char **r_err_str) const override
AbcCurveReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
static bool is_cyclic(const Nurb *nu)
#define printf(...)
static float3 to_zup_float3(Imath::V3f v)
static int16_t get_curve_resolution(const ICurvesSchema &schema, const Alembic::Abc::ISampleSelector &sample_sel)
static void add_bezier_control_point(int cp, int offset, const Span< Imath::V3f > floor_positions, const Span< Imath::V3f > ceil_positions, MutableSpan< float3 > positions, MutableSpan< float3 > handles_left, MutableSpan< float3 > handles_right, float weight)
void get_min_max_time(const Alembic::AbcGeom::IObject &object, const Schema &schema, chrono_t &min, chrono_t &max)
Definition abc_util.h:69
static bool curves_topology_changed(const bke::CurvesGeometry &curves, Span< int > preprocessed_offsets)
static bool samples_have_same_topology(const SampleType &sample, const SampleType &ceil_sample)
BLI_INLINE void copy_zup_from_yup(float zup[3], const float yup[3])
static std::optional< PreprocessedSampleData > preprocess_sample(StringRefNull iobject_name, bool use_interpolation, const ICurvesSchema &schema, const ISampleSelector sample_sel)
static int8_t get_knot_mode(const Alembic::AbcGeom::CurveType abc_curve_type)
BLI_INLINE float3 interpolate_to_zup(const Span< Imath::V3f > &floor_positions, const Span< Imath::V3f > &ceil_positions, int i, float weight)
static CurveType get_curve_type(const Alembic::AbcGeom::BasisType basis)
const std::string ABC_CURVE_RESOLUTION_U_PROPNAME
static int16_t get_curve_order(const Alembic::AbcGeom::CurveType abc_curve_type, const UcharArraySamplePtr orders, const size_t curve_index)
bool has_animations(Alembic::AbcGeom::IPolyMeshSchema &schema, ImportSettings *settings)
std::optional< SampleInterpolationSettings > get_sample_interpolation_settings(const Alembic::AbcGeom::ISampleSelector &selector, const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling, size_t samples_number)
Definition abc_util.cc:122
static int bezier_point_count(int alembic_count, bool is_cyclic)
static int get_curve_overlap(const P3fArraySamplePtr positions, const int idx, const int num_verts, const int16_t order)
VecBase< float, 3 > float3
CurvesGeometry geometry
std::optional< SampleInterpolationSettings > interpolation_settings
i
Definition text_draw.cc:230