Blender V4.5
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 = MEM_calloc_arrayN<float>(num_knots, __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
46{
47 Curve *cu = BKE_curve_add(bmain, name_.c_str(), OB_CURVES_LEGACY);
48
49 cu->flag |= CU_3D;
50 cu->actvert = CU_ACT_NONE;
51 cu->resolu = 2;
52
54 object_->data = cu;
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 pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
72 pxr::UsdAttribute vertexAttr = curve_prim_.GetCurveVertexCountsAttr();
73 pxr::UsdAttribute pointsAttr = curve_prim_.GetPointsAttr();
74
75 pxr::VtIntArray usdCounts;
76 vertexAttr.Get(&usdCounts, motionSampleTime);
77
78 pxr::VtVec3fArray usdPoints;
79 pointsAttr.Get(&usdPoints, motionSampleTime);
80
81 pxr::VtFloatArray usdWidths;
82 widthsAttr.Get(&usdWidths, motionSampleTime);
83
84 pxr::VtIntArray orders;
85 curve_prim_.GetOrderAttr().Get(&orders, motionSampleTime);
86
87 pxr::VtDoubleArray knots;
88 curve_prim_.GetKnotsAttr().Get(&knots, motionSampleTime);
89
90 pxr::VtVec3fArray usdNormals;
91 curve_prim_.GetNormalsAttr().Get(&usdNormals, motionSampleTime);
92
93 /* If normals, extrude, else bevel.
94 * Perhaps to be replaced by Blender USD Schema. */
95 if (!usdNormals.empty()) {
96 /* Set extrusion to 1. */
97 cu->extrude = 1.0f;
98 }
99 else {
100 /* Set bevel depth to 1. */
101 cu->bevel_radius = 1.0f;
102 }
103
104 size_t idx = 0;
105 for (size_t i = 0; i < usdCounts.size(); i++) {
106 const int num_verts = usdCounts[i];
107
108 Nurb *nu = MEM_callocN<Nurb>(__func__);
109 nu->flag = CU_SMOOTH;
110 nu->type = CU_NURBS;
111
112 nu->resolu = cu->resolu;
113 nu->resolv = cu->resolv;
114
115 nu->pntsu = num_verts;
116 nu->pntsv = 1;
117
118 if (i < orders.size()) {
119 nu->orderu = short(orders[i]);
120 }
121 else {
122 nu->orderu = 4;
123 nu->orderv = 4;
124 }
125
126 /* TODO(makowalski): investigate setting Cyclic U and Endpoint U options. */
127#if 0
128 if (knots.size() > 3) {
129 if ((knots[0] == knots[1]) && (knots[knots.size()] == knots[knots.size() - 1])) {
130 nu->flagu |= CU_NURB_ENDPOINT;
131 }
132 else {
133 nu->flagu |= CU_NURB_CYCLIC;
134 }
135 }
136#endif
137
138 float weight = 1.0f;
139
140 nu->bp = MEM_calloc_arrayN<BPoint>(nu->pntsu, __func__);
141 BPoint *bp = nu->bp;
142
143 for (int j = 0; j < nu->pntsu; j++, bp++, idx++) {
144 bp->vec[0] = usdPoints[idx][0];
145 bp->vec[1] = usdPoints[idx][1];
146 bp->vec[2] = usdPoints[idx][2];
147 bp->vec[3] = weight;
148 bp->f1 = SELECT;
149 bp->weight = weight;
150
151 float radius = 0.1f;
152 if (idx < usdWidths.size()) {
153 radius = usdWidths[idx] / 2.0f;
154 }
155
156 bp->radius = radius;
157 }
158
159 if (!set_knots(knots, nu->knotsu)) {
161 }
162
164 }
165}
166
169 const char **r_err_str)
170{
171 BLI_assert(geometry_set.has_mesh());
172 Mesh *new_mesh = read_mesh(nullptr, params, r_err_str);
173 geometry_set.replace_mesh(new_mesh);
174}
175
176Mesh *USDNurbsReader::read_mesh(Mesh * /*existing_mesh*/,
178 const char ** /*r_err_str*/)
179{
180 pxr::UsdGeomCurves curve_prim(prim_);
181
182 pxr::UsdAttribute widthsAttr = curve_prim.GetWidthsAttr();
183 pxr::UsdAttribute vertexAttr = curve_prim.GetCurveVertexCountsAttr();
184 pxr::UsdAttribute pointsAttr = curve_prim.GetPointsAttr();
185
186 pxr::VtIntArray usdCounts;
187
188 vertexAttr.Get(&usdCounts, params.motion_sample_time);
189 int num_subcurves = usdCounts.size();
190
191 pxr::VtVec3fArray usdPoints;
192 pointsAttr.Get(&usdPoints, params.motion_sample_time);
193
194 int vertex_idx = 0;
195 int curve_idx;
196 Curve *curve = static_cast<Curve *>(object_->data);
197
198 const int curve_count = BLI_listbase_count(&curve->nurb);
199 bool same_topology = curve_count == num_subcurves;
200
201 if (same_topology) {
202 Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
203 for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
204 const int num_in_usd = usdCounts[curve_idx];
205 const int num_in_blender = nurbs->pntsu;
206
207 if (num_in_usd != num_in_blender) {
208 same_topology = false;
209 break;
210 }
211 }
212 }
213
214 if (!same_topology) {
215 BKE_nurbList_free(&curve->nurb);
216 read_curve_sample(curve, params.motion_sample_time);
217 }
218 else {
219 Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
220 for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
221 const int totpoint = usdCounts[curve_idx];
222
223 if (nurbs->bp) {
224 BPoint *point = nurbs->bp;
225
226 for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
227 point->vec[0] = usdPoints[vertex_idx][0];
228 point->vec[1] = usdPoints[vertex_idx][1];
229 point->vec[2] = usdPoints[vertex_idx][2];
230 }
231 }
232 else if (nurbs->bezt) {
233 BezTriple *bezier = nurbs->bezt;
234
235 for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
236 bezier->vec[1][0] = usdPoints[vertex_idx][0];
237 bezier->vec[1][1] = usdPoints[vertex_idx][1];
238 bezier->vec[1][2] = usdPoints[vertex_idx][2];
239 }
240 }
241 }
242 }
243
245}
246
247} // namespace blender::io::usd
ListBase * BKE_curve_nurbs_get(Curve *cu)
Definition curve.cc:4962
void BKE_nurb_knot_calc_u(Nurb *nu)
Definition curve.cc:1193
void BKE_nurbList_free(ListBase *lb)
Definition curve.cc:601
Curve * BKE_curve_add(Main *bmain, const char *name, int type)
Definition curve.cc:411
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:46
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
#define CU_ACT_NONE
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
@ CU_NURBS
@ CU_SMOOTH
@ CU_3D
struct Nurb Nurb
struct BPoint BPoint
struct BezTriple BezTriple
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) override
void read_object_data(Main *bmain, double motionSampleTime) override
#define SELECT
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
uint8_t f1
float vec[4]
short resolv
float extrude
short resolu
float bevel_radius
ListBase nurb
void * first
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)
i
Definition text_draw.cc:230
static bool set_knots(const pxr::VtDoubleArray &knots, float *&nu_knots)