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