28using Alembic::Abc::FloatArraySamplePtr;
29using Alembic::Abc::Int32ArraySamplePtr;
30using Alembic::Abc::P3fArraySamplePtr;
31using Alembic::Abc::PropertyHeader;
32using Alembic::Abc::UcharArraySamplePtr;
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;
45 const Alembic::Abc::ISampleSelector &sample_sel)
47 ICompoundProperty user_props = schema.getUserProperties();
53 if (!header || !header->isScalar() || !IInt16Property::matches(*header)) {
57 IInt16Property resolu(user_props, header->getName());
58 return resolu.getValue(sample_sel);
62 const UcharArraySamplePtr orders,
63 const size_t curve_index)
65 switch (abc_curve_type) {
66 case Alembic::AbcGeom::kCubic:
68 case Alembic::AbcGeom::kVariableOrder:
69 if (orders && orders->size() > curve_index) {
70 return int16_t((*orders)[curve_index]);
73 case Alembic::AbcGeom::kLinear:
79static int8_t
get_knot_mode(
const Alembic::AbcGeom::CurveType abc_curve_type)
81 if (abc_curve_type == Alembic::AbcGeom::kCubic) {
98 const int start = idx;
99 const int end = idx + num_verts;
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];
115 if (overlap == 0 && num_verts > 2 && (*positions)[start] == (*positions)[end - 1]) {
125 case Alembic::AbcGeom::kNoBasis:
127 case Alembic::AbcGeom::kBezierBasis:
129 case Alembic::AbcGeom::kBsplineBasis:
131 case Alembic::AbcGeom::kCatmullromBasis:
133 case Alembic::AbcGeom::kHermiteBasis:
134 case Alembic::AbcGeom::kPowerBasis:
143 return is_cyclic ? (alembic_count / 3) : ((alembic_count / 3) + 1);
156 if (curves.
offsets() != preprocessed_offsets) {
162template<
typename SampleType>
165 const P3fArraySamplePtr positions =
sample.getPositions();
166 const Int32ArraySamplePtr per_curve_vertices_count =
sample.getCurvesNumVertices();
168 const P3fArraySamplePtr ceil_positions = ceil_sample.getPositions();
169 const Int32ArraySamplePtr ceil_per_curve_vertices_count = ceil_sample.getCurvesNumVertices();
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) {
180 if (memcmp(per_curve_vertices_count->get(),
181 ceil_per_curve_vertices_count->get(),
182 per_curve_vertices_count->size() *
sizeof(
int)))
222 FloatArraySamplePtr
radii =
nullptr;
229 bool use_interpolation,
230 const ICurvesSchema &schema,
231 const ISampleSelector sample_sel)
234 ICurvesSchema::Sample smp;
236 smp = schema.getValue(sample_sel);
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(),
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();
255 if (positions->size() == 0) {
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();
266 const int curve_count = per_curve_vertices_count->size();
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);
275 data.do_cyclic = periodicity == Alembic::AbcGeom::kPeriodic;
280 if (smp.getType() == Alembic::AbcGeom::kVariableOrder && !orders) {
283 data.do_cyclic =
false;
287 data.curves_orders.resize(curve_count);
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];
299 data.offset_in_blender[
i] = blender_offset;
300 data.offset_in_alembic[
i] = alembic_offset;
304 data.curves_orders[
i] = curve_order;
309 const int overlap =
data.do_cyclic ?
311 positions, alembic_offset, vertices_count, curve_order) :
318 blender_offset += (overlap >= vertices_count) ? vertices_count : (vertices_count - overlap);
321 alembic_offset += vertices_count;
323 data.offset_in_blender[curve_count] = blender_offset;
324 data.offset_in_alembic[curve_count] = alembic_offset;
328 data.positions = positions;
330 if (weights && weights->size() > 1) {
331 data.weights = weights;
334 if (radii && radii->size() > 1) {
338 const std::optional<SampleInterpolationSettings> interpolation_settings =
340 sample_sel, schema.getTimeSampling(), schema.getNumSamples());
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));
346 data.ceil_positions = ceil_smp.getPositions();
347 data.interpolation_settings = interpolation_settings;
357 ICurves abc_curves(
object, kWrapExisting);
358 m_curves_schema = abc_curves.getSchema();
365 return m_curves_schema.valid();
369 const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
371 const char **r_err_str)
const
373 if (!Alembic::AbcGeom::ICurves::matches(alembic_header)) {
375 "Object type mismatch, Alembic object path pointed to Curves when importing, but not "
381 *r_err_str =
RPT_(
"Object type mismatch, Alembic object path points to Curves.");
408 const Imath::V3f &floor_pos = floor_positions[
i];
409 const Imath::V3f &ceil_pos = ceil_positions[
i];
411 interp_v3_v3v3(p, floor_pos.getValue(), ceil_pos.getValue(), weight);
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];
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];
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);
441 bool use_interpolation,
442 const ICurvesSchema &schema,
443 const ISampleSelector &sample_sel)
446 m_iobject.getFullName(), use_interpolation, schema, sample_sel);
447 if (!opt_preprocess) {
453 const int point_count =
data.offset_in_blender.last();
454 const int curve_count =
data.offset_in_blender.size() - 1;
459 curves.
resize(point_count, curve_count);
467 if (curve_resolution > 0) {
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;
482 alembic_points_ceil = alembic_points;
492 int point_offset = 0;
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];
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),
512 point_offset += cp_count;
517 int position_offset =
data.offset_in_alembic[i_curve];
519 if (
data.interpolation_settings.has_value()) {
521 alembic_points, alembic_points_ceil, position_offset++, interp_weight);
524 curves_positions[i_point] =
to_zup_float3(alembic_points[position_offset++]);
530 if (
data.do_cyclic) {
537 Alembic::Abc::FloatArraySample alembic_widths = *
data.radii;
539 radii[i_point] = alembic_widths[i_point] / 2.0f;
551 const int alembic_offset =
data.offset_in_alembic[i_curve];
554 data_weights_span.
slice(alembic_offset, points.
size()));
561 const Alembic::Abc::ISampleSelector &sample_sel,
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
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
@ NURBS_KNOT_MODE_ENDPOINT
@ MOD_MESHSEQ_INTERPOLATE_VERTICES
Object is a sort of wrapper for general info.
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
constexpr void fill(const T &value) const
constexpr void copy_from(Span< T > values) const
constexpr int64_t size() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr void copy_from(Span< T > values) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
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
Span< int > offsets() 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 valid() const override
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)
std::string m_object_name
Alembic::Abc::IObject m_iobject
AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings)
ImportSettings * m_settings
static bool is_cyclic(const Nurb *nu)
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)
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)
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
Curves * get_curves_for_write()
Vector< int > offset_in_blender
Vector< int > offset_in_alembic
std::optional< SampleInterpolationSettings > interpolation_settings
FloatArraySamplePtr radii
Vector< bool > curves_cyclic
FloatArraySamplePtr weights
P3fArraySamplePtr positions
Vector< int8_t > curves_orders
P3fArraySamplePtr ceil_positions