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