Blender  V3.3
alembic.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include "scene/alembic.h"
5 
6 #include "scene/alembic_read.h"
7 #include "scene/camera.h"
8 #include "scene/curves.h"
9 #include "scene/mesh.h"
10 #include "scene/object.h"
11 #include "scene/pointcloud.h"
12 #include "scene/scene.h"
13 #include "scene/shader.h"
14 
15 #include "util/foreach.h"
16 #include "util/log.h"
17 #include "util/progress.h"
18 #include "util/transform.h"
19 #include "util/vector.h"
20 
21 #ifdef WITH_ALEMBIC
22 
23 using namespace Alembic::AbcGeom;
24 
26 
27 /* TODO(kevindietrich): motion blur support. */
28 
29 template<typename SchemaType>
30 static vector<FaceSetShaderIndexPair> parse_face_sets_for_shader_assignment(
31  SchemaType &schema, const array<Node *> &used_shaders)
32 {
34 
35  std::vector<std::string> face_set_names;
36  schema.getFaceSetNames(face_set_names);
37 
38  if (face_set_names.empty()) {
39  return result;
40  }
41 
42  for (const std::string &face_set_name : face_set_names) {
43  int shader_index = 0;
44 
45  for (Node *node : used_shaders) {
46  if (node->name == face_set_name) {
47  break;
48  }
49 
50  ++shader_index;
51  }
52 
53  if (shader_index >= used_shaders.size()) {
54  /* use the first shader instead if none was found */
55  shader_index = 0;
56  }
57 
58  const Alembic::AbcGeom::IFaceSet face_set = schema.getFaceSet(face_set_name);
59 
60  if (!face_set.valid()) {
61  continue;
62  }
63 
64  result.push_back({face_set, shader_index});
65  }
66 
67  return result;
68 }
69 
70 void CachedData::clear()
71 {
72  attributes.clear();
73  curve_first_key.clear();
74  curve_keys.clear();
75  curve_radius.clear();
76  curve_shader.clear();
77  num_ngons.clear();
78  shader.clear();
79  subd_creases_edge.clear();
80  subd_creases_weight.clear();
81  subd_face_corners.clear();
82  subd_num_corners.clear();
83  subd_ptex_offset.clear();
84  subd_smooth.clear();
85  subd_start_corner.clear();
86  transforms.clear();
87  triangles.clear();
88  uv_loops.clear();
89  vertices.clear();
90  points.clear();
91  radiuses.clear();
92  points_shader.clear();
93 
94  for (CachedAttribute &attr : attributes) {
95  attr.data.clear();
96  }
97 
98  attributes.clear();
99 }
100 
101 CachedData::CachedAttribute &CachedData::add_attribute(const ustring &name,
102  const TimeSampling &time_sampling)
103 {
104  for (auto &attr : attributes) {
105  if (attr.name == name) {
106  return attr;
107  }
108  }
109 
110  CachedAttribute &attr = attributes.emplace_back();
111  attr.name = name;
112  attr.data.set_time_sampling(time_sampling);
113  return attr;
114 }
115 
116 bool CachedData::is_constant() const
117 {
118 # define CHECK_IF_CONSTANT(data) \
119  if (!data.is_constant()) { \
120  return false; \
121  }
122 
123  CHECK_IF_CONSTANT(curve_first_key)
124  CHECK_IF_CONSTANT(curve_keys)
125  CHECK_IF_CONSTANT(curve_radius)
126  CHECK_IF_CONSTANT(curve_shader)
127  CHECK_IF_CONSTANT(num_ngons)
128  CHECK_IF_CONSTANT(shader)
129  CHECK_IF_CONSTANT(subd_creases_edge)
130  CHECK_IF_CONSTANT(subd_creases_weight)
131  CHECK_IF_CONSTANT(subd_face_corners)
132  CHECK_IF_CONSTANT(subd_num_corners)
133  CHECK_IF_CONSTANT(subd_ptex_offset)
134  CHECK_IF_CONSTANT(subd_smooth)
135  CHECK_IF_CONSTANT(subd_start_corner)
136  CHECK_IF_CONSTANT(transforms)
137  CHECK_IF_CONSTANT(triangles)
138  CHECK_IF_CONSTANT(uv_loops)
139  CHECK_IF_CONSTANT(vertices)
140  CHECK_IF_CONSTANT(points)
141  CHECK_IF_CONSTANT(radiuses)
142  CHECK_IF_CONSTANT(points_shader)
143 
144  for (const CachedAttribute &attr : attributes) {
145  if (!attr.data.is_constant()) {
146  return false;
147  }
148  }
149 
150  return true;
151 
152 # undef CHECK_IF_CONSTANT
153 }
154 
155 void CachedData::invalidate_last_loaded_time(bool attributes_only)
156 {
157  if (attributes_only) {
158  for (CachedAttribute &attr : attributes) {
159  attr.data.invalidate_last_loaded_time();
160  }
161 
162  return;
163  }
164 
165  curve_first_key.invalidate_last_loaded_time();
166  curve_keys.invalidate_last_loaded_time();
167  curve_radius.invalidate_last_loaded_time();
168  curve_shader.invalidate_last_loaded_time();
169  num_ngons.invalidate_last_loaded_time();
170  shader.invalidate_last_loaded_time();
171  subd_creases_edge.invalidate_last_loaded_time();
172  subd_creases_weight.invalidate_last_loaded_time();
173  subd_face_corners.invalidate_last_loaded_time();
174  subd_num_corners.invalidate_last_loaded_time();
175  subd_ptex_offset.invalidate_last_loaded_time();
176  subd_smooth.invalidate_last_loaded_time();
177  subd_start_corner.invalidate_last_loaded_time();
178  transforms.invalidate_last_loaded_time();
179  triangles.invalidate_last_loaded_time();
180  uv_loops.invalidate_last_loaded_time();
181  vertices.invalidate_last_loaded_time();
182  points.invalidate_last_loaded_time();
183  radiuses.invalidate_last_loaded_time();
184  points_shader.invalidate_last_loaded_time();
185 }
186 
187 void CachedData::set_time_sampling(TimeSampling time_sampling)
188 {
189  curve_first_key.set_time_sampling(time_sampling);
190  curve_keys.set_time_sampling(time_sampling);
191  curve_radius.set_time_sampling(time_sampling);
192  curve_shader.set_time_sampling(time_sampling);
193  num_ngons.set_time_sampling(time_sampling);
194  shader.set_time_sampling(time_sampling);
195  subd_creases_edge.set_time_sampling(time_sampling);
196  subd_creases_weight.set_time_sampling(time_sampling);
197  subd_face_corners.set_time_sampling(time_sampling);
198  subd_num_corners.set_time_sampling(time_sampling);
199  subd_ptex_offset.set_time_sampling(time_sampling);
200  subd_smooth.set_time_sampling(time_sampling);
201  subd_start_corner.set_time_sampling(time_sampling);
202  transforms.set_time_sampling(time_sampling);
203  triangles.set_time_sampling(time_sampling);
204  uv_loops.set_time_sampling(time_sampling);
205  vertices.set_time_sampling(time_sampling);
206  points.set_time_sampling(time_sampling);
207  radiuses.set_time_sampling(time_sampling);
208  points_shader.set_time_sampling(time_sampling);
209 
210  for (CachedAttribute &attr : attributes) {
211  attr.data.set_time_sampling(time_sampling);
212  }
213 }
214 
215 size_t CachedData::memory_used() const
216 {
217  size_t mem_used = 0;
218 
219  mem_used += curve_first_key.memory_used();
220  mem_used += curve_keys.memory_used();
221  mem_used += curve_radius.memory_used();
222  mem_used += curve_shader.memory_used();
223  mem_used += num_ngons.memory_used();
224  mem_used += shader.memory_used();
225  mem_used += subd_creases_edge.memory_used();
226  mem_used += subd_creases_weight.memory_used();
227  mem_used += subd_face_corners.memory_used();
228  mem_used += subd_num_corners.memory_used();
229  mem_used += subd_ptex_offset.memory_used();
230  mem_used += subd_smooth.memory_used();
231  mem_used += subd_start_corner.memory_used();
232  mem_used += transforms.memory_used();
233  mem_used += triangles.memory_used();
234  mem_used += uv_loops.memory_used();
235  mem_used += vertices.memory_used();
236  mem_used += points.memory_used();
237  mem_used += radiuses.memory_used();
238  mem_used += points_shader.memory_used();
239 
240  for (const CachedAttribute &attr : attributes) {
241  mem_used += attr.data.memory_used();
242  }
243 
244  return mem_used;
245 }
246 
247 static M44d convert_yup_zup(const M44d &mtx, float scale_mult)
248 {
249  V3d scale, shear, rotation, translation;
250  extractSHRT(mtx,
251  scale,
252  shear,
253  rotation,
254  translation,
255  true,
256  IMATH_INTERNAL_NAMESPACE::Euler<double>::XZY);
257 
258  M44d rot_mat, scale_mat, trans_mat;
259  rot_mat.setEulerAngles(V3d(rotation.x, -rotation.z, rotation.y));
260  scale_mat.setScale(V3d(scale.x, scale.z, scale.y));
261  trans_mat.setTranslation(V3d(translation.x, -translation.z, translation.y));
262 
263  M44d temp_mat = scale_mat * rot_mat * trans_mat;
264 
265  scale_mat.setScale(static_cast<double>(scale_mult));
266 
267  return temp_mat * scale_mat;
268 }
269 
270 static void transform_decompose(
271  const M44d &mat, V3d &scale, V3d &shear, Quatd &rotation, V3d &translation)
272 {
273  M44d mat_remainder(mat);
274 
275  /* extract scale and shear */
276  Imath::extractAndRemoveScalingAndShear(mat_remainder, scale, shear);
277 
278  /* extract translation */
279  translation.x = mat_remainder[3][0];
280  translation.y = mat_remainder[3][1];
281  translation.z = mat_remainder[3][2];
282 
283  /* extract rotation */
284  rotation = extractQuat(mat_remainder);
285 }
286 
287 static M44d transform_compose(const V3d &scale,
288  const V3d &shear,
289  const Quatd &rotation,
290  const V3d &translation)
291 {
292  M44d scale_mat, shear_mat, rot_mat, trans_mat;
293 
294  scale_mat.setScale(scale);
295  shear_mat.setShear(shear);
296  rot_mat = rotation.toMatrix44();
297  trans_mat.setTranslation(translation);
298 
299  return scale_mat * shear_mat * rot_mat * trans_mat;
300 }
301 
302 /* get the matrix for the specified time, or return the identity matrix if there is no exact match
303  */
304 static M44d get_matrix_for_time(const MatrixSampleMap &samples, chrono_t time)
305 {
306  MatrixSampleMap::const_iterator iter = samples.find(time);
307  if (iter != samples.end()) {
308  return iter->second;
309  }
310 
311  return M44d();
312 }
313 
314 /* get the matrix for the specified time, or interpolate between samples if there is no exact match
315  */
316 static M44d get_interpolated_matrix_for_time(const MatrixSampleMap &samples, chrono_t time)
317 {
318  if (samples.empty()) {
319  return M44d();
320  }
321 
322  /* see if exact match */
323  MatrixSampleMap::const_iterator iter = samples.find(time);
324  if (iter != samples.end()) {
325  return iter->second;
326  }
327 
328  if (samples.size() == 1) {
329  return samples.begin()->second;
330  }
331 
332  if (time <= samples.begin()->first) {
333  return samples.begin()->second;
334  }
335 
336  if (time >= samples.rbegin()->first) {
337  return samples.rbegin()->second;
338  }
339 
340  /* find previous and next time sample to interpolate */
341  chrono_t prev_time = samples.begin()->first;
342  chrono_t next_time = samples.rbegin()->first;
343 
344  for (MatrixSampleMap::const_iterator I = samples.begin(); I != samples.end(); ++I) {
345  chrono_t current_time = (*I).first;
346 
347  if (current_time > prev_time && current_time <= time) {
348  prev_time = current_time;
349  }
350 
351  if (current_time > next_time && current_time >= time) {
352  next_time = current_time;
353  }
354  }
355 
356  const M44d prev_mat = get_matrix_for_time(samples, prev_time);
357  const M44d next_mat = get_matrix_for_time(samples, next_time);
358 
359  V3d prev_scale, next_scale;
360  V3d prev_shear, next_shear;
361  V3d prev_translation, next_translation;
362  Quatd prev_rotation, next_rotation;
363 
364  transform_decompose(prev_mat, prev_scale, prev_shear, prev_rotation, prev_translation);
365  transform_decompose(next_mat, next_scale, next_shear, next_rotation, next_translation);
366 
367  chrono_t t = (time - prev_time) / (next_time - prev_time);
368 
369  /* Ensure rotation around the shortest angle. */
370  if ((prev_rotation ^ next_rotation) < 0) {
371  next_rotation = -next_rotation;
372  }
373 
374  return transform_compose(Imath::lerp(prev_scale, next_scale, t),
375  Imath::lerp(prev_shear, next_shear, t),
376  Imath::slerp(prev_rotation, next_rotation, t),
377  Imath::lerp(prev_translation, next_translation, t));
378 }
379 
380 static void concatenate_xform_samples(const MatrixSampleMap &parent_samples,
381  const MatrixSampleMap &local_samples,
382  MatrixSampleMap &output_samples)
383 {
384  set<chrono_t> union_of_samples;
385 
386  for (const std::pair<chrono_t, M44d> pair : parent_samples) {
387  union_of_samples.insert(pair.first);
388  }
389 
390  for (const std::pair<chrono_t, M44d> pair : local_samples) {
391  union_of_samples.insert(pair.first);
392  }
393 
394  foreach (chrono_t time, union_of_samples) {
395  M44d parent_matrix = get_interpolated_matrix_for_time(parent_samples, time);
396  M44d local_matrix = get_interpolated_matrix_for_time(local_samples, time);
397 
398  output_samples[time] = local_matrix * parent_matrix;
399  }
400 }
401 
402 static Transform make_transform(const M44d &a, float scale)
403 {
404  M44d m = convert_yup_zup(a, scale);
405  Transform trans;
406  for (int j = 0; j < 3; j++) {
407  for (int i = 0; i < 4; i++) {
408  trans[j][i] = static_cast<float>(m[i][j]);
409  }
410  }
411  return trans;
412 }
413 
414 NODE_DEFINE(AlembicObject)
415 {
416  NodeType *type = NodeType::add("alembic_object", create);
417 
418  SOCKET_STRING(path, "Alembic Path", ustring());
419  SOCKET_NODE_ARRAY(used_shaders, "Used Shaders", Shader::get_node_type());
420 
421  SOCKET_BOOLEAN(ignore_subdivision, "Ignore Subdivision", true);
422 
423  SOCKET_INT(subd_max_level, "Max Subdivision Level", 1);
424  SOCKET_FLOAT(subd_dicing_rate, "Subdivision Dicing Rate", 1.0f);
425 
426  SOCKET_FLOAT(radius_scale, "Radius Scale", 1.0f);
427 
428  return type;
429 }
430 
431 AlembicObject::AlembicObject() : Node(get_node_type())
432 {
433  schema_type = INVALID;
434 }
435 
436 AlembicObject::~AlembicObject()
437 {
438 }
439 
440 void AlembicObject::set_object(Object *object_)
441 {
442  object = object_;
443 }
444 
445 Object *AlembicObject::get_object()
446 {
447  return object;
448 }
449 
450 bool AlembicObject::has_data_loaded() const
451 {
452  return data_loaded;
453 }
454 
455 void AlembicObject::load_data_in_cache(CachedData &cached_data,
456  AlembicProcedural *proc,
457  IPolyMeshSchema &schema,
458  Progress &progress)
459 {
460  /* Only load data for the original Geometry. */
461  if (instance_of) {
462  return;
463  }
464 
465  cached_data.clear();
466 
467  PolyMeshSchemaData data;
468  data.topology_variance = schema.getTopologyVariance();
469  data.time_sampling = schema.getTimeSampling();
470  data.positions = schema.getPositionsProperty();
471  data.face_counts = schema.getFaceCountsProperty();
472  data.face_indices = schema.getFaceIndicesProperty();
473  data.normals = schema.getNormalsParam();
474  data.num_samples = schema.getNumSamples();
475  data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders());
476 
477  read_geometry_data(proc, cached_data, data, progress);
478 
479  if (progress.get_cancel()) {
480  return;
481  }
482 
483  /* Use the schema as the base compound property to also be able to look for top level properties.
484  */
485  read_attributes(
486  proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
487 
488  if (progress.get_cancel()) {
489  return;
490  }
491 
492  cached_data.invalidate_last_loaded_time(true);
493  data_loaded = true;
494 }
495 
496 void AlembicObject::load_data_in_cache(CachedData &cached_data,
497  AlembicProcedural *proc,
498  ISubDSchema &schema,
499  Progress &progress)
500 {
501  /* Only load data for the original Geometry. */
502  if (instance_of) {
503  return;
504  }
505 
506  cached_data.clear();
507 
508  if (this->get_ignore_subdivision()) {
509  PolyMeshSchemaData data;
510  data.topology_variance = schema.getTopologyVariance();
511  data.time_sampling = schema.getTimeSampling();
512  data.positions = schema.getPositionsProperty();
513  data.face_counts = schema.getFaceCountsProperty();
514  data.face_indices = schema.getFaceIndicesProperty();
515  data.num_samples = schema.getNumSamples();
516  data.velocities = schema.getVelocitiesProperty();
517  data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders());
518 
519  read_geometry_data(proc, cached_data, data, progress);
520 
521  if (progress.get_cancel()) {
522  return;
523  }
524 
525  /* Use the schema as the base compound property to also be able to look for top level
526  * properties. */
527  read_attributes(
528  proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
529 
530  cached_data.invalidate_last_loaded_time(true);
531  data_loaded = true;
532  return;
533  }
534 
535  SubDSchemaData data;
536  data.time_sampling = schema.getTimeSampling();
537  data.num_samples = schema.getNumSamples();
538  data.topology_variance = schema.getTopologyVariance();
539  data.face_counts = schema.getFaceCountsProperty();
540  data.face_indices = schema.getFaceIndicesProperty();
541  data.positions = schema.getPositionsProperty();
542  data.face_varying_interpolate_boundary = schema.getFaceVaryingInterpolateBoundaryProperty();
543  data.face_varying_propagate_corners = schema.getFaceVaryingPropagateCornersProperty();
544  data.interpolate_boundary = schema.getInterpolateBoundaryProperty();
545  data.crease_indices = schema.getCreaseIndicesProperty();
546  data.crease_lengths = schema.getCreaseLengthsProperty();
547  data.crease_sharpnesses = schema.getCreaseSharpnessesProperty();
548  data.corner_indices = schema.getCornerIndicesProperty();
549  data.corner_sharpnesses = schema.getCornerSharpnessesProperty();
550  data.holes = schema.getHolesProperty();
551  data.subdivision_scheme = schema.getSubdivisionSchemeProperty();
552  data.velocities = schema.getVelocitiesProperty();
553  data.shader_face_sets = parse_face_sets_for_shader_assignment(schema, get_used_shaders());
554 
555  read_geometry_data(proc, cached_data, data, progress);
556 
557  if (progress.get_cancel()) {
558  return;
559  }
560 
561  /* Use the schema as the base compound property to also be able to look for top level properties.
562  */
563  read_attributes(
564  proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
565 
566  cached_data.invalidate_last_loaded_time(true);
567  data_loaded = true;
568 }
569 
570 void AlembicObject::load_data_in_cache(CachedData &cached_data,
571  AlembicProcedural *proc,
572  const ICurvesSchema &schema,
573  Progress &progress)
574 {
575  /* Only load data for the original Geometry. */
576  if (instance_of) {
577  return;
578  }
579 
580  cached_data.clear();
581 
582  CurvesSchemaData data;
583  data.positions = schema.getPositionsProperty();
584  data.position_weights = schema.getPositionWeightsProperty();
585  data.normals = schema.getNormalsParam();
586  data.knots = schema.getKnotsProperty();
587  data.orders = schema.getOrdersProperty();
588  data.widths = schema.getWidthsParam();
589  data.velocities = schema.getVelocitiesProperty();
590  data.time_sampling = schema.getTimeSampling();
591  data.topology_variance = schema.getTopologyVariance();
592  data.num_samples = schema.getNumSamples();
593  data.num_vertices = schema.getNumVerticesProperty();
594  data.default_radius = proc->get_default_radius();
595  data.radius_scale = get_radius_scale();
596 
597  read_geometry_data(proc, cached_data, data, progress);
598 
599  if (progress.get_cancel()) {
600  return;
601  }
602 
603  /* Use the schema as the base compound property to also be able to look for top level properties.
604  */
605  read_attributes(
606  proc, cached_data, schema, schema.getUVsParam(), get_requested_attributes(), progress);
607 
608  cached_data.invalidate_last_loaded_time(true);
609  data_loaded = true;
610 }
611 
612 void AlembicObject::setup_transform_cache(CachedData &cached_data, float scale)
613 {
614  cached_data.transforms.clear();
615  cached_data.transforms.invalidate_last_loaded_time();
616 
617  if (scale == 0.0f) {
618  scale = 1.0f;
619  }
620 
621  if (xform_time_sampling) {
622  cached_data.transforms.set_time_sampling(*xform_time_sampling);
623  }
624 
625  if (xform_samples.size() == 0) {
626  Transform tfm = transform_scale(make_float3(scale));
627  cached_data.transforms.add_data(tfm, 0.0);
628  }
629  else {
630  /* It is possible for a leaf node of the hierarchy to have multiple samples for its transforms
631  * if a sibling has animated transforms. So check if we indeed have animated transformations.
632  */
633  M44d first_matrix = xform_samples.begin()->first;
634  bool has_animation = false;
635  for (const std::pair<chrono_t, M44d> pair : xform_samples) {
636  if (pair.second != first_matrix) {
637  has_animation = true;
638  break;
639  }
640  }
641 
642  if (!has_animation) {
643  Transform tfm = make_transform(first_matrix, scale);
644  cached_data.transforms.add_data(tfm, 0.0);
645  }
646  else {
647  for (const std::pair<chrono_t, M44d> pair : xform_samples) {
648  Transform tfm = make_transform(pair.second, scale);
649  cached_data.transforms.add_data(tfm, pair.first);
650  }
651  }
652  }
653 }
654 
655 AttributeRequestSet AlembicObject::get_requested_attributes()
656 {
657  AttributeRequestSet requested_attributes;
658 
659  Geometry *geometry = object->get_geometry();
660  assert(geometry);
661 
662  foreach (Node *node, geometry->get_used_shaders()) {
663  Shader *shader = static_cast<Shader *>(node);
664 
665  foreach (const AttributeRequest &attr, shader->attributes.requests) {
666  if (attr.name != "") {
667  requested_attributes.add(attr.name);
668  }
669  }
670  }
671 
672  return requested_attributes;
673 }
674 
675 /* Update existing attributes and remove any attribute not in the cached_data, those attributes
676  * were added by Cycles (e.g. face normals) */
677 static void update_attributes(AttributeSet &attributes, CachedData &cached_data, double frame_time)
678 {
679  set<Attribute *> cached_attributes;
680 
681  for (CachedData::CachedAttribute &attribute : cached_data.attributes) {
682  const CacheLookupResult<array<char>> result = attribute.data.data_for_time(frame_time);
683 
684  if (result.has_no_data_for_time()) {
685  continue;
686  }
687 
688  Attribute *attr = nullptr;
689  if (attribute.std != ATTR_STD_NONE) {
690  attr = attributes.add(attribute.std, attribute.name);
691  }
692  else {
693  attr = attributes.add(attribute.name, attribute.type_desc, attribute.element);
694  }
695  assert(attr);
696 
697  cached_attributes.insert(attr);
698 
699  if (!result.has_new_data()) {
700  continue;
701  }
702 
703  const ccl::array<char> &attr_data = result.get_data();
704 
705  /* weak way of detecting if the topology has changed
706  * todo: reuse code from device_update patch */
707  if (attr->buffer.size() != attr_data.size()) {
708  attr->buffer.resize(attr_data.size());
709  }
710 
711  memcpy(attr->data(), attr_data.data(), attr_data.size());
712  attr->modified = true;
713  }
714 
715  /* remove any attributes not in cached_attributes */
716  list<Attribute>::iterator it;
717  for (it = attributes.attributes.begin(); it != attributes.attributes.end();) {
718  if (cached_attributes.find(&(*it)) == cached_attributes.end()) {
719  attributes.remove(it++);
720  continue;
721  }
722 
723  it++;
724  }
725 }
726 
727 NODE_DEFINE(AlembicProcedural)
728 {
729  NodeType *type = NodeType::add("alembic", create);
730 
731  SOCKET_STRING(filepath, "Filename", ustring());
732  SOCKET_STRING_ARRAY(layers, "Layers", array<ustring>());
733  SOCKET_FLOAT(frame, "Frame", 1.0f);
734  SOCKET_FLOAT(start_frame, "Start Frame", 1.0f);
735  SOCKET_FLOAT(end_frame, "End Frame", 1.0f);
736  SOCKET_FLOAT(frame_rate, "Frame Rate", 24.0f);
737  SOCKET_FLOAT(frame_offset, "Frame Offset", 0.0f);
738  SOCKET_FLOAT(default_radius, "Default Radius", 0.01f);
739  SOCKET_FLOAT(scale, "Scale", 1.0f);
740 
741  SOCKET_NODE_ARRAY(objects, "Objects", AlembicObject::get_node_type());
742 
743  SOCKET_BOOLEAN(use_prefetch, "Use Prefetch", true);
744  SOCKET_INT(prefetch_cache_size, "Prefetch Cache Size", 4096);
745 
746  return type;
747 }
748 
749 AlembicProcedural::AlembicProcedural() : Procedural(get_node_type())
750 {
751  objects_loaded = false;
752  scene_ = nullptr;
753 }
754 
755 AlembicProcedural::~AlembicProcedural()
756 {
757  ccl::set<Geometry *> geometries_set;
758  ccl::set<Object *> objects_set;
759  ccl::set<AlembicObject *> abc_objects_set;
760 
761  foreach (Node *node, objects) {
762  AlembicObject *abc_object = static_cast<AlembicObject *>(node);
763 
764  if (abc_object->get_object()) {
765  objects_set.insert(abc_object->get_object());
766 
767  if (abc_object->get_object()->get_geometry()) {
768  geometries_set.insert(abc_object->get_object()->get_geometry());
769  }
770  }
771 
772  delete_node(abc_object);
773  }
774 
775  /* We may delete a Procedural before rendering started, so scene_ can be null. */
776  if (!scene_) {
777  assert(geometries_set.empty());
778  assert(objects_set.empty());
779  return;
780  }
781 
782  scene_->delete_nodes(geometries_set, this);
783  scene_->delete_nodes(objects_set, this);
784 }
785 
787 {
788  assert(scene_ == nullptr || scene_ == scene);
789  scene_ = scene;
790 
791  if (frame < start_frame || frame > end_frame) {
792  clear_modified();
793  return;
794  }
795 
796  bool need_shader_updates = false;
797  bool need_data_updates = false;
798 
799  foreach (Node *object_node, objects) {
800  AlembicObject *object = static_cast<AlembicObject *>(object_node);
801 
802  if (object->is_modified()) {
803  need_data_updates = true;
804  }
805 
806  /* Check if the shaders were modified. */
807  if (object->used_shaders_is_modified() && object->get_object() &&
808  object->get_object()->get_geometry()) {
809  Geometry *geometry = object->get_object()->get_geometry();
810  array<Node *> used_shaders = object->get_used_shaders();
811  geometry->set_used_shaders(used_shaders);
812  need_shader_updates = true;
813  }
814 
815  /* Check for changes in shaders (e.g. newly requested attributes). */
816  foreach (Node *shader_node, object->get_used_shaders()) {
817  Shader *shader = static_cast<Shader *>(shader_node);
818 
819  if (shader->need_update_geometry()) {
820  object->need_shader_update = true;
821  need_shader_updates = true;
822  }
823  }
824  }
825 
826  if (!is_modified() && !need_shader_updates && !need_data_updates) {
827  return;
828  }
829 
830  if (!archive.valid() || filepath_is_modified() || layers_is_modified()) {
831  Alembic::AbcCoreFactory::IFactory factory;
832  factory.setPolicy(Alembic::Abc::ErrorHandler::kQuietNoopPolicy);
833 
834  std::vector<std::string> filenames;
835  filenames.push_back(filepath.c_str());
836 
837  for (const ustring &layer : layers) {
838  filenames.push_back(layer.c_str());
839  }
840 
841  /* We need to reverse the order as overriding archives should come first. */
842  std::reverse(filenames.begin(), filenames.end());
843 
844  archive = factory.getArchive(filenames);
845 
846  if (!archive.valid()) {
847  /* avoid potential infinite update loops in viewport synchronization */
848  filepath.clear();
849  layers.clear();
850  clear_modified();
851  return;
852  }
853  }
854 
855  if (!objects_loaded || objects_is_modified()) {
856  load_objects(progress);
857  objects_loaded = true;
858  }
859 
860  const chrono_t frame_time = (chrono_t)((frame - frame_offset) / frame_rate);
861 
862  /* Clear the subdivision caches as the data is stored differently. */
863  for (Node *node : objects) {
864  AlembicObject *object = static_cast<AlembicObject *>(node);
865 
866  if (object->schema_type != AlembicObject::SUBD) {
867  continue;
868  }
869 
870  if (object->ignore_subdivision_is_modified()) {
871  object->clear_cache();
872  }
873  }
874 
875  if (use_prefetch_is_modified()) {
876  if (!use_prefetch) {
877  for (Node *node : objects) {
878  AlembicObject *object = static_cast<AlembicObject *>(node);
879  object->clear_cache();
880  }
881  }
882  }
883 
884  if (prefetch_cache_size_is_modified()) {
885  /* Check whether the current memory usage fits in the new requested size,
886  * abort the render if it is any higher. */
887  size_t memory_used = 0ul;
888  for (Node *node : objects) {
889  AlembicObject *object = static_cast<AlembicObject *>(node);
890  memory_used += object->get_cached_data().memory_used();
891  }
892 
893  if (memory_used > get_prefetch_cache_size_in_bytes()) {
894  progress.set_error("Error: Alembic Procedural memory limit reached");
895  return;
896  }
897  }
898 
899  build_caches(progress);
900 
901  foreach (Node *node, objects) {
902  AlembicObject *object = static_cast<AlembicObject *>(node);
903 
904  if (progress.get_cancel()) {
905  return;
906  }
907 
908  /* skip constant objects */
909  if (object->is_constant() && !object->is_modified() && !object->need_shader_update &&
910  !scale_is_modified()) {
911  continue;
912  }
913 
914  if (object->schema_type == AlembicObject::POLY_MESH) {
915  read_mesh(object, frame_time);
916  }
917  else if (object->schema_type == AlembicObject::CURVES) {
918  read_curves(object, frame_time);
919  }
920  else if (object->schema_type == AlembicObject::POINTS) {
921  read_points(object, frame_time);
922  }
923  else if (object->schema_type == AlembicObject::SUBD) {
924  read_subd(object, frame_time);
925  }
926 
927  object->need_shader_update = false;
928  object->clear_modified();
929  }
930 
931  clear_modified();
932 }
933 
934 void AlembicProcedural::add_object(AlembicObject *object)
935 {
936  objects.push_back_slow(object);
937  tag_objects_modified();
938 }
939 
940 void AlembicProcedural::tag_update(Scene *scene)
941 {
943 }
944 
945 AlembicObject *AlembicProcedural::get_or_create_object(const ustring &path)
946 {
947  foreach (Node *node, objects) {
948  AlembicObject *object = static_cast<AlembicObject *>(node);
949 
950  if (object->get_path() == path) {
951  return object;
952  }
953  }
954 
955  AlembicObject *object = create_node<AlembicObject>();
956  object->set_path(path);
957 
958  add_object(object);
959 
960  return object;
961 }
962 
963 void AlembicProcedural::load_objects(Progress &progress)
964 {
965  unordered_map<string, AlembicObject *> object_map;
966 
967  foreach (Node *node, objects) {
968  AlembicObject *object = static_cast<AlembicObject *>(node);
969 
970  /* only consider newly added objects */
971  if (object->get_object() == nullptr) {
972  object_map.insert({object->get_path().c_str(), object});
973  }
974  }
975 
976  IObject root = archive.getTop();
977 
978  for (size_t i = 0; i < root.getNumChildren(); ++i) {
979  walk_hierarchy(root, root.getChildHeader(i), {}, object_map, progress);
980  }
981 
982  /* Create nodes in the scene. */
983  for (std::pair<string, AlembicObject *> pair : object_map) {
984  AlembicObject *abc_object = pair.second;
985 
986  Geometry *geometry = nullptr;
987 
988  if (!abc_object->instance_of) {
989  if (abc_object->schema_type == AlembicObject::CURVES) {
990  geometry = scene_->create_node<Hair>();
991  }
992  else if (abc_object->schema_type == AlembicObject::POINTS) {
993  geometry = scene_->create_node<PointCloud>();
994  }
995  else if (abc_object->schema_type == AlembicObject::POLY_MESH ||
996  abc_object->schema_type == AlembicObject::SUBD) {
997  geometry = scene_->create_node<Mesh>();
998  }
999  else {
1000  continue;
1001  }
1002 
1003  geometry->set_owner(this);
1004  geometry->name = abc_object->iobject.getName();
1005 
1006  array<Node *> used_shaders = abc_object->get_used_shaders();
1007  geometry->set_used_shaders(used_shaders);
1008  }
1009 
1010  Object *object = scene_->create_node<Object>();
1011  object->set_owner(this);
1012  object->set_geometry(geometry);
1013  object->name = abc_object->iobject.getName();
1014 
1015  abc_object->set_object(object);
1016  }
1017 
1018  /* Share geometries between instances. */
1019  foreach (Node *node, objects) {
1020  AlembicObject *abc_object = static_cast<AlembicObject *>(node);
1021 
1022  if (abc_object->instance_of) {
1023  abc_object->get_object()->set_geometry(
1024  abc_object->instance_of->get_object()->get_geometry());
1025  abc_object->schema_type = abc_object->instance_of->schema_type;
1026  }
1027  }
1028 }
1029 
1030 void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame_time)
1031 {
1032  CachedData &cached_data = abc_object->get_cached_data();
1033 
1034  /* update sockets */
1035 
1036  Object *object = abc_object->get_object();
1037  cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
1038 
1039  if (object->is_modified()) {
1040  object->tag_update(scene_);
1041  }
1042 
1043  /* Only update sockets for the original Geometry. */
1044  if (abc_object->instance_of) {
1045  return;
1046  }
1047 
1048  Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
1049 
1050  /* Make sure shader ids are also updated. */
1051  if (mesh->used_shaders_is_modified()) {
1052  mesh->tag_shader_modified();
1053  }
1054 
1055  cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
1056 
1057  cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_shader_socket());
1058 
1059  array<int3> *triangle_data = cached_data.triangles.data_for_time(frame_time).get_data_or_null();
1060  if (triangle_data) {
1061  array<int> triangles;
1063 
1064  triangles.reserve(triangle_data->size() * 3);
1065  smooth.reserve(triangle_data->size());
1066 
1067  for (size_t i = 0; i < triangle_data->size(); ++i) {
1068  int3 tri = (*triangle_data)[i];
1069  triangles.push_back_reserved(tri.x);
1070  triangles.push_back_reserved(tri.y);
1071  triangles.push_back_reserved(tri.z);
1072  smooth.push_back_reserved(1);
1073  }
1074 
1075  mesh->set_triangles(triangles);
1076  mesh->set_smooth(smooth);
1077  }
1078 
1079  /* update attributes */
1080 
1081  update_attributes(mesh->attributes, cached_data, frame_time);
1082 
1083  if (mesh->is_modified()) {
1084  bool need_rebuild = mesh->triangles_is_modified();
1085  mesh->tag_update(scene_, need_rebuild);
1086  }
1087 }
1088 
1089 void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame_time)
1090 {
1091  if (abc_object->get_ignore_subdivision()) {
1092  read_mesh(abc_object, frame_time);
1093  return;
1094  }
1095 
1096  CachedData &cached_data = abc_object->get_cached_data();
1097 
1098  /* Update sockets. */
1099 
1100  Object *object = abc_object->get_object();
1101  cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
1102 
1103  if (object->is_modified()) {
1104  object->tag_update(scene_);
1105  }
1106 
1107  /* Only update sockets for the original Geometry. */
1108  if (abc_object->instance_of) {
1109  return;
1110  }
1111 
1112  if (abc_object->subd_max_level_is_modified() || abc_object->subd_dicing_rate_is_modified()) {
1113  /* need to reset the current data is something changed */
1114  cached_data.invalidate_last_loaded_time();
1115  }
1116 
1117  Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
1118 
1119  /* Make sure shader ids are also updated. */
1120  if (mesh->used_shaders_is_modified()) {
1121  mesh->tag_shader_modified();
1122  }
1123 
1124  /* Cycles overwrites the original triangles when computing displacement, so we always have to
1125  * repass the data if something is animated (vertices most likely) to avoid buffer overflows. */
1126  if (!cached_data.is_constant()) {
1127  cached_data.invalidate_last_loaded_time();
1128 
1129  /* remove previous triangles, if any */
1130  array<int> triangles;
1131  mesh->set_triangles(triangles);
1132  }
1133 
1135 
1136  /* Alembic is OpenSubDiv compliant, there is no option to set another subdivision type. */
1137  mesh->set_subdivision_type(Mesh::SubdivisionType::SUBDIVISION_CATMULL_CLARK);
1138  mesh->set_subd_max_level(abc_object->get_subd_max_level());
1139  mesh->set_subd_dicing_rate(abc_object->get_subd_dicing_rate());
1140 
1141  cached_data.vertices.copy_to_socket(frame_time, mesh, mesh->get_verts_socket());
1142 
1143  /* cached_data.shader is also used for subd_shader */
1144  cached_data.shader.copy_to_socket(frame_time, mesh, mesh->get_subd_shader_socket());
1145 
1146  cached_data.subd_start_corner.copy_to_socket(
1147  frame_time, mesh, mesh->get_subd_start_corner_socket());
1148 
1149  cached_data.subd_num_corners.copy_to_socket(
1150  frame_time, mesh, mesh->get_subd_num_corners_socket());
1151 
1152  cached_data.subd_smooth.copy_to_socket(frame_time, mesh, mesh->get_subd_smooth_socket());
1153 
1154  cached_data.subd_ptex_offset.copy_to_socket(
1155  frame_time, mesh, mesh->get_subd_ptex_offset_socket());
1156 
1157  cached_data.subd_face_corners.copy_to_socket(
1158  frame_time, mesh, mesh->get_subd_face_corners_socket());
1159 
1160  cached_data.num_ngons.copy_to_socket(frame_time, mesh, mesh->get_num_ngons_socket());
1161 
1162  cached_data.subd_creases_edge.copy_to_socket(
1163  frame_time, mesh, mesh->get_subd_creases_edge_socket());
1164 
1165  cached_data.subd_creases_weight.copy_to_socket(
1166  frame_time, mesh, mesh->get_subd_creases_weight_socket());
1167 
1168  cached_data.subd_vertex_crease_indices.copy_to_socket(
1169  frame_time, mesh, mesh->get_subd_vert_creases_socket());
1170 
1171  cached_data.subd_vertex_crease_weights.copy_to_socket(
1172  frame_time, mesh, mesh->get_subd_vert_creases_weight_socket());
1173 
1174  mesh->set_num_subd_faces(mesh->get_subd_shader().size());
1175 
1176  /* Update attributes. */
1177 
1178  update_attributes(mesh->subd_attributes, cached_data, frame_time);
1179 
1180  if (mesh->is_modified()) {
1181  bool need_rebuild = (mesh->triangles_is_modified()) ||
1182  (mesh->subd_num_corners_is_modified()) ||
1183  (mesh->subd_shader_is_modified()) || (mesh->subd_smooth_is_modified()) ||
1184  (mesh->subd_ptex_offset_is_modified()) ||
1185  (mesh->subd_start_corner_is_modified()) ||
1186  (mesh->subd_face_corners_is_modified());
1187 
1188  mesh->tag_update(scene_, need_rebuild);
1189  }
1190 }
1191 
1192 void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t frame_time)
1193 {
1194  CachedData &cached_data = abc_object->get_cached_data();
1195 
1196  /* update sockets */
1197 
1198  Object *object = abc_object->get_object();
1199  cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
1200 
1201  if (object->is_modified()) {
1202  object->tag_update(scene_);
1203  }
1204 
1205  /* Only update sockets for the original Geometry. */
1206  if (abc_object->instance_of) {
1207  return;
1208  }
1209 
1210  Hair *hair = static_cast<Hair *>(object->get_geometry());
1211 
1212  /* Make sure shader ids are also updated. */
1213  if (hair->used_shaders_is_modified()) {
1214  hair->tag_curve_shader_modified();
1215  }
1216 
1217  cached_data.curve_keys.copy_to_socket(frame_time, hair, hair->get_curve_keys_socket());
1218 
1219  cached_data.curve_radius.copy_to_socket(frame_time, hair, hair->get_curve_radius_socket());
1220 
1221  cached_data.curve_shader.copy_to_socket(frame_time, hair, hair->get_curve_shader_socket());
1222 
1223  cached_data.curve_first_key.copy_to_socket(frame_time, hair, hair->get_curve_first_key_socket());
1224 
1225  /* update attributes */
1226 
1227  update_attributes(hair->attributes, cached_data, frame_time);
1228 
1229  const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
1230  hair->tag_update(scene_, rebuild);
1231 }
1232 
1233 void AlembicProcedural::read_points(AlembicObject *abc_object, Abc::chrono_t frame_time)
1234 {
1235  CachedData &cached_data = abc_object->get_cached_data();
1236 
1237  /* update sockets */
1238 
1239  Object *object = abc_object->get_object();
1240  cached_data.transforms.copy_to_socket(frame_time, object, object->get_tfm_socket());
1241 
1242  if (object->is_modified()) {
1243  object->tag_update(scene_);
1244  }
1245 
1246  /* Only update sockets for the original Geometry. */
1247  if (abc_object->instance_of) {
1248  return;
1249  }
1250 
1251  PointCloud *point_cloud = static_cast<PointCloud *>(object->get_geometry());
1252 
1253  /* Make sure shader ids are also updated. */
1254  if (point_cloud->used_shaders_is_modified()) {
1255  point_cloud->tag_shader_modified();
1256  }
1257 
1258  cached_data.points.copy_to_socket(frame_time, point_cloud, point_cloud->get_points_socket());
1259  cached_data.radiuses.copy_to_socket(frame_time, point_cloud, point_cloud->get_radius_socket());
1260  cached_data.points_shader.copy_to_socket(
1261  frame_time, point_cloud, point_cloud->get_shader_socket());
1262 
1263  /* update attributes */
1264 
1265  update_attributes(point_cloud->attributes, cached_data, frame_time);
1266 
1267  const bool rebuild = (point_cloud->points_is_modified() || point_cloud->radius_is_modified() ||
1268  point_cloud->shader_is_modified());
1269  point_cloud->tag_update(scene_, rebuild);
1270 }
1271 
1272 void AlembicProcedural::walk_hierarchy(
1273  IObject parent,
1274  const ObjectHeader &header,
1275  MatrixSamplesData matrix_samples_data,
1276  const unordered_map<std::string, AlembicObject *> &object_map,
1277  Progress &progress)
1278 {
1279  if (progress.get_cancel()) {
1280  return;
1281  }
1282 
1283  IObject next_object;
1284 
1285  MatrixSampleMap concatenated_xform_samples;
1286 
1287  if (IXform::matches(header)) {
1288  IXform xform(parent, header.getName());
1289 
1290  IXformSchema &xs = xform.getSchema();
1291 
1292  if (xs.getNumOps() > 0) {
1293  TimeSamplingPtr ts = xs.getTimeSampling();
1294  MatrixSampleMap local_xform_samples;
1295 
1296  MatrixSampleMap *temp_xform_samples = nullptr;
1297  if (matrix_samples_data.samples == nullptr) {
1298  /* If there is no parent transforms, fill the map directly. */
1299  temp_xform_samples = &concatenated_xform_samples;
1300  }
1301  else {
1302  /* use a temporary map */
1303  temp_xform_samples = &local_xform_samples;
1304  }
1305 
1306  for (size_t i = 0; i < xs.getNumSamples(); ++i) {
1307  chrono_t sample_time = ts->getSampleTime(index_t(i));
1308  XformSample sample = xs.getValue(ISampleSelector(sample_time));
1309  temp_xform_samples->insert({sample_time, sample.getMatrix()});
1310  }
1311 
1312  if (matrix_samples_data.samples != nullptr) {
1313  concatenate_xform_samples(
1314  *matrix_samples_data.samples, local_xform_samples, concatenated_xform_samples);
1315  }
1316 
1317  matrix_samples_data.samples = &concatenated_xform_samples;
1318  matrix_samples_data.time_sampling = ts;
1319  }
1320 
1321  next_object = xform;
1322  }
1323  else if (ISubD::matches(header)) {
1324  ISubD subd(parent, header.getName());
1325 
1326  unordered_map<std::string, AlembicObject *>::const_iterator iter;
1327  iter = object_map.find(subd.getFullName());
1328 
1329  if (iter != object_map.end()) {
1330  AlembicObject *abc_object = iter->second;
1331  abc_object->iobject = subd;
1332  abc_object->schema_type = AlembicObject::SUBD;
1333 
1334  if (matrix_samples_data.samples) {
1335  abc_object->xform_samples = *matrix_samples_data.samples;
1336  abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
1337  }
1338  }
1339 
1340  next_object = subd;
1341  }
1342  else if (IPolyMesh::matches(header)) {
1343  IPolyMesh mesh(parent, header.getName());
1344 
1345  unordered_map<std::string, AlembicObject *>::const_iterator iter;
1346  iter = object_map.find(mesh.getFullName());
1347 
1348  if (iter != object_map.end()) {
1349  AlembicObject *abc_object = iter->second;
1350  abc_object->iobject = mesh;
1351  abc_object->schema_type = AlembicObject::POLY_MESH;
1352 
1353  if (matrix_samples_data.samples) {
1354  abc_object->xform_samples = *matrix_samples_data.samples;
1355  abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
1356  }
1357  }
1358 
1359  next_object = mesh;
1360  }
1361  else if (ICurves::matches(header)) {
1362  ICurves curves(parent, header.getName());
1363 
1364  unordered_map<std::string, AlembicObject *>::const_iterator iter;
1365  iter = object_map.find(curves.getFullName());
1366 
1367  if (iter != object_map.end()) {
1368  AlembicObject *abc_object = iter->second;
1369  abc_object->iobject = curves;
1370  abc_object->schema_type = AlembicObject::CURVES;
1371 
1372  if (matrix_samples_data.samples) {
1373  abc_object->xform_samples = *matrix_samples_data.samples;
1374  abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
1375  }
1376  }
1377 
1378  next_object = curves;
1379  }
1380  else if (IFaceSet::matches(header)) {
1381  // ignore the face set, it will be read along with the data
1382  }
1383  else if (IPoints::matches(header)) {
1384  IPoints points(parent, header.getName());
1385 
1386  unordered_map<std::string, AlembicObject *>::const_iterator iter;
1387  iter = object_map.find(points.getFullName());
1388 
1389  if (iter != object_map.end()) {
1390  AlembicObject *abc_object = iter->second;
1391  abc_object->iobject = points;
1392  abc_object->schema_type = AlembicObject::POINTS;
1393 
1394  if (matrix_samples_data.samples) {
1395  abc_object->xform_samples = *matrix_samples_data.samples;
1396  abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
1397  }
1398  }
1399 
1400  next_object = points;
1401  }
1402  else if (INuPatch::matches(header)) {
1403  // unsupported for now
1404  }
1405  else {
1406  next_object = parent.getChild(header.getName());
1407 
1408  if (next_object.isInstanceRoot()) {
1409  unordered_map<std::string, AlembicObject *>::const_iterator iter;
1410 
1411  /* Was this object asked to be rendered? */
1412  iter = object_map.find(next_object.getFullName());
1413 
1414  if (iter != object_map.end()) {
1415  AlembicObject *abc_object = iter->second;
1416 
1417  /* Only try to render an instance if the original object is also rendered. */
1418  iter = object_map.find(next_object.instanceSourcePath());
1419 
1420  if (iter != object_map.end()) {
1421  abc_object->iobject = next_object;
1422  abc_object->instance_of = iter->second;
1423 
1424  if (matrix_samples_data.samples) {
1425  abc_object->xform_samples = *matrix_samples_data.samples;
1426  abc_object->xform_time_sampling = matrix_samples_data.time_sampling;
1427  }
1428  }
1429  }
1430  }
1431  }
1432 
1433  if (next_object.valid()) {
1434  for (size_t i = 0; i < next_object.getNumChildren(); ++i) {
1435  walk_hierarchy(
1436  next_object, next_object.getChildHeader(i), matrix_samples_data, object_map, progress);
1437  }
1438  }
1439 }
1440 
1441 void AlembicProcedural::build_caches(Progress &progress)
1442 {
1443  size_t memory_used = 0;
1444 
1445  for (Node *node : objects) {
1446  AlembicObject *object = static_cast<AlembicObject *>(node);
1447 
1448  if (progress.get_cancel()) {
1449  return;
1450  }
1451 
1452  if (object->schema_type == AlembicObject::POLY_MESH) {
1453  if (!object->has_data_loaded()) {
1454  IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting);
1455  IPolyMeshSchema schema = polymesh.getSchema();
1456  object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
1457  }
1458  else if (object->need_shader_update) {
1459  IPolyMesh polymesh(object->iobject, Alembic::Abc::kWrapExisting);
1460  IPolyMeshSchema schema = polymesh.getSchema();
1461  read_attributes(this,
1462  object->get_cached_data(),
1463  schema,
1464  schema.getUVsParam(),
1465  object->get_requested_attributes(),
1466  progress);
1467  }
1468  }
1469  else if (object->schema_type == AlembicObject::CURVES) {
1470  if (!object->has_data_loaded() || default_radius_is_modified() ||
1471  object->radius_scale_is_modified()) {
1472  ICurves curves(object->iobject, Alembic::Abc::kWrapExisting);
1473  ICurvesSchema schema = curves.getSchema();
1474  object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
1475  }
1476  }
1477  else if (object->schema_type == AlembicObject::POINTS) {
1478  if (!object->has_data_loaded() || default_radius_is_modified() ||
1479  object->radius_scale_is_modified()) {
1480  IPoints points(object->iobject, Alembic::Abc::kWrapExisting);
1481  IPointsSchema schema = points.getSchema();
1482  object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
1483  }
1484  }
1485  else if (object->schema_type == AlembicObject::SUBD) {
1486  if (!object->has_data_loaded()) {
1487  ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
1488  ISubDSchema schema = subd_mesh.getSchema();
1489  object->load_data_in_cache(object->get_cached_data(), this, schema, progress);
1490  }
1491  else if (object->need_shader_update) {
1492  ISubD subd_mesh(object->iobject, Alembic::Abc::kWrapExisting);
1493  ISubDSchema schema = subd_mesh.getSchema();
1494  read_attributes(this,
1495  object->get_cached_data(),
1496  schema,
1497  schema.getUVsParam(),
1498  object->get_requested_attributes(),
1499  progress);
1500  }
1501  }
1502 
1503  if (scale_is_modified() || object->get_cached_data().transforms.size() == 0) {
1504  object->setup_transform_cache(object->get_cached_data(), scale);
1505  }
1506 
1507  memory_used += object->get_cached_data().memory_used();
1508 
1509  if (use_prefetch) {
1510  if (memory_used > get_prefetch_cache_size_in_bytes()) {
1511  progress.set_error("Error: Alembic Procedural memory limit reached");
1512  return;
1513  }
1514  }
1515  }
1516 
1517  VLOG_WORK << "AlembicProcedural memory usage : " << string_human_readable_size(memory_used);
1518 }
1519 
1521 
1522 #endif
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
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 or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
SIMD_FORCE_INLINE btQuaternion slerp(const btQuaternion &q1, const btQuaternion &q2, const btScalar &t)
Return the result of spherical linear interpolation betwen two quaternions.
Definition: btQuaternion.h:920
vector< AttributeRequest > requests
void add(ustring name)
Attribute * add(ustring name, TypeDesc type, AttributeElement element)
list< Attribute > attributes
void remove(ustring name)
char * data()
vector< char > buffer
void tag_update(Scene *scene, bool rebuild)
AttributeSet attributes
Definition: hair.h:13
bool get_cancel() const
Definition: progress.h:90
void set_error(const string &error_message_)
Definition: progress.h:110
bool need_update_geometry() const
AttributeRequestSet attributes
Definition: scene/shader.h:118
size_t size() const
void push_back_reserved(const T &t)
void reserve(size_t newcapacity)
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
OperationNode * node
double time
Scene scene
ccl_device_inline Transform make_transform(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j, float k, float l)
ccl_device_inline Transform transform_scale(float3 s)
ccl_device_inline void transform_compose(ccl_private Transform *tfm, ccl_private const DecomposedTransform *decomp)
@ ATTR_STD_NONE
Definition: kernel/types.h:613
#define VLOG_WORK
Definition: log.h:80
#define make_float3(x, y, z)
Definition: metal/compat.h:204
static char * generate(GHash *messages, size_t *r_output_size)
Definition: msgfmt.c:170
static void clear(Message *msg)
Definition: msgfmt.c:278
static float lerp(float t, float a, float b)
static unsigned a[3]
Definition: RandGen.cpp:78
std::unique_ptr< IDProperty, IDPropertyDeleter > create(StringRefNull prop_name, int32_t value)
Allocate a new IDProperty of type IDP_INT, set its name and value.
#define I
#define SOCKET_NODE_ARRAY(name, ui_name, node_type,...)
Definition: node_type.h:268
#define SOCKET_FLOAT(name, ui_name, default_value,...)
Definition: node_type.h:191
#define SOCKET_INT(name, ui_name, default_value,...)
Definition: node_type.h:187
#define NODE_DEFINE(structname)
Definition: node_type.h:141
#define SOCKET_BOOLEAN(name, ui_name, default_value,...)
Definition: node_type.h:185
#define SOCKET_STRING_ARRAY(name, ui_name, default_value,...)
Definition: node_type.h:257
#define SOCKET_STRING(name, ui_name, default_value,...)
Definition: node_type.h:203
smooth(Type::FLOAT, "mask_weight")
string string_human_readable_size(size_t size)
Definition: string.cpp:229
float size[3]
void clear_non_sockets()
Definition: scene/mesh.cpp:270
void set_num_subd_faces(size_t num_subd_faces_)
Definition: scene/mesh.h:237
static NodeType * add(const char *name, CreateFunc create, Type type=NONE, const NodeType *base=NULL)
ustring name
Definition: graph/node.h:174
bool is_modified() const
Definition: graph/node.cpp:804
void set_owner(const NodeOwner *owner_)
Definition: graph/node.cpp:773
void tag_update(Scene *scene)
ProceduralManager * procedural_manager
Definition: scene.h:229
static void transform_decompose(DecomposedTransform *decomp, const Transform *tfm)
Definition: transform.cpp:164