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