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{
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
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
vector< AttributeRequest > requests
void add(ustring name)
Attribute * add(ustring name, TypeDesc type, AttributeElement element)
list< Attribute > attributes
void remove(ustring name)
char * data()
vector< char > buffer
void tag_update(Scene *scene, bool rebuild)
AttributeSet attributes
Definition hair.h:14
bool get_cancel() const
Definition progress.h:93
void set_error(const string &error_message_)
Definition progress.h:113
bool need_update_geometry() const
AttributeRequestSet attributes
size_t size() const
void push_back_reserved(const T &t)
void reserve(size_t newcapacity)
#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
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:245
AttributeSet subd_attributes
Definition scene/mesh.h:159
@ SUBDIVISION_CATMULL_CLARK
Definition scene/mesh.h:123
void clear_non_sockets()
void set_num_subd_faces(size_t num_subd_faces_)
Definition scene/mesh.h:238
static NodeType * add(const char *name, CreateFunc create, Type type=NONE, const NodeType *base=NULL)
ustring name
Definition graph/node.h:177
bool is_modified() const
void set_owner(const NodeOwner *owner_)
ProceduralManager * procedural_manager
Definition scene.h:147
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