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