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;
50 curve_->actvert = CU_ACT_NONE;
51 curve_->resolu = 2;
52
54 object_->data = curve_;
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)
struct Nurb Nurb
@ CU_NURBS
@ CU_3D
struct BPoint BPoint
#define CU_ACT_NONE
@ CU_SMOOTH
struct BezTriple BezTriple
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
Object is a sort of wrapper for general info.
@ OB_CURVES_LEGACY
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
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]
short resolv
short resolu
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)
static bool set_knots(const pxr::VtDoubleArray &knots, float *&nu_knots)