Blender  V3.3
alembic.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #pragma once
5 
6 #include "graph/node.h"
7 #include "scene/attribute.h"
8 #include "scene/procedural.h"
9 #include "util/set.h"
10 #include "util/transform.h"
11 #include "util/vector.h"
12 
13 #ifdef WITH_ALEMBIC
14 
15 # include <Alembic/AbcCoreFactory/All.h>
16 # include <Alembic/AbcGeom/All.h>
17 
19 
20 class AlembicProcedural;
21 class Geometry;
22 class Object;
23 class Progress;
24 class Shader;
25 
26 using MatrixSampleMap = std::map<Alembic::Abc::chrono_t, Alembic::Abc::M44d>;
27 
28 struct MatrixSamplesData {
29  MatrixSampleMap *samples = nullptr;
30  Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling;
31 };
32 
33 /* Helpers to detect if some type is a `ccl::array`. */
34 template<typename> struct is_array : public std::false_type {
35 };
36 
37 template<typename T> struct is_array<array<T>> : public std::true_type {
38 };
39 
40 /* Holds the data for a cache lookup at a given time, as well as information to
41  * help disambiguate successes or failures to get data from the cache. */
42 template<typename T> class CacheLookupResult {
43  enum class State {
44  NEW_DATA,
45  ALREADY_LOADED,
46  NO_DATA_FOR_TIME,
47  };
48 
49  T *data;
50  State state;
51 
52  protected:
53  /* Prevent default construction outside of the class: for a valid result, we
54  * should use the static functions below. */
55  CacheLookupResult() = default;
56 
57  public:
58  static CacheLookupResult new_data(T *data_)
59  {
60  CacheLookupResult result;
61  result.data = data_;
62  result.state = State::NEW_DATA;
63  return result;
64  }
65 
66  static CacheLookupResult no_data_found_for_time()
67  {
68  CacheLookupResult result;
69  result.data = nullptr;
70  result.state = State::NO_DATA_FOR_TIME;
71  return result;
72  }
73 
74  static CacheLookupResult already_loaded()
75  {
76  CacheLookupResult result;
77  result.data = nullptr;
78  result.state = State::ALREADY_LOADED;
79  return result;
80  }
81 
82  /* This should only be call if new data is available. */
83  const T &get_data() const
84  {
85  assert(state == State::NEW_DATA);
86  assert(data != nullptr);
87  return *data;
88  }
89 
90  T *get_data_or_null() const
91  {
92  // data_ should already be null if there is no new data so no need to check
93  return data;
94  }
95 
96  bool has_new_data() const
97  {
98  return state == State::NEW_DATA;
99  }
100 
101  bool has_already_loaded() const
102  {
103  return state == State::ALREADY_LOADED;
104  }
105 
106  bool has_no_data_for_time() const
107  {
108  return state == State::NO_DATA_FOR_TIME;
109  }
110 };
111 
112 /* Store the data set for an animation at every time points, or at the beginning of the animation
113  * for constant data.
114  *
115  * The data is supposed to be stored in chronological order, and is looked up using the current
116  * animation time in seconds using the TimeSampling from the Alembic property. */
117 template<typename T> class DataStore {
118  /* Holds information to map a cache entry for a given time to an index into the data array. */
119  struct TimeIndexPair {
120  /* Frame time for this entry. */
121  double time = 0;
122  /* Frame time for the data pointed to by `index`. */
123  double source_time = 0;
124  /* Index into the data array. */
125  size_t index = 0;
126  };
127 
128  /* This is the actual data that is stored. We deduplicate data across frames to avoid storing
129  * values if they have not changed yet (e.g. the triangles for a building before fracturing, or a
130  * fluid simulation before a break or splash) */
131  vector<T> data{};
132 
133  /* This is used to map they entry for a given time to an index into the data array, multiple
134  * frames can point to the same index. */
135  vector<TimeIndexPair> index_data_map{};
136 
137  Alembic::AbcCoreAbstract::TimeSampling time_sampling{};
138 
139  double last_loaded_time = std::numeric_limits<double>::max();
140 
141  public:
142  /* Keys used to compare values. */
145 
146  void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling_)
147  {
148  time_sampling = time_sampling_;
149  }
150 
151  Alembic::AbcCoreAbstract::TimeSampling get_time_sampling() const
152  {
153  return time_sampling;
154  }
155 
156  /* Get the data for the specified time.
157  * Return nullptr if there is no data or if the data for this time was already loaded. */
158  CacheLookupResult<T> data_for_time(double time)
159  {
160  if (size() == 0) {
161  return CacheLookupResult<T>::no_data_found_for_time();
162  }
163 
164  const TimeIndexPair &index = get_index_for_time(time);
165 
166  if (index.index == -1ul) {
167  return CacheLookupResult<T>::no_data_found_for_time();
168  }
169 
170  if (last_loaded_time == index.time || last_loaded_time == index.source_time) {
171  return CacheLookupResult<T>::already_loaded();
172  }
173 
174  last_loaded_time = index.source_time;
175 
176  assert(index.index < data.size());
177 
178  return CacheLookupResult<T>::new_data(&data[index.index]);
179  }
180 
181  /* get the data for the specified time, but do not check if the data was already loaded for this
182  * time return nullptr if there is no data */
183  CacheLookupResult<T> data_for_time_no_check(double time)
184  {
185  if (size() == 0) {
186  return CacheLookupResult<T>::no_data_found_for_time();
187  }
188 
189  const TimeIndexPair &index = get_index_for_time(time);
190 
191  if (index.index == -1ul) {
192  return CacheLookupResult<T>::no_data_found_for_time();
193  }
194 
195  assert(index.index < data.size());
196 
197  return CacheLookupResult<T>::new_data(&data[index.index]);
198  }
199 
200  void add_data(T &data_, double time)
201  {
202  index_data_map.push_back({time, time, data.size()});
203 
204  if constexpr (is_array<T>::value) {
205  data.emplace_back();
206  data.back().steal_data(data_);
207  return;
208  }
209 
210  data.push_back(data_);
211  }
212 
213  void reuse_data_for_last_time(double time)
214  {
215  const TimeIndexPair &data_index = index_data_map.back();
216  index_data_map.push_back({time, data_index.source_time, data_index.index});
217  }
218 
219  void add_no_data(double time)
220  {
221  index_data_map.push_back({time, time, -1ul});
222  }
223 
224  bool is_constant() const
225  {
226  return data.size() <= 1;
227  }
228 
229  size_t size() const
230  {
231  return data.size();
232  }
233 
234  void clear()
235  {
236  invalidate_last_loaded_time();
237  data.clear();
238  index_data_map.clear();
239  }
240 
241  void invalidate_last_loaded_time()
242  {
243  last_loaded_time = std::numeric_limits<double>::max();
244  }
245 
246  /* Copy the data for the specified time to the node's socket. If there is no
247  * data for this time or it was already loaded, do nothing. */
248  void copy_to_socket(double time, Node *node, const SocketType *socket)
249  {
250  CacheLookupResult<T> result = data_for_time(time);
251 
252  if (!result.has_new_data()) {
253  return;
254  }
255 
256  /* TODO(kevindietrich): arrays are emptied when passed to the sockets, so for now we copy the
257  * arrays to avoid reloading the data */
258  T value = result.get_data();
259  node->set(*socket, value);
260  }
261 
262  size_t memory_used() const
263  {
264  if constexpr (is_array<T>::value) {
265  size_t mem_used = 0;
266 
267  for (const T &array : data) {
268  mem_used += array.size() * sizeof(array[0]);
269  }
270 
271  return mem_used;
272  }
273 
274  return data.size() * sizeof(T);
275  }
276 
277  private:
278  const TimeIndexPair &get_index_for_time(double time) const
279  {
280  std::pair<size_t, Alembic::Abc::chrono_t> index_pair;
281  index_pair = time_sampling.getNearIndex(time, index_data_map.size());
282  return index_data_map[index_pair.first];
283  }
284 };
285 
286 /* Actual cache for the stored data.
287  * This caches the topological, transformation, and attribute data for a Mesh node or a Hair node
288  * inside of DataStores.
289  */
290 struct CachedData {
291  DataStore<Transform> transforms{};
292 
293  /* mesh data */
294  DataStore<array<float3>> vertices;
295  DataStore<array<int3>> triangles{};
296  /* triangle "loops" are the polygons' vertices indices used for indexing face varying attributes
297  * (like UVs) */
298  DataStore<array<int>> uv_loops{};
299  DataStore<array<int>> shader{};
300 
301  /* subd data */
302  DataStore<array<int>> subd_start_corner;
303  DataStore<array<int>> subd_num_corners;
304  DataStore<array<bool>> subd_smooth;
305  DataStore<array<int>> subd_ptex_offset;
306  DataStore<array<int>> subd_face_corners;
307  DataStore<int> num_ngons;
308  DataStore<array<int>> subd_creases_edge;
309  DataStore<array<float>> subd_creases_weight;
310  DataStore<array<int>> subd_vertex_crease_indices;
311  DataStore<array<float>> subd_vertex_crease_weights;
312 
313  /* hair data */
314  DataStore<array<float3>> curve_keys;
315  DataStore<array<float>> curve_radius;
316  DataStore<array<int>> curve_first_key;
317  DataStore<array<int>> curve_shader;
318 
319  /* point data */
320  DataStore<array<float3>> points;
321  DataStore<array<float>> radiuses;
322  DataStore<array<int>> points_shader;
323 
324  struct CachedAttribute {
327  TypeDesc type_desc;
328  ustring name;
329  DataStore<array<char>> data{};
330  };
331 
332  vector<CachedAttribute> attributes{};
333 
334  void clear();
335 
336  CachedAttribute &add_attribute(const ustring &name,
337  const Alembic::Abc::TimeSampling &time_sampling);
338 
339  bool is_constant() const;
340 
341  void invalidate_last_loaded_time(bool attributes_only = false);
342 
343  void set_time_sampling(Alembic::AbcCoreAbstract::TimeSampling time_sampling);
344 
345  size_t memory_used() const;
346 };
347 
348 /* Representation of an Alembic object for the AlembicProcedural.
349  *
350  * The AlembicObject holds the path to the Alembic IObject inside of the archive that is desired
351  * for rendering, as well as the list of shaders that it is using.
352  *
353  * The names of the shaders should correspond to the names of the FaceSets inside of the Alembic
354  * archive for per-triangle shader association. If there is no FaceSets, or the names do not
355  * match, the first shader is used for rendering for all triangles.
356  */
357 class AlembicObject : public Node {
358  public:
360 
361  /* Path to the IObject inside of the archive. */
362  NODE_SOCKET_API(ustring, path)
363 
364  /* Shaders used for rendering. */
365  NODE_SOCKET_API_ARRAY(array<Node *>, used_shaders)
366 
367  /* Treat this subdivision object as a regular polygon mesh, so no subdivision will be performed.
368  */
369  NODE_SOCKET_API(bool, ignore_subdivision)
370 
371  /* Maximum number of subdivisions for ISubD objects. */
372  NODE_SOCKET_API(int, subd_max_level)
373 
374  /* Finest level of detail (in pixels) for the subdivision. */
375  NODE_SOCKET_API(float, subd_dicing_rate)
376 
377  /* Scale the radius of points and curves. */
378  NODE_SOCKET_API(float, radius_scale)
379 
380  AlembicObject();
381  ~AlembicObject();
382 
383  private:
384  friend class AlembicProcedural;
385 
386  void set_object(Object *object);
387  Object *get_object();
388 
389  void load_data_in_cache(CachedData &cached_data,
390  AlembicProcedural *proc,
391  Alembic::AbcGeom::IPolyMeshSchema &schema,
392  Progress &progress);
393  void load_data_in_cache(CachedData &cached_data,
394  AlembicProcedural *proc,
395  Alembic::AbcGeom::ISubDSchema &schema,
396  Progress &progress);
397  void load_data_in_cache(CachedData &cached_data,
398  AlembicProcedural *proc,
399  const Alembic::AbcGeom::ICurvesSchema &schema,
400  Progress &progress);
401 
402  bool has_data_loaded() const;
403 
404  /* Enumeration used to speed up the discrimination of an IObject as IObject::matches() methods
405  * are too expensive and show up in profiles. */
406  enum AbcSchemaType {
407  INVALID,
408  POLY_MESH,
409  SUBD,
410  CURVES,
411  POINTS,
412  };
413 
414  bool need_shader_update = true;
415 
416  AlembicObject *instance_of = nullptr;
417 
418  Alembic::AbcCoreAbstract::TimeSamplingPtr xform_time_sampling;
419  MatrixSampleMap xform_samples;
420  Alembic::AbcGeom::IObject iobject;
421 
422  /* Set if the path points to a valid IObject whose type is supported. */
423  AbcSchemaType schema_type;
424 
425  CachedData &get_cached_data()
426  {
427  return cached_data_;
428  }
429 
430  bool is_constant() const
431  {
432  return cached_data_.is_constant();
433  }
434 
435  void clear_cache()
436  {
437  cached_data_.clear();
438  }
439 
440  Object *object = nullptr;
441 
442  bool data_loaded = false;
443 
444  CachedData cached_data_;
445 
446  void setup_transform_cache(CachedData &cached_data, float scale);
447 
448  AttributeRequestSet get_requested_attributes();
449 };
450 
451 /* Procedural to render objects from a single Alembic archive.
452  *
453  * Every object desired to be rendered should be passed as an AlembicObject through the objects
454  * socket.
455  *
456  * This procedural will load the data set for the entire animation in memory on the first frame,
457  * and directly set the data for the new frames on the created Nodes if needed. This allows for
458  * faster updates between frames as it avoids reseeking the data on disk.
459  */
460 class AlembicProcedural : public Procedural {
461  Alembic::AbcGeom::IArchive archive;
462  bool objects_loaded;
463  Scene *scene_;
464 
465  public:
467 
468  /* The file path to the Alembic archive */
469  NODE_SOCKET_API(ustring, filepath)
470 
471  /* Layers for the Alembic archive. Layers are in the order in which they override data, with the
472  * latter elements overriding the former ones. */
474 
475  /* The current frame to render. */
476  NODE_SOCKET_API(float, frame)
477 
478  /* The first frame to load data for. */
479  NODE_SOCKET_API(float, start_frame)
480 
481  /* The last frame to load data for. */
482  NODE_SOCKET_API(float, end_frame)
483 
484  /* Subtracted to the current frame. */
485  NODE_SOCKET_API(float, frame_offset)
486 
487  /* The frame rate used for rendering in units of frames per second. */
488  NODE_SOCKET_API(float, frame_rate)
489 
490  /* List of AlembicObjects to render. */
492 
493  /* Set the default radius to use for curves when the Alembic Curves Schemas do not have radius
494  * information. */
495  NODE_SOCKET_API(float, default_radius)
496 
497  /* Multiplier to account for differences in default units for measuring objects in various
498  * software. */
499  NODE_SOCKET_API(float, scale)
500 
501  /* Cache controls */
502  NODE_SOCKET_API(bool, use_prefetch)
503 
504  /* Memory limit for the cache, if the data does not fit within this limit, rendering is aborted.
505  */
506  NODE_SOCKET_API(int, prefetch_cache_size)
507 
508  AlembicProcedural();
509  ~AlembicProcedural();
510 
511  /* Populates the Cycles scene with Nodes for every contained AlembicObject on the first
512  * invocation, and updates the data on subsequent invocations if the frame changed. */
513  void generate(Scene *scene, Progress &progress);
514 
515  /* Tag for an update only if something was modified. */
516  void tag_update(Scene *scene);
517 
518  /* This should be called by scene exporters to request the rendering of an object located
519  * in the Alembic archive at the given path.
520  *
521  * Since we lazily load object, the function does not validate the existence of the object
522  * in the archive. If no objects with such path if found in the archive during the next call
523  * to `generate`, it will be ignored.
524  *
525  * Returns a pointer to an existing or a newly created AlembicObject for the given path. */
526  AlembicObject *get_or_create_object(const ustring &path);
527 
528  private:
529  /* Add an object to our list of objects, and tag the socket as modified. */
530  void add_object(AlembicObject *object);
531 
532  /* Load the data for all the objects whose data has not yet been loaded. */
533  void load_objects(Progress &progress);
534 
535  /* Traverse the Alembic hierarchy to lookup the IObjects for the AlembicObjects that were
536  * specified in our objects socket, and accumulate all of the transformations samples along the
537  * way for each IObject. */
538  void walk_hierarchy(Alembic::AbcGeom::IObject parent,
539  const Alembic::AbcGeom::ObjectHeader &ohead,
540  MatrixSamplesData matrix_samples_data,
541  const unordered_map<string, AlembicObject *> &object_map,
542  Progress &progress);
543 
544  /* Read the data for an IPolyMesh at the specified frame_time. Creates corresponding Geometry and
545  * Object Nodes in the Cycles scene if none exist yet. */
546  void read_mesh(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
547 
548  /* Read the data for an ICurves at the specified frame_time. Creates corresponding Geometry and
549  * Object Nodes in the Cycles scene if none exist yet. */
550  void read_curves(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
551 
552  /* Read the data for an IPoints at the specified frame_time. Creates corresponding Geometry and
553  * Object Nodes in the Cycles scene if none exist yet. */
554  void read_points(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
555 
556  /* Read the data for an ISubD at the specified frame_time. Creates corresponding Geometry and
557  * Object Nodes in the Cycles scene if none exist yet. */
558  void read_subd(AlembicObject *abc_object, Alembic::AbcGeom::Abc::chrono_t frame_time);
559 
560  void build_caches(Progress &progress);
561 
562  size_t get_prefetch_cache_size_in_bytes() const
563  {
564  /* prefetch_cache_size is in megabytes, so convert to bytes. */
565  return static_cast<size_t>(prefetch_cache_size) * 1024 * 1024;
566  }
567 };
568 
570 
571 #endif
struct Key Key
ATTR_WARN_UNUSED_RESULT const void * element
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
virtual void generate(Scene *scene, Progress &progress)=0
size_t size() const
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
OperationNode * node
double time
Scene scene
T * data_
Definition: eval_output.h:163
#define NODE_SOCKET_API_ARRAY(type_, name)
Definition: graph/node.h:62
#define NODE_SOCKET_API(type_, name)
Definition: graph/node.h:54
const int state
AttributeStandard
Definition: kernel/types.h:612
AttributeElement
Definition: kernel/types.h:597
#define T
static void clear(Message *msg)
Definition: msgfmt.c:278
#define NODE_DECLARE
Definition: node_type.h:135
float max