Blender  V3.3
abc_writer_nurbs.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "abc_writer_nurbs.h"
9 
10 #include "DNA_curve_types.h"
11 #include "DNA_object_types.h"
12 
13 #include "BLI_listbase.h"
14 
15 #include "BKE_curve.h"
16 
17 #include "CLG_log.h"
18 static CLG_LogRef LOG = {"io.alembic"};
19 
20 namespace blender::io::alembic {
21 
22 using Alembic::Abc::OObject;
23 using Alembic::AbcGeom::FloatArraySample;
24 using Alembic::AbcGeom::OBoolProperty;
25 using Alembic::AbcGeom::OCompoundProperty;
26 using Alembic::AbcGeom::ONuPatch;
27 using Alembic::AbcGeom::ONuPatchSchema;
28 
30 {
31 }
32 
34 {
35  Curve *curve = static_cast<Curve *>(context->object->data);
36  size_t num_nurbs = BLI_listbase_count(&curve->nurb);
37  OObject abc_parent = args_.abc_parent;
38  const char *abc_parent_path = abc_parent.getFullName().c_str();
39 
40  for (size_t i = 0; i < num_nurbs; i++) {
41  std::stringstream patch_name_stream;
42  patch_name_stream << args_.abc_name << '_' << i;
43 
44  while (abc_parent.getChildHeader(patch_name_stream.str())) {
45  patch_name_stream << "_";
46  }
47 
48  std::string patch_name = patch_name_stream.str();
49  CLOG_INFO(&LOG, 2, "exporting %s/%s", abc_parent_path, patch_name.c_str());
50 
51  ONuPatch nurbs(abc_parent, patch_name, timesample_index_);
52  abc_nurbs_.push_back(nurbs);
53  abc_nurbs_schemas_.push_back(nurbs.getSchema());
54  }
55 }
56 
58 {
59  if (abc_nurbs_.empty()) {
60  return OObject();
61  }
62  /* For parenting purposes within the Alembic file, all NURBS patches are equal, so just use the
63  * first one. */
64  return abc_nurbs_[0];
65 }
66 
67 Alembic::Abc::OCompoundProperty ABCNurbsWriter::abc_prop_for_custom_props()
68 {
69  if (abc_nurbs_.empty()) {
70  return Alembic::Abc::OCompoundProperty();
71  }
72 
73  /* A single NURBS object in Blender is expanded to multiple curves in Alembic.
74  * Just store the custom properties on the first one for simplicity. */
75  return abc_schema_prop_for_custom_props(abc_nurbs_schemas_[0]);
76 }
77 
79 {
80  /* Check if object has shape keys. */
81  Curve *cu = static_cast<Curve *>(context.object->data);
82  return (cu->key != nullptr);
83 }
84 
86 {
87  return ELEM(context->object->type, OB_SURF, OB_CURVES_LEGACY);
88 }
89 
90 static void get_knots(std::vector<float> &knots, const int num_knots, float *nu_knots)
91 {
92  if (num_knots <= 1) {
93  return;
94  }
95 
96  /* Add an extra knot at the beginning and end of the array since most apps
97  * require/expect them. */
98  knots.reserve(num_knots + 2);
99 
100  knots.push_back(0.0f);
101 
102  for (int i = 0; i < num_knots; i++) {
103  knots.push_back(nu_knots[i]);
104  }
105 
106  knots[0] = 2.0f * knots[1] - knots[2];
107  knots.push_back(2.0f * knots[num_knots] - knots[num_knots - 1]);
108 }
109 
111 {
112  Curve *curve = static_cast<Curve *>(context.object->data);
113  ListBase *nulb;
114 
115  if (context.object->runtime.curve_cache->deformed_nurbs.first != nullptr) {
116  nulb = &context.object->runtime.curve_cache->deformed_nurbs;
117  }
118  else {
119  nulb = BKE_curve_nurbs_get(curve);
120  }
121 
122  size_t count = 0;
123  for (Nurb *nu = static_cast<Nurb *>(nulb->first); nu; nu = nu->next, count++) {
124  std::vector<float> knotsU;
125  get_knots(knotsU, KNOTSU(nu), nu->knotsu);
126 
127  std::vector<float> knotsV;
128  get_knots(knotsV, KNOTSV(nu), nu->knotsv);
129 
130  const int size = nu->pntsu * nu->pntsv;
131  std::vector<Imath::V3f> positions(size);
132  std::vector<float> weights(size);
133 
134  const BPoint *bp = nu->bp;
135 
136  for (int i = 0; i < size; i++, bp++) {
137  copy_yup_from_zup(positions[i].getValue(), bp->vec);
138  weights[i] = bp->vec[3];
139  }
140 
141  ONuPatchSchema::Sample sample;
142  sample.setUOrder(nu->orderu + 1);
143  sample.setVOrder(nu->orderv + 1);
144  sample.setPositions(positions);
145  sample.setPositionWeights(weights);
146  sample.setUKnot(FloatArraySample(knotsU));
147  sample.setVKnot(FloatArraySample(knotsV));
148  sample.setNu(nu->pntsu);
149  sample.setNv(nu->pntsv);
150 
151  /* TODO(kevin): to accommodate other software we should duplicate control
152  * points to indicate that a NURBS is cyclic. */
153  OCompoundProperty user_props = abc_nurbs_schemas_[count].getUserProperties();
154 
155  if ((nu->flagu & CU_NURB_ENDPOINT) != 0) {
156  OBoolProperty prop(user_props, "endpoint_u");
157  prop.set(true);
158  }
159 
160  if ((nu->flagv & CU_NURB_ENDPOINT) != 0) {
161  OBoolProperty prop(user_props, "endpoint_v");
162  prop.set(true);
163  }
164 
165  if ((nu->flagu & CU_NURB_CYCLIC) != 0) {
166  OBoolProperty prop(user_props, "cyclic_u");
167  prop.set(true);
168  }
169 
170  if ((nu->flagv & CU_NURB_CYCLIC) != 0) {
171  OBoolProperty prop(user_props, "cyclic_v");
172  prop.set(true);
173  }
174 
175  abc_nurbs_schemas_[count].set(sample);
176  }
177 }
178 
179 } // namespace blender::io::alembic
#define KNOTSU(nu)
Definition: BKE_curve.h:52
#define KNOTSV(nu)
Definition: BKE_curve.h:54
ListBase * BKE_curve_nurbs_get(struct Curve *cu)
Definition: curve.cc:4976
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define ELEM(...)
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:187
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
Object is a sort of wrapper for general info.
@ OB_SURF
@ OB_CURVES_LEGACY
static CLG_LogRef LOG
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
Alembic::Abc::OCompoundProperty abc_schema_prop_for_custom_props(T abc_schema)
const ABCWriterConstructorArgs args_
virtual bool check_is_animated(const HierarchyContext &context) const override
virtual bool is_supported(const HierarchyContext *context) const override
virtual void create_alembic_objects(const HierarchyContext *context) override
ABCNurbsWriter(const ABCWriterConstructorArgs &args)
virtual void do_write(HierarchyContext &context) override
virtual Alembic::Abc::OObject get_alembic_object() const override
Alembic::Abc::OCompoundProperty abc_prop_for_custom_props() override
Curve curve
int count
static void get_knots(std::vector< float > &knots, const int num_knots, float *nu_knots)
BLI_INLINE void copy_yup_from_zup(float yup[3], const float zup[3])
MutableSpan< float3 > positions
float vec[4]
struct Key * key
ListBase nurb
void * first
Definition: DNA_listBase.h:31
struct Nurb * next