Blender V4.3
usd_reader_nurbs.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Tangent Animation. All rights reserved.
2 * SPDX-FileCopyrightText: 2023 Blender Authors
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 *
6 * Adapted from the Blender Alembic importer implementation. */
7
8#include "usd_reader_nurbs.hh"
9
10#include "BKE_curve.hh"
11#include "BKE_geometry_set.hh"
12#include "BKE_mesh.hh"
13#include "BKE_object.hh"
14
15#include "BLI_listbase.h"
16
17#include "DNA_curve_types.h"
18#include "DNA_object_types.h"
19
20#include "MEM_guardedalloc.h"
21
22#include <pxr/base/vt/types.h>
23
24#include <pxr/usd/usdGeom/curves.h>
25
26static bool set_knots(const pxr::VtDoubleArray &knots, float *&nu_knots)
27{
28 if (knots.empty()) {
29 return false;
30 }
31
32 /* Skip first and last knots, as they are used for padding. */
33 const size_t num_knots = knots.size();
34 nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), __func__));
35
36 for (size_t i = 0; i < num_knots; i++) {
37 nu_knots[i] = float(knots[i]);
38 }
39
40 return true;
41}
42
43namespace blender::io::usd {
44
45void USDNurbsReader::create_object(Main *bmain, const double /*motionSampleTime*/)
46{
47 curve_ = BKE_curve_add(bmain, name_.c_str(), OB_CURVES_LEGACY);
48
49 curve_->flag |= CU_3D;
51 curve_->resolu = 2;
52
55}
56
57void USDNurbsReader::read_object_data(Main *bmain, const double motionSampleTime)
58{
59 Curve *cu = (Curve *)object_->data;
60 read_curve_sample(cu, motionSampleTime);
61
62 if (curve_prim_.GetPointsAttr().ValueMightBeTimeVarying()) {
64 }
65
66 USDXformReader::read_object_data(bmain, motionSampleTime);
67}
68
69void USDNurbsReader::read_curve_sample(Curve *cu, const double motionSampleTime)
70{
71 curve_prim_ = pxr::UsdGeomNurbsCurves(prim_);
72
73 pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
74 pxr::UsdAttribute vertexAttr = curve_prim_.GetCurveVertexCountsAttr();
75 pxr::UsdAttribute pointsAttr = curve_prim_.GetPointsAttr();
76
77 pxr::VtIntArray usdCounts;
78 vertexAttr.Get(&usdCounts, motionSampleTime);
79
80 pxr::VtVec3fArray usdPoints;
81 pointsAttr.Get(&usdPoints, motionSampleTime);
82
83 pxr::VtFloatArray usdWidths;
84 widthsAttr.Get(&usdWidths, motionSampleTime);
85
86 pxr::VtIntArray orders;
87 curve_prim_.GetOrderAttr().Get(&orders, motionSampleTime);
88
89 pxr::VtDoubleArray knots;
90 curve_prim_.GetKnotsAttr().Get(&knots, motionSampleTime);
91
92 pxr::VtVec3fArray usdNormals;
93 curve_prim_.GetNormalsAttr().Get(&usdNormals, motionSampleTime);
94
95 /* If normals, extrude, else bevel.
96 * Perhaps to be replaced by Blender USD Schema. */
97 if (!usdNormals.empty()) {
98 /* Set extrusion to 1. */
99 curve_->extrude = 1.0f;
100 }
101 else {
102 /* Set bevel depth to 1. */
103 curve_->bevel_radius = 1.0f;
104 }
105
106 size_t idx = 0;
107 for (size_t i = 0; i < usdCounts.size(); i++) {
108 const int num_verts = usdCounts[i];
109
110 Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), __func__));
111 nu->flag = CU_SMOOTH;
112 nu->type = CU_NURBS;
113
114 nu->resolu = cu->resolu;
115 nu->resolv = cu->resolv;
116
117 nu->pntsu = num_verts;
118 nu->pntsv = 1;
119
120 if (i < orders.size()) {
121 nu->orderu = short(orders[i]);
122 }
123 else {
124 nu->orderu = 4;
125 nu->orderv = 4;
126 }
127
128 /* TODO(makowalski): investigate setting Cyclic U and Endpoint U options. */
129#if 0
130 if (knots.size() > 3) {
131 if ((knots[0] == knots[1]) && (knots[knots.size()] == knots[knots.size() - 1])) {
132 nu->flagu |= CU_NURB_ENDPOINT;
133 }
134 else {
135 nu->flagu |= CU_NURB_CYCLIC;
136 }
137 }
138#endif
139
140 float weight = 1.0f;
141
142 nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(BPoint) * nu->pntsu, __func__));
143 BPoint *bp = nu->bp;
144
145 for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
146 bp->vec[0] = float(usdPoints[idx][0]);
147 bp->vec[1] = float(usdPoints[idx][1]);
148 bp->vec[2] = float(usdPoints[idx][2]);
149 bp->vec[3] = weight;
150 bp->f1 = SELECT;
151 bp->weight = weight;
152
153 float radius = 0.1f;
154 if (idx < usdWidths.size()) {
155 radius = usdWidths[idx];
156 }
157
158 bp->radius = radius;
159 }
160
161 if (!set_knots(knots, nu->knotsu)) {
163 }
164
166 }
167}
168
171 const char **r_err_str)
172{
173 BLI_assert(geometry_set.has_mesh());
174 Mesh *new_mesh = read_mesh(nullptr, params, r_err_str);
175 geometry_set.replace_mesh(new_mesh);
176}
177
178Mesh *USDNurbsReader::read_mesh(Mesh * /*existing_mesh*/,
180 const char ** /*r_err_str*/)
181{
182 pxr::UsdGeomCurves curve_prim(prim_);
183
184 pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr();
185 pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr();
186 pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr();
187
188 pxr::VtIntArray usdCounts;
189
190 vertexAttr.Get(&usdCounts, params.motion_sample_time);
191 int num_subcurves = usdCounts.size();
192
193 pxr::VtVec3fArray usdPoints;
194 pointsAttr.Get(&usdPoints, params.motion_sample_time);
195
196 int vertex_idx = 0;
197 int curve_idx;
198 Curve *curve = static_cast<Curve *>(object_->data);
199
200 const int curve_count = BLI_listbase_count(&curve->nurb);
201 bool same_topology = curve_count == num_subcurves;
202
203 if (same_topology) {
204 Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
205 for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
206 const int num_in_usd = usdCounts[curve_idx];
207 const int num_in_blender = nurbs->pntsu;
208
209 if (num_in_usd != num_in_blender) {
210 same_topology = false;
211 break;
212 }
213 }
214 }
215
216 if (!same_topology) {
217 BKE_nurbList_free(&curve->nurb);
218 read_curve_sample(curve, params.motion_sample_time);
219 }
220 else {
221 Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
222 for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
223 const int totpoint = usdCounts[curve_idx];
224
225 if (nurbs->bp) {
226 BPoint *point = nurbs->bp;
227
228 for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
229 point->vec[0] = usdPoints[vertex_idx][0];
230 point->vec[1] = usdPoints[vertex_idx][1];
231 point->vec[2] = usdPoints[vertex_idx][2];
232 }
233 }
234 else if (nurbs->bezt) {
235 BezTriple *bezier = nurbs->bezt;
236
237 for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
238 bezier->vec[1][0] = usdPoints[vertex_idx][0];
239 bezier->vec[1][1] = usdPoints[vertex_idx][1];
240 bezier->vec[1][2] = usdPoints[vertex_idx][2];
241 }
242 }
243 }
244 }
245
247}
248
249} // namespace blender::io::usd
ListBase * BKE_curve_nurbs_get(Curve *cu)
Definition curve.cc:4965
void BKE_nurb_knot_calc_u(Nurb *nu)
Definition curve.cc:1181
void BKE_nurbList_free(ListBase *lb)
Definition curve.cc:596
Curve * BKE_curve_add(Main *bmain, const char *name, int type)
Definition curve.cc:386
Mesh * BKE_mesh_new_nomain_from_curve(const Object *ob)
General operations, lookup, etc. for blender objects.
Object * BKE_object_add_only_object(Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
@ CU_SMOOTH
@ CU_NURBS
#define CU_ACT_NONE
@ CU_3D
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
Object is a sort of wrapper for general info.
@ OB_CURVES_LEGACY
Read Guarded memory(de)allocation.
void read_geometry(bke::GeometrySet &geometry_set, USDMeshReadParams params, const char **r_err_str) override
void read_object_data(Main *bmain, double motionSampleTime) override
pxr::UsdGeomNurbsCurves curve_prim_
void read_curve_sample(Curve *cu, double motionSampleTime)
void create_object(Main *bmain, double motionSampleTime) override
void read_object_data(Main *bmain, double motionSampleTime) override
#define SELECT
draw_view in_light_buf[] float
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
uint8_t f1
float vec[4]
float vec[3][3]
short resolv
float extrude
short resolu
float bevel_radius
short flagu
short orderu
struct Nurb * next
short orderv
float * knotsu
short flag
short type
BezTriple * bezt
BPoint * bp
short resolu
short resolv
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static bool set_knots(const pxr::VtDoubleArray &knots, float *&nu_knots)