Blender  V3.3
usd_reader_nurbs.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Adapted from the Blender Alembic importer implementation.
3  * Modifications Copyright 2021 Tangent Animation. All rights reserved. */
4 
5 #include "usd_reader_nurbs.h"
6 
7 #include "BKE_curve.h"
8 #include "BKE_mesh.h"
9 #include "BKE_object.h"
10 
11 #include "BLI_listbase.h"
12 
13 #include "DNA_curve_types.h"
14 #include "DNA_object_types.h"
15 
16 #include "MEM_guardedalloc.h"
17 
18 #include <pxr/base/vt/array.h>
19 #include <pxr/base/vt/types.h>
20 #include <pxr/base/vt/value.h>
21 #include <pxr/usd/sdf/types.h>
22 
23 #include <pxr/usd/usdGeom/curves.h>
24 
25 static bool set_knots(const pxr::VtDoubleArray &knots, float *&nu_knots)
26 {
27  if (knots.empty()) {
28  return false;
29  }
30 
31  /* Skip first and last knots, as they are used for padding. */
32  const size_t num_knots = knots.size();
33  nu_knots = static_cast<float *>(MEM_callocN(num_knots * sizeof(float), __func__));
34 
35  for (size_t i = 0; i < num_knots; i++) {
36  nu_knots[i] = (float)knots[i];
37  }
38 
39  return true;
40 }
41 
42 namespace blender::io::usd {
43 
44 void USDNurbsReader::create_object(Main *bmain, const double /* motionSampleTime */)
45 {
46  curve_ = BKE_curve_add(bmain, name_.c_str(), OB_CURVES_LEGACY);
47 
48  curve_->flag |= CU_3D;
50  curve_->resolu = 2;
51 
53  object_->data = curve_;
54 }
55 
56 void USDNurbsReader::read_object_data(Main *bmain, const double motionSampleTime)
57 {
58  Curve *cu = (Curve *)object_->data;
59  read_curve_sample(cu, motionSampleTime);
60 
61  if (curve_prim_.GetPointsAttr().ValueMightBeTimeVarying()) {
63  }
64 
65  USDXformReader::read_object_data(bmain, motionSampleTime);
66 }
67 
68 void USDNurbsReader::read_curve_sample(Curve *cu, const double motionSampleTime)
69 {
70  curve_prim_ = pxr::UsdGeomNurbsCurves(prim_);
71 
72  pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
73  pxr::UsdAttribute vertexAttr = curve_prim_.GetCurveVertexCountsAttr();
74  pxr::UsdAttribute pointsAttr = curve_prim_.GetPointsAttr();
75 
76  pxr::VtIntArray usdCounts;
77  vertexAttr.Get(&usdCounts, motionSampleTime);
78 
79  pxr::VtVec3fArray usdPoints;
80  pointsAttr.Get(&usdPoints, motionSampleTime);
81 
82  pxr::VtFloatArray usdWidths;
83  widthsAttr.Get(&usdWidths, motionSampleTime);
84 
85  pxr::VtIntArray orders;
86  curve_prim_.GetOrderAttr().Get(&orders, motionSampleTime);
87 
88  pxr::VtDoubleArray knots;
89  curve_prim_.GetKnotsAttr().Get(&knots, motionSampleTime);
90 
91  pxr::VtVec3fArray usdNormals;
92  curve_prim_.GetNormalsAttr().Get(&usdNormals, motionSampleTime);
93 
94  /* If normals, extrude, else bevel.
95  * Perhaps to be replaced by Blender USD Schema. */
96  if (!usdNormals.empty()) {
97  /* Set extrusion to 1. */
98  curve_->extrude = 1.0f;
99  }
100  else {
101  /* Set bevel depth to 1. */
102  curve_->bevel_radius = 1.0f;
103  }
104 
105  size_t idx = 0;
106  for (size_t i = 0; i < usdCounts.size(); i++) {
107  const int num_verts = usdCounts[i];
108 
109  Nurb *nu = static_cast<Nurb *>(MEM_callocN(sizeof(Nurb), __func__));
110  nu->flag = CU_SMOOTH;
111  nu->type = CU_NURBS;
112 
113  nu->resolu = cu->resolu;
114  nu->resolv = cu->resolv;
115 
116  nu->pntsu = num_verts;
117  nu->pntsv = 1;
118 
119  if (i < orders.size()) {
120  nu->orderu = static_cast<short>(orders[i]);
121  }
122  else {
123  nu->orderu = 4;
124  nu->orderv = 4;
125  }
126 
127  /* TODO(makowalski): investigate setting Cyclic U and Endpoint U options. */
128 #if 0
129  if (knots.size() > 3) {
130  if ((knots[0] == knots[1]) && (knots[knots.size()] == knots[knots.size() - 1])) {
131  nu->flagu |= CU_NURB_ENDPOINT;
132  } else {
133  nu->flagu |= CU_NURB_CYCLIC;
134  }
135  }
136 #endif
137 
138  float weight = 1.0f;
139 
140  nu->bp = static_cast<BPoint *>(MEM_callocN(sizeof(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] = (float)usdPoints[idx][0];
145  bp->vec[1] = (float)usdPoints[idx][1];
146  bp->vec[2] = (float)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];
154  }
155 
156  bp->radius = radius;
157  }
158 
159  if (!set_knots(knots, nu->knotsu)) {
161  }
162 
164  }
165 }
166 
167 Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */,
168  const double motionSampleTime,
169  const int /* read_flag */,
170  const char ** /* err_str */)
171 {
172  pxr::UsdGeomCurves curve_prim_(prim_);
173 
174  pxr::UsdAttribute widthsAttr = curve_prim_.GetWidthsAttr();
175  pxr::UsdAttribute vertexAttr = curve_prim_.GetCurveVertexCountsAttr();
176  pxr::UsdAttribute pointsAttr = curve_prim_.GetPointsAttr();
177 
178  pxr::VtIntArray usdCounts;
179 
180  vertexAttr.Get(&usdCounts, motionSampleTime);
181  int num_subcurves = usdCounts.size();
182 
183  pxr::VtVec3fArray usdPoints;
184  pointsAttr.Get(&usdPoints, motionSampleTime);
185 
186  int vertex_idx = 0;
187  int curve_idx;
188  Curve *curve = static_cast<Curve *>(object_->data);
189 
190  const int curve_count = BLI_listbase_count(&curve->nurb);
191  bool same_topology = curve_count == num_subcurves;
192 
193  if (same_topology) {
194  Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
195  for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
196  const int num_in_usd = usdCounts[curve_idx];
197  const int num_in_blender = nurbs->pntsu;
198 
199  if (num_in_usd != num_in_blender) {
200  same_topology = false;
201  break;
202  }
203  }
204  }
205 
206  if (!same_topology) {
208  read_curve_sample(curve, motionSampleTime);
209  }
210  else {
211  Nurb *nurbs = static_cast<Nurb *>(curve->nurb.first);
212  for (curve_idx = 0; nurbs; nurbs = nurbs->next, curve_idx++) {
213  const int totpoint = usdCounts[curve_idx];
214 
215  if (nurbs->bp) {
216  BPoint *point = nurbs->bp;
217 
218  for (int i = 0; i < totpoint; i++, point++, vertex_idx++) {
219  point->vec[0] = usdPoints[vertex_idx][0];
220  point->vec[1] = usdPoints[vertex_idx][1];
221  point->vec[2] = usdPoints[vertex_idx][2];
222  }
223  }
224  else if (nurbs->bezt) {
225  BezTriple *bezier = nurbs->bezt;
226 
227  for (int i = 0; i < totpoint; i++, bezier++, vertex_idx++) {
228  bezier->vec[1][0] = usdPoints[vertex_idx][0];
229  bezier->vec[1][1] = usdPoints[vertex_idx][1];
230  bezier->vec[1][2] = usdPoints[vertex_idx][2];
231  }
232  }
233  }
234  }
235 
237 }
238 
239 } // namespace blender::io::usd
typedef float(TangentPoint)[2]
struct Curve * BKE_curve_add(struct Main *bmain, const char *name, int type)
Definition: curve.cc:414
void BKE_nurb_knot_calc_u(struct Nurb *nu)
Definition: curve.cc:1234
void BKE_nurbList_free(struct ListBase *lb)
Definition: curve.cc:649
ListBase * BKE_curve_nurbs_get(struct Curve *cu)
Definition: curve.cc:4976
struct Mesh * BKE_mesh_new_nomain_from_curve(const struct Object *ob)
General operations, lookup, etc. for blender objects.
struct Object * BKE_object_add_only_object(struct Main *bmain, int type, const char *name) ATTR_RETURNS_NONNULL
Definition: object.cc:2241
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
@ CU_NURBS
@ CU_SMOOTH
#define CU_ACT_NONE
@ CU_NURB_CYCLIC
@ CU_NURB_ENDPOINT
@ CU_3D
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 Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise 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
Mesh * read_mesh(struct Mesh *existing_mesh, double motionSampleTime, int read_flag, const char **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
Curve curve
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
float weight
uint8_t f1
float vec[4]
float radius
float vec[3][3]
short resolv
float extrude
short resolu
float bevel_radius
ListBase nurb
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
short flagu
short orderu
struct Nurb * next
short orderv
float * knotsu
short flag
short type
BezTriple * bezt
BPoint * bp
short resolu
short resolv
void * data
static bool set_knots(const pxr::VtDoubleArray &knots, float *&nu_knots)